Сегодня я с большим удовольствием проведу вас через создание и использование сильно вдохновленной биологией парадигмы нейронной сети, которую я назвал биологической. Это будет довольно длинный пост с подробным описанием каждого объекта от дендритов до аксонов и многого другого. Я также хотел бы, чтобы это было доступно для тех, кто никогда не создавал нейронную сеть. По этим причинам я потрачу время, чтобы представить, что именно мы пытаемся имитировать; нейрон.

Думайте о картинке выше как о трубке, которая обрабатывает данные слева направо. Дендриты собирают входные сигналы от предыдущих нейронов и пытаются стимулировать ядро. При успешной стимуляции ядро ​​посылает выходной сигнал по собственному аксону через синаптическую щель к дендритам другого нейрона. Этот процесс будет продолжаться по цепочке.

Представьте, что каждый нейрон принимает решение. Ядро можно рассматривать как поставщика страховых услуг или агента, пытающегося удостовериться, что они страхуют только те дома, которые проходят проверку, чтобы заработать как можно больше денег. Тогда дендриты можно рассматривать как всех коллег агента по телефону, которые дают агенту голосование «да» или «нет» в отношении важных новых зданий, пытаясь повлиять на решение агента. Затем агент берет трубку босса или аксон и передает свое окончательное решение. Агент может присвоить номер «доверия» каждому из входящих телефонов. Никогда не встречаясь ни с одним из коллег, агент не может знать, насколько им можно доверять. Однако, когда босс перезванивает агенту, чтобы сообщить, была ли страховка хорошей или нет, агент запоминает, кто из коллег сказал «да» или «нет», и отмечает число своего «верования» вверх или вниз, если они были правы. или неправильно. Когда поступает новый звонок о новом доме, и один коллега голосует «за» с числом убеждений -0,9 (отрицательно), а другой коллега голосует «нет» с числом убеждений 1,1 (положительно), наиболее вероятно, что затем агент позвонит на линию группы боссов и ответит «нет», что гарантирует наилучшую классификацию. Имейте в виду, что можно доверять чьей-то неправоте больше, чем чьей-то правоте. Если бы телефонные звонки были ответами «да» с -1,4 и «да» с уверенностью 0,8, агенту все равно надлежало бы проголосовать «против» в целом просто потому, что первый коллега уже давно ошибался. Эти числа «доверия» являются входными весами для каждого нейрона.

Я хочу использовать эту аналогию в качестве перехода к нескольким темам, которые не обязательно проявляются в простой ситуации выше, но которые легко увидеть через ее призму. Эти темы исключаются из-за «маскирования», функций активации, импульса, отсечения градиента, уменьшения веса и размера мини-пакета.

Dropout — это удивительная и простая концепция, которая предотвращает чрезмерную зависимость агента от какого-либо одного коллеги. Концептуально мы не позволим некоторым коллегам звонить агенту. На практике это делается путем маскирования входных данных фильтром, предназначенным для «обнуления» и предотвращения некоторых входных данных. У агента может быть 100 коллег, от которых он ожидает телефонных звонков, прежде чем сообщить о своем решении. С вероятностью отсева 20% разумно предположить, что только 80 телефонных звонков доходят до нее при случайном выборе. Это вынуждает агента принимать решение, используя меньшую подсеть коллег, и ограничивает ее обновления «убеждений» теми немногими, от которых она получала звонки. Подобное разрушение системы с самого начала может показаться бесполезным, но вскоре агент поймет, что более подходящие значения «убеждения» применимы к каждому коллеге, вместо того, чтобы полагаться на то, что один из них ошибается или прав. Этот метод потребует от агента больше времени, чтобы получить достаточную обратную связь от группы боссов, чтобы присвоить эти значения, чем обычно. Последний трюк с отсевом — игнорировать его после тренировки. В примере это означает, что каждый телефонный звонок теперь работает. Теперь, когда агент точно настроил свои «убеждения» без чрезмерной уверенности, он начнет получать телефонные звонки от каждого коллеги, все тщательно взвешенные, прежде чем принять решение и поднять следующий телефон.

Функции активации сами по себе являются уникальной темой. Вы часто будете слышать, что функции активации обеспечивают нелинейность. Но что это значит? Зачем нам это нужно? Что такое линейная модель? К этому моменту я по существу описал линейную модель, то есть модель с активацией Идентичности. Активация Identity проста (in=out), где ничего не делается для изменения ввода перед результатом. Теперь я предлагаю концепцию возбуждения или нетерпения по поводу решения. Вот где агент действительно вступает в игру. Начальство, не имея собственных мыслей по этому поводу, могло просто обойти агента и опросить самих коллег. Посреднику не нужно было бы просто собирать ответы коллег перед их передачей. На практике любой скрытый слой с активацией Identity можно по существу удалить, а Сеть сделать более мелкой. Несколько слоев активации Identity в строке эквивалентны одному слою Identity. Чтобы увидеть это яснее, сделаем агента очень возбудимым. Я рассмотрю активацию SoftPlus, чтобы понять это.

На графике видно, что происходит с решением агента на основе сводки входных данных. Входные данные, которые подталкивают агента к «нет», смягчаются, и требуется огромное влияние, чтобы подтолкнуть агента к 0 или «абсолютно нет». Однако мы видим, что любые положительные входящие влияния встречают горячее одобрение. Это даст агенту собственную точку зрения на входные данные, оправдывая начальство тем, что он или она действительно оказывает влияние на решения и не должен быть уволен. Что касается поправок группы боссов, то положительные решения, принимаемые агентом, будут обновляться активнее, чем отрицательные. См. это на наклоне графика. Чем больше наклон линии, тем больше нейрон будет обновлять веса, используемые для принятия решения. Возвращаясь к аналогии, чем больше агент был готов рисковать своей репутацией для принятия решения, тем больше внимания уделялось обновлению ценностей «убеждения» коллег. Точнее говоря, решения, принятые с помощью SoftPlus, когда агент говорит «нет», выводя ноль, здесь больше похожи на простое исключение себя из решения. Не участвуя в принятии решения, агент не вызывает гнева со стороны начальства и мало что может сделать, когда дело доходит до обновления значений «убеждения». Да, существуют абсолютно активационные функции, которые пропускают отрицательные значения, и они позволяют агенту быть решительным в своем решении «нет». Рассмотрим также сравнение между недалеким агентом и очень плоской функцией активации. Независимо от того, что говорит начальство, агент практически не будет предпринимать никаких действий по обновлению значений «убеждения». Это характерно для функции активации, такой как сигмоид, которая быстро «насыщается» в сторону решения, становясь очень уверенной в нем. Сигмоид выглядит так:

Это дает агенту возможность либо отказаться от решения, либо скромно проголосовать, и то и другое с очень закрытым умом. В этот проект я включаю несколько функций активации, в том числе некоторые из которых я придумал сам. Однако имейте в виду, что заполнение вашей страховой компании очень легковозбудимыми агентами может вызвать серьезные проблемы. Я предлагаю комбинировать громко активные агенты со слоями спокойных агентов, чтобы смягчить их чрезмерную возбудимость. С помощью этого процесса я нашел гораздо больший успех, чем простое использование одной и той же функции активации для каждого слоя.

Momentum сглаживает процесс обновления веса и может ускорить его, если несколько обновлений идут в одном направлении. Точно так же он может ослабить ошибочные обновления, которые не поддерживаются другими подобными обновлениями. Импульс обычно не только ускоряет обучение сети, но и позволяет сети находить более эффективные минимумы в ландшафте потерь. Агент в рабочем примере может использовать оценку «согласованности» для каждого коллеги. Чем более последовательно они правы или неправы, тем более комфортно агент будет чувствовать себя при обновлении своего рейтинга «веры». Непоследовательные коллеги будут получать меньшие обновления, в то время как коллега, который явно ошибается, получит большее обновление в негативном направлении, подразумевая всегда делать противоположное тому, что он или она предлагает. Это приводит к тому, что берется «скользящее среднее» обновлений и применяется скользящее среднее значение к весам вместо непосредственного применения обновлений. Это раскрывает консенсус по временной шкале входных данных коллеги, позволяя агенту классифицировать их как «в целом неправильные» или «в целом правильные», а не отменять обновление, если они были правы в одном и ошибались в следующем. Импульс будет в множителе от [0,1). Нулевой импульс указывает на то, что обновления будут применяться напрямую, в то время как импульс 0,99 подразумевает сильную зависимость от среднего значения по каждому отдельному обновлению. Для начала кажется, что наиболее выгодно начать без импульса и посмотреть, как его добавление может повлиять на результаты. Часто выбирается значение импульса 0,9.

Отсечение градиента, каким бы простым оно ни было, может быть еще проще увидеть в аналогии. Градиент — это информация, которую агент получает о том, насколько неправильное или правильное решение он принял, и насколько это должно повлиять на значения «убеждения» агента. Отсечение здесь обеспечивает абсолютный максимум или минимум. Это не позволяет группе боссов сильно нарушать ценности «убеждения» агента массовым обновлением. При отсечении градиента обратная связь, которую получает агент, всегда ограничена двумя значениями. Текущее состояние сети использует необычайно либеральный диапазон градиента [-5,5].

В аналогии уменьшение веса напрямую соответствует уменьшению «ценности убеждений». Что это означает? В Сети не будет стационарного веса, даже если он не получает обновления. Каждый раунд тренировки вес теряет небольшой процент от себя, приближаясь к нулю. Это означает, что большие веса подвержены более серьезному влиянию, чем меньшие веса. Это еще один способ предотвратить чрезмерную зависимость от какого-либо одного коллеги, и он потребует нескольких обновлений в заданном направлении, чтобы поддерживать большой вес в этом направлении от распада. Для дальнейшего чтения по этому вопросу изучите регуляризацию L2 в нейронных сетях, так как уменьшение веса является ее реализацией. Эта сеть использует постоянное значение затухания веса 0,0001.

Последняя тема, которую я хотел бы затронуть перед кодированием, — это реализация мини-пакетов в сети. Хотя сеть может анализировать только один образец за раз, она имеет функцию накопления данных по циклам и обновления каждого запуска мини-пакета путем усреднения значений по размеру мини-пакета. Этот подход открывает возможность для внесения оперативных изменений в размер мини-пакета во время обучения. Пока я все еще работаю, я еще не представил для этого поразительного применения, но это определенно доступно для пользователя. Имейте в виду, что большие мини-пакеты, хотя и обеспечивают более устойчивый подход к решению, могут привести к тому, что Сети потребуется больше времени для сходимости по одной основной причине: Сеть теперь отбирает «мини-пакеты» несколько раз с включенным обучением, прежде чем сделать одно обновление. Осторожные шаги становятся более медленными шагами.

Биологический не может похвастаться самой высокой пропускной способностью для нейронной сети. Тем не менее, он разбит на небольшие строительные блоки и поставляется с инструментами для их создания, пытаясь эмулировать процесс, стоящий за нейроном, и аналогию со страховкой, описанную выше. Для многих это сердце объектно-ориентированного программирования. По этой причине для меня Bi-logical является одним из моих фаворитов. Это также имеет неприятный побочный эффект создания большего проекта в моем файловом пространстве. Я предлагаю вам здесь самодостаточную группу из 12 классов подкаталога Network, сопровождаемых классом Vector в подкаталоге Math и примером класса XORGate в подкаталоге Testing.XORTesting проекта.

Обычно я начинаю «сверху вниз», когда мы сначала смотрим, как проект составлен, а затем отслеживаем зависимости. Тем не менее, я нахожу этот проект более управляемым, если рассматривать его «изнутри наружу», и начну с самого базового класса — Вектора. Он просто содержит массив данных и предоставляет функциональные возможности для работы с ним или другими векторами и их соответствующими массивами данных.

Отлично! Теперь у нас есть основная рабочая лошадка для проекта. Почти каждый расчет будет выполняться с использованием этих векторов. Я надеюсь, что это станет более очевидным в ближайшее время.

Следующим шагом в нашем путешествии от «внутри к выходу» будет определение функций активации, которые мы используем в Сети. Здесь мы просто маркируем типы, а не кодируем математику, которая их определяет. Эта математика будет происходить позже внутри класса Nucleus, который применяет активацию.

Как видите, я предоставил довольно много потенциальных функций активации для использования в Сети. Большинство из них, как правило, распространены, однако SArSinH — мое собственное творение. Это очень изменчивая активация, и по этой причине ее не следует использовать в последовательных слоях. Его бурная активация должна быть смягчена другим слоем постепенной активации. Фактически, в списке есть один, который идеально подходит, потому что он изящно обрабатывает большие входные данные. Я добился большего успеха, сочетая SArSinH (масштабированный гиперболический арксинус) с чередующейся активацией синуса, чем просто связывая такие вещи, как ELU (экспоненциальная линейная единица) или SELU (масштабированная экспоненциальная линейная единица). Я искренне призываю вас экспериментировать с как можно большим количеством типов. Если интересно, можно даже автоматизировать процесс по аналогии с методом, представленным в другом моем посте Генетические алгоритмы и параллельное обучение. Если вы хотите включить свою собственную активацию в этот проект, методология довольно проста. Просто добавьте имя активации в список здесь и определите ее функцию и производную внутри будущего класса Nucleus. Пока вы можете определить его производную. Если вы плохо знакомы с деривативами, в Интернете есть несколько ресурсов, которые могут помочь вам их рассчитать (вспомните Wolfram Alpha).

Класс Nucleus отвечает за фактическое применение активации к взвешенному решению Дендритов, т. е. агент становится нетерпеливым или подавленным из-за ввода коллег. Это относительно небольшой класс с простой целью, как мы сейчас увидим:

Проницательный взгляд может заметить бесполезный метод обновления в конце класса. Пожалуйста, простите меня, так как этому проекту суждено стать чем-то большим, чем он есть сейчас. Еще одно острое наблюдение может выявить наличие EntropySigmoid, которого не было в списке активации. Опять же, чтобы проект скомпилировался, просто добавьте EntropySigmoid в перечисление Activation. EntropySigmoid, еще одно творение, созданное благодаря большому количеству свободного времени, был разработан для использования на выходном слое и синтезирования использования логарифмических потерь с использованием формулы для квадратичных потерь. По следующей причине я еще не включил в этот пост понятие функции потерь; Я не буду делать этого просто потому, что квадратичная потеря легко интерпретируется как «насколько далеко я был от цели» путем простого вычитания цели из вычисленного значения. Другие функции потерь, хотя и более сложные, не являются важной частью этого проекта.

Следующий класс, который я хотел бы представить, — это еще меньший служебный класс под названием Axon. Аксон — это просто место для хранения активированного значения, которое будет ждать, пока к нему не будет получен доступ для следующего слоя. Другими словами, именно здесь решение нейрона будет находиться до тех пор, пока оно не понадобится.

Здорово! Теперь у нас есть все части Нейрона. Теперь я размещу эти сегменты внутри класса Neuron. Это простой класс, который наблюдает за получением входных данных, их обработкой с помощью дендритов, активацией через ядро, сохранением в аксоне и предоставлением прямого доступа к значению, хранящемуся в аксоне. Это своего рода «сквозной менеджер», который группирует функциональность отдельных сегментов в один закрытый процесс как для прямого, так и для обратного распространения по сети.

Теперь у нас есть Нейрон для нейронной сети! Фантастика!

Следующим шагом будет создание слоев. Один слой нейронов можно считать нейронной сетью, если он оснащен входным и выходным слоями. Как вы увидите позже, добавление слоев будет тривиальной, привлекательной и интересной задачей. Я хотел бы начать сначала с базовой концепции слоя. Я предлагаю здесь то, что известно в Java как интерфейс. Это концепция, которая подразумевает и гарантирует основные функциональные возможности любых наследуемых классов. Наследующими классами здесь будут InputLayer, HiddenLayer и OutputLayer. Мы можем сгруппировать их в общий формат слоя, в котором каждый слой будет по существу выполнять те же процессы, что и другие слои, хотя и по-разному. Чтобы увидеть это в действии, давайте взглянем на код:

Обратите внимание, что интерфейсы не предоставляют интерпретации методов. Они просто гарантируют, что любой наследующий класс будет иметь эту функциональность. Этот процесс будет непрозрачен для класса Network, который еще не готов. На самом деле, класс сети будет знать только то, что он состоит из общих слоев, и ему все равно, являются ли они входными слоями или скрытыми слоями и т. д. На последующих этапах мы позаботимся о том, чтобы при построении сети мы вставляли InputLayer и OutputLayer автоматически. Пользователь будет строить только скрытые слои сети. В этом смысле OutputLayer — это просто ограничение, применяемое к последнему HiddenLayer, и оно будет того же размера.

InputLayer будет самым простым из слоев. Он просто содержит входной вектор, применяет любую запрошенную маску (вспомните вышеприведенный раздел об исключении) и передает ее первому скрытому слою. Это, что важно, не требует никаких нейронов. Ссылаясь на приведенные выше аннотации, это должна быть довольно простая реализация.

Обратите внимание, что для методов update() или modmodifyBias() внутри InputLayer ничего не нужно делать, так как он не имеет внутри себя нейронов для обновления и не изменяет входные данные с какой-либо предвзятостью.

В OutputLayer мы увидим расчет потерь в действии. Для вычисления ошибки я использую MSE или среднеквадратичную ошибку. Как следует из названия, этот расчет представляет собой среднее значение разницы между каждым выходом и каждой целью, каждое в квадрате. Это дает положительное значение ошибки, так как все квадраты всегда будут положительными. Цель Сети состоит в том, чтобы свести к минимуму это число. Производная от этой «стоимости» используется для расчета направления и размера «убытка» Сети. Производная MSE — это просто разница между выходным значением и целевым значением, пропорциональная обратной величине числа выходных сигналов. Если предположение Сети было выше целевого значения, результат этой производной будет положительным. Аналогично, оценка, полученная ниже целевого значения, даст отрицательный результат потерь при обратном распространении.

Опять же, внутри OutputLayer есть несколько неиспользуемых методов. Это по той же причине, что и InputLayer. В этой конструкции просто нет Нейронов, чтобы выпрашивать функциональность.

Последней конструкцией Layer, которая нам потребуется, будет HiddenLayer. Этот будет значительно более вовлечен, но имейте в виду, что это просто «сквозной менеджер» для нейронов, как нейроны для своих соответствующих компонентов. Этот слой должен принимать входящий вектор признаков и отвечать выходным вектором решений, который, в свою очередь, может стать вектором признаков для следующего скрытого слоя или вектором ответа для выходного слоя. Во время обратного распространения он должен получить вектор информации об ошибке и распространить его через нейроны, чтобы построить вектор влияния для «предыдущего» (в данном случае «следующего», поскольку мы движемся назад во время обратного распространения) слоя как это идет.

Здорово! Теперь у нас есть все типы слоев, которые нам нужны для полноценной сети.

Прежде чем строить Сеть, я хотел бы коснуться еще одной концепции. Это пока может показаться неочевидным, но нам понадобится какой-то способ хранения инструкций для построения этих слоев. Пользователь создаст инструкции, а Сеть будет использовать их для физического конструирования. Я хочу представить эту концепцию сейчас, хотя она станет очевидной при использовании позже, потому что она также содержит конкретное перечисление, которое нам нужно. Это перечисление называется MaskType. Он предложит три доступные маски, одна из которых ничего не делает и известна как MaskType.NONE. Два других предлагают маски исключения, одна используется для входного слоя, а другая используется для скрытых слоев. Выпадение ввода, хотя оно все еще может быть полезным, для меня это немного табу. Мне просто не нравится идея не предоставлять Сети всю доступную информацию, когда я прошу ее принять решение. Я советую использовать отсев только для входного вектора, если он очень большой. Причина того, что отсев входных данных отделена от стандартной версии, заключается в том, что часто (и у меня нет под рукой ресурсов, чтобы подтвердить это) целесообразно использовать более низкую скорость отсева для входных данных, чем для скрытого слоя. Я искренне извиняюсь за отсутствие ссылок здесь. Несмотря на мои опасения, это вариант, который я включил. Настройте эти показатели отсева и применяйте маски к сети, следуя любой причудливой прихоти, которую вы можете почувствовать. На самом деле нет никакой замены опыту исследования.

Последний компонент Сети может быть самоочевидным. Нам нужен объект Маска. Прежде чем я представлю это, позвольте мне сказать, что я не полностью затронул тему отсева. Вместо того, чтобы просто присваивать нули в некоторых случайных точках вектора, нужно сделать одну небольшую модификацию. Это связано с «громкостью» входящего Вектора. Присваивая нули некоторым точкам, мы ослабляем нормаль входного вектора, фактически делая его «тише». ввод на полную громкость. Чтобы компенсировать это, Джеффри Хинтон и др. в статье «Dropout: A Simple Way to Prevent Neural Networks from Overfitting» предложили, чтобы вектор, не подверженный Dropout, масштабировался по вероятности того, что он должны были не обнуляться в первую очередь. Например, если наш процент отсева был установлен на 20% или значение 0,2, любой вектор, проходящий через сеть, пока не применяется отсев, должен быть масштабирован на 80% или значение 0,8***. Это приводит к ослаблению вектора, чтобы не перегружать Нейрон. Предлагаю такую ​​интерпретацию этого процесса на практике:

Идеально! Теперь мы готовы построить Сеть вокруг компонентов, которые мы сделали до сих пор! Сама Сеть, опять же, на самом деле является еще одним переходным менеджером, который добавляет немного функциональности к ошибке запроса. Он также предлагает два метода расчета ошибки без фактического обучения сети. Один из методов, известный как dryTrain(), выполняет обратное распространение только через OutputLayer. Затем вы можете запросить Сеть об ошибке, как обычно. Другим является статический метод getError(), который требует, чтобы выходной вектор и целевой вектор возвращали ошибку. Эти методы будут эквивалентны.

Я покажу вам демонстрацию Сети. Чтобы действительно показать это, я поручу ему синтезировать вентиль XOR. Если вы не знакомы, вентиль XOR принимает два входа и возвращает одно значение на выходе. Рассмотрим два входа A и B как двоичные, либо 0, либо 1. Логический элемент XOR работает с ними так, чтобы сказать «если одно или другое, но не оба». Это означает, что при заданном входном векторе (0,0) сеть должна выводить вектор (0). Учитывая (1,0), вывод должен быть (1). Аналогично (0,1) выводит (1). Однако логический элемент XOR говорит не оба, поэтому ввод (1,1) должен привести к выводу (0). Я использую этот пример по одной важной причине: несмотря на то, что можно запустить сеть без скрытых слоев, сеть не может воспроизвести поведение вентиля XOR без скрытого слоя. Я призываю вас поэкспериментировать с этим. Только добавив хотя бы один HiddenLayer, Сеть сможет решить эту проблему. В приведенном ниже примере мы сначала строим сеть, затем создаем наши данные и обучаем векторы. Обратите внимание: если вы измените вывод «Активация сети» на TanH, вы можете и должны изменить выходы, которые в противном случае были бы равны 0, на -1. TanH — прекрасный инструмент для принятия решений, и он имеет более широкий диапазон, чем Sigmoid, что также подразумевает другой порог для принятия решения. С Sigmoid решение равно 1, если Сеть выбирает значение выше 0,5, или 0, если оно выбирает значение ниже 0,5. С TanH решение равно +1, если Сеть выбирает значение выше 0, и -1, если она выбирает значение ниже 0. TanH допускает более активное обратное распространение, чем ваш типичный сигмоид, из-за его более активной производной. Однако в этой демонстрации я не использую типичный Sigmoid, а вместо этого использую EntropySigmoid. Этот монстр не знает себе равных, когда дело доходит до OutputLayer (Примечание: несмотря на мою любовь к экспериментам, я бы не советовал использовать эту активацию в любом другом слое, так как она очень специфична. эквивалентно участию в гонке космических кораблей на моторной лодке). Пример сети, который я вам покажу, будет использовать все дополнительные методы, которые использует сеть, включая снижение веса, выпадение, несколько слоев, различные активации, импульс и размер мини-пакета из четырех. Это традиционный пример чрезмерной подгонки*****. Обратите внимание, что из-за того, что размер мини-пакета сети установлен на 4, этот процесс будет обновлять сеть всего 5000 раз, несмотря на просмотр 20000 выборок.

Вундербар! Вы сделали это! Поздравляем с созданием собственной БИО-логической сети! Я надеюсь услышать о любых приложениях, которые вы можете найти для него. Спасибо за чтение.

БИО-логический: Java-реализация нейронной сети

— — — — — — — — — — — — —

  • ****** Я ожидаю, что добавление Drop-Out любого типа хотя бы немного уменьшит наши шансы на экстремальное переобучение. Для этого XOR-гейта это все еще не должно быть проблемой, учитывая достаточно широкий слой и не слишком высокую скорость выпадения. Учитывая все обстоятельства, потеря веса все же должна иметь большее влияние.
  • В предвкушении вы можете заметить, что теперь у нас есть две из трех жизненно важных частей нейрона. Недостающее звено — это то, что известно как класс Dendrites. Класс Dendrites, хотя и не такой лаконичный и приятный, как предыдущие нейронные компоненты, выполняет большую часть тяжелой работы в этом процессе. Здесь входные данные разбиваются на компоненты для подготовки к обратному проходу, затем обрабатываются весами дендритов, прежде чем направляются в ядро ​​для активации. Я считаю уместным здесь более подробно остановиться на самом обратном проходе. Мы должны хранить два «вектора производных». Эти векторы, dwrtI и dwrtW (производные по входам и производные по весам соответственно), необходимы во время обратного прохода для соответствующего распространения ошибки через сеть и до весов. Здесь нет необходимости в интенсивных вычислениях, поскольку производная цепочки умножений между весами и входными данными (например, w1*i1 + w2*i2 + w3*i3 +..) — это просто либо веса или вводит сами. На самом деле dwrtW — это просто копия входного вектора, а dwrtI — просто копия вектора весов. Чтобы вернуться к аналогии, агент должен сохранить информацию о том, что посоветовали его или ее коллеги и насколько агент им поверил (соответственно входные данные и веса), чтобы присвоить новые значения «убеждения» после того, как босс группа перезванивает ей с сообщением об ошибке. Проще говоря, каждый ввод перед активацией влиял на решение агента в зависимости от степени «веры», приписываемой ему. Соответственно, каждое значение «убеждения» влияло на решение в зависимости от размера соответствующего входа. При обновлении на основе ошибки мы должны знать влияние каждого веса на ошибку. Это задается dwrtW или входным вектором. Чтобы сообщить своим коллегам, насколько сильно они повлияли на ошибку, в свою очередь, агент должен сначала масштабировать ошибку на то, сколько внимания было уделено их вводным данным. При малом внимании, т. е. небольшом весе или значении «доверия», на ошибку мало влияет, так как решение коллеги в основном отбрасывается, и соответствующему коллеге нечего будет обновлять. Обратите внимание, что во время обратного распространения агент уже применил градиент своей собственной активации до любого расчета входящего влияния. Другими словами, трезвомыслящий или «насыщенный» агент уже сведет к минимуму ошибку обратного хода, прежде чем обвинять или хвалить за решение коллег.