Всем привет. В этот раз мы попытаемся разобраться с нейронными сетями без биологии и за 1 день.
Зачем они нужны?
Для того чтобы понять зачем нужны нейронные сети, нужно разобраться с тем, что они из себя представляют.
Искусственные нейронные сети — это совокупность искусственных нейронов, которые выполняют роль сумматоров.
Искусственные нейронные сети нужны для решения сложных задач, например: прогнозирование, распознавание образов. Так же они применяются в области машинного обучения и искусственного интеллекта, вы можете встраивать их в свои игры.
Главная особенность нейронных сетей — они способны обучаться.
Искусственный нейрон
Перед тем как переходить к строению нейронных сетей, нужно разобраться с их единицей — нейронами.
За входы обозначены x1, x2. На них поступают данные, либо в вещественном виде, либо в целом. Очень часто приходится проводить нормализацию входных данных. Для этого достаточно:
Количество входов зависит от задачи.
Так же мы имеем веса: w1, w2. В них и заключается суть нейронных сетей, через них проходит обучение. О нём чуть позднее.
Перед началом обработки данных, входы умножаются на соответствующие им веса. Т.е x1 * w1, x2 * w2. Далее результаты произведений поступают на нейрон и суммируются. (x1 * w1) + (x2 * w2)
Например: x1 = 1; x2 = 3; w1 = 0; w2 = -1;
(1 * 0) + (3 * (-1) ) = -3
Усвоим для себя, что количество весов должно соответствовать количеству входов.
Далее результат суммирования поступает в блок нелинейного преобразования. В нём должна находиться функция активации.
Функция активации
Функции активации нужны для нормализации выходных данных. Допустим ответ -3 нам ни о чём не говорит, и мы хотели бы преобразовать его к 1 или 0.
Для такого имеется функция единого скачка. Когда в нейроне заряд превысил какой-то порог, то нейрон выдаёт 1. Если заряд ниже порога, то нейрон выдаст 0. Например, T — порог. Он равен 0. Результат суммирования -3. -3 < 0, значит и ответ нейрона 0. Если заряд был бы больше, например равный 0.5 или 1 или 124124, то нейрон выдал бы 1.
Порог устанавливается по вашему желанию, так как нейронная сеть всё равно подстроиться под него.
Когда нам необходимо преобразовать данные для большего выбора варианта, то нам необходимо преобразовать суммированный результат в вид от 0 до 1.
Для такого у нас имеется логистическая функция.
Или:
a — степень крутизны на графике функции.
net — результат суммирования
В нашем случае -3 преобразуется в 0.9525741268224334
В таком случае мы можем просклонять такой ответ к хорошему результату.
Практика
Представим себе такую задачу. Мы хотели бы получить подсказку от нейронной сети, встречаться ли нам с девушкой или нет. Мы имеем такие входные данные:
Рост девушки, (в метрах)
На сколько она красива, (1% — 100%)
Есть ли ум, ( 1/0 )
Умеет ли готовить. (1/0)
Допустим установим все эти входы такими числами: 1.66, 100%, 1, 1
4 входа — 5 весов. t(порог) = 400
Установим сейчас веса без обучения, как степень важности параметра:
1, 5,5, 4.
Умножаем входы на соответствующие им по номеру веса: (1.66 * 1) + (100 * 5) + (1 * 5) + (1 * 4) = 1.66 + 500 + 5 + 4 = 510.66 > 400, значит встречаться с девушкой можно, так как нейрон выдаст 1.
Теперь попробуем проверить через логистическую функцию. 1 / (1 + exp(-510.66)) = 1.0
В данном случае мы тоже получили 1, значит встречаться можно. Но здесь у нас больше вариантов, ибо тут мы можем распределить ответы НС так:
net => 0.80, встречаться можно.
net < 0.80 && net != 0.5, нужно ещё подумать.
net <= 0.5, встречаться не нужно.
Надеюсь вам было понятно.
Типы нейронных сетей
Теперь нужно понять строение нейронных сетей. Они разделяются на однослойные и многослойные, с прямыми связями и обратными связями.
Единственное, что объединяет ОНС и МНС — это то, что входные нейроны не обрабатывают, лишь передают сигналы на обработку.
Однослойные НС
В таких НС данные с входных слоёв передаются сразу на выходные нейроны, которые обрабатывают сигналы.
В данном примере три входных нейрона(x1, x2, x3), три выходных нейрона(out1, out2, out3).
В таком случае, получается, три связи у каждого выходного нейрона.
out1: w1, w2, w3. out2: w1, w2, w3. out3: w1, w2, w3.
Каждая связь может иметь разное значение.
Как нейрон обрабатывает сигнал — я писал выше.
Многослойные НС
Такие НС работают гораздо сложнее, но и способны они на большее.
Главная их отличительная особенность — они имеют скрытые(обрабатывающие) слои.
Названы они так, из-за того, что мы не видим какие сигналы они передают на выходы.
Сигналы они обрабатывают, часто имеют логистическую функцию активации, но можно и пороговую(единый скачок). С количеством слоёв и нейронов в них вам нужно разобраться самим, ибо для этого формул нет.
Сети с прямыми связями
Сети с прямыми связями могут быть однослойные и многослойные, вы уже видели их на рисунках выше. Таким образом связи из входов направляются к выходному слою или к скрытому слою и т.д к выходному.
Такие сети способны на прогнозирование, линейную интерполяцию, распознавание образов, не редко на классификацию и многое другое.
Сети с обратными связями
Данные сети имеют как прямые связи, так и обратные.
Такие нейронные сети могут иметь разное количество слоёв, или могут быть вообще однослойными. Но главная их особенность — они имеют ассоциативную(кратковременную) память. На таких нейронных сетях вы можете сделать чат-ботов. Так же они могут применяться в управлении, решать задачи классификации и многое другое.
Персептрон
Персептрон — нейронная сеть рецептор. Он имеет входной слой(S), обрабатывающие слои(A),
выходной слой®
Нейроны S слоя входные. Они могут находиться в состоянии возбуждения(1), либо в состоянии покоя(-1 или 0). Конечно же, никто не запрещает вам использовать и другие числа. Так же вы можете их нормализовать, например 1 / num, где num — ваше число.
Прежде чем попасть в A слой, сигналы с S слоя должны пройти по весам SA, значения которых могут быть в пределах от -1 до 1 в вещественном виде. Далее, сигналы поступают в A слой, суммируются, проходят через функцию активации. Далее, сигналы которые идут по AR весам. Здесь они могут иметь уже любые значения, которые установятся обучением.
В нейронах R слоя сигналы так же обрабатываются, проходят через функцию активации и вы получайте ответ.
Обучение
Вот мы и перешли к самой важной, но и в то же время очень сложной части.
Обучение нейронной сети — это процесс, при котором изменяются весовые коэффициенты. Собственно, благодаря этим весовым коэффициентам и работают нейронные сети.
Правило Хебба №1
Данное правило действует чаще всего с однослойными персептронами, входные сигналы которых равны 1, -1 или 0. С остальными числами у вас оно работать не будет.
Работает оно просто:
1. Если нейронная сеть выдаёт правильный результат, то весовые коэффициенты не изменяются.
2. Если нейронная сеть ошиблась и не дала правильный ответ(распознала неверно), то весовые коэффициенты уменьшаются.
3. Если нейронная сеть ошиблась и отвергла правильный ответ, то весовые коэффициенты увеличиваются.
Правило Хебба №2
Данное правило работает со всеми числами. По-другому оно называется delta правилом.
Оно имеет две формулы, в которых нужно разобраться, так как delta правило присутствует в методах обучения для многослойных нейронных сетей.
Для delta формулы нам необходимо знать ошибку сети. Чаще всего, ошибка — это разность правильного и неправильного ответов.
Где d — правильный ответ, b — ответ сети.
Теперь рассмотрим саму формулу:
w(t + 1) — новый весовой коэффициент.
w — старый весовой коэффициент
err — ошибка(разность правильного ответа и ответа сети)
n — скорость обучения
xi — значение которое пришло на i-ый вход
Я думаю, что вам не совсем понятна скорость обучения и как её искать. Ищется она в диапазоне чисел от 0 до 1, очень часто ставят 0.001, 0.0001 или 1.
Метод обратного распространения ошибки
Это самый лучший метод обучения сетей, который используется как с многослойными, так и однослойными сетями. Чем-то он может напомнить вам delta правило, ибо формула та же.
В данном случае, нам необходимо создать счётчик ошибок. Если показатель счётчика равен 0 — значит нейронная сеть обучена. Конечно же, в данном случае нам необходимо иметь обучающую подборку.
Алгоритм такого обучение следующий:
1. Инициализация весов случайными значениями.
2. Выбрать обучающие данные, подать на входы сети.
3. Вычислить выход сети.
4. Вычислить разность между правильным ответом и неправильным.
5. Корректируем веса для минимизации ошибки.
6. Повторяем 2 и 5 шаг, пока ошибка не достигнет 0 или приемлемого уровня.
Практика
Вот теперь мы практикуем свои знания. Сейчас мы попробуем сделать однослойный персептрон, который будет работать с методом обратного распространения ошибки.
Пусть он строит логическую таблицу функций 'AND' и 'OR'. Кто знаком с алгеброй логики, тот поймёт.
Начнём описывать эту сеть через ООП.
Мы видим, что у нас два входных нейрона, две связи, один выходной нейрон.
public class NeuralNetwork {
static double enters[] = new double[2]; // создаём входы
static double out; // храним выход сети
static double[] weights = {0,0}; // весовые коэффициенты
Теперь нам необходимо создать матрицу готовых ответов и входов для таблицы AND.
static double tableOfLearn[][] = {
{0,0,0},
{1,0,0},
{0,1,0},
{1,1,1}
};
Создаём обработку входных данных. Здесь не так всё сложно. Если вы помните, то входные данные умножающие на соответствующие им по индексу веса и результаты произведений суммируются. Воспользуемся пороговой функцией. Если выход > 0.1, то НС даёт 1.
public static void summator(){
out = 0; обнуляем выход
for ( int i = 0; i < enters.length; i++ )
out+=enters[i]*weights[i]; // вход * вес, суммируем.
if ( out > 0.1 ) out=1; else out=0; // функция активации
}
Теперь пишем обучение сети. Метод обратного распространения ошибки.
Создали счётчик ошибок, запускаем цикл. Копируем в входы НС входные данные из обучающей таблицы. Запускаем обработчик, получаем ошибку. Дальше используем delta правило.
public static void train(){
double gError = 0; // создаём счётчик ошибок
int it = 0; // количество итераций
do {
gError = 0; // обнуляем счётчик
it++; // увеличиваем на 1 итерации
for ( int i = 0; i < tableOfLearn.length; i++ ){
enters = java.util.Arrays.copyOf(tableOfLearn[i],
tableOfLearn[i].length - 1); // копируем в входы обучающие входы
summator(); // суммируем
double error = tableOfLearn[i][2] - out; // получаем ошибку
gError+=Math.abs(error); // суммируем ошибку в модуле
for ( int j = 0; j < enters.length; j++ )
weights[j]+=0.1*error*enters[j]; // старый вес + скорость * ошибку * i-ый вход
}
} while(gError!=0); // пока gError не равно 0, выполняем код
}
Теперь мы запускаем тестер НС. Включаем обучение; НС обучилась; проверяем её работу.
train();
for ( int p = 0; p < tableOfLearn.length; p++ ){
enters = java.util.Arrays.copyOf(tableOfLearn[p],
tableOfLearn[p].length - 1);
summator();
System.out.println(out);
}
Включаем тестирование при запуске программы.
public static void main(String[] args) {
new NeuralNetwork().test();
}
Вот такой результат мы получаем:
Заключение
Конечно, многое может быть вам было не понятно. На сайте я буду писать множество статей о создании разных проектов с НС, поэтому объяснять о них я буду не один раз. Я надеюсь, что кому-то эта статья понравится. Спасибо за внимание, удачного кода и послушного ИИ.
Автор: EmeraldSoft