Для популярного глубокого обучения сейчас необходимо поддерживать дух обучения - программисты, особенно архитекторы, всегда должны быть обеспокоены основными технологиями и ключевыми алгоритмами, и при необходимости вы должны писать и освоить его. Не заботиться о том, когда его использовать - будь то его использовать, является политической проблемой или написать его, это технический вопрос, точно так же, как солдаты не заботятся о том, сражаться или нет, а о том, как победить.
Как программисты изучают машинное обучение
Для программистов машинное обучение имеет определенный порог (этот порог также является его основной конкурентоспособностью). Я полагаю, что у многих людей будут головные боли за английские документы, полные математических формул при обучении машинного обучения, и могут даже сдаться. Но на самом деле программа реализации алгоритма машинного обучения не сложно написать. Ниже приводится обратный многослойный алгоритм нейронной сети (BP), реализованный 70 строк кода, то есть глубокое обучение. На самом деле, это не только нейронные сети, но и большинство алгоритмов машинного обучения, таких как логистическая регрессия, дерево решений C45/ID3, случайный лес, байесовский, совместная фильтрация, графические вычисления, KMEANS, PageRank и т. Д., Может быть реализовано в 100 рядах автономных программ (рассмотрите его позже).
Реальная сложность машинного обучения заключается в том, почему он рассчитывает, как это, каков математический принцип, стоящий за ним и как вывести формулу. Большая часть информации в Интернете вводит эту часть теоретических знаний, но редко рассказывает вам, как процесс расчета и реализация программы алгоритма. Для программистов вам нужно сделать только инженерные приложения, а не доказывать новый метод математического расчета. Фактически, большинство инженеров машинного обучения используют пакеты с открытым исходным кодом или программное обеспечение для инструментов, написанные другими для входных данных и корректировки коэффициентов расчета для обучения результатов, и самостоятельно редко реализует процесс алгоритма. Тем не менее, все еще очень важно освоить процесс расчета каждого алгоритма, чтобы вы могли понять, какие изменения в том, что алгоритм сделал данные и какое влияние является алгоритм для достижения.
Эта статья посвящена внедрению однолеповой нейронной сети. Что касается мульти-машинизированной параллелизации нейронных сетей, Fourinone обеспечивает очень гибкую и полную параллельную основу для вычислений. Нам нужно только понять реализацию автономной программы для зачатия и разработки распределенного параллелизационного решения. Если мы не понимаем процесс расчета алгоритма, все идеи не смогут быть расширены. Кроме того, существует также сверточная нейронная сеть, которая в основном представляет собой идею сокращения размерности, используемая для обработки изображений, которая не находится в рамках этой статьи.
Описание процесса нейронной сети:
Прежде всего, важно показать, что нейронная сеть выполняет задачи прогнозирования. Я считаю, что вы помните наименее квадратный метод, который вы узнали в старшей школе. Мы можем использовать это, чтобы сделать менее строгую, но более интуитивную аналогию:
Во -первых, мы хотим получить маркеры набора данных и набора данных (в методе наименьших квадратов мы также получаем набор значений x и y)
Алгоритм соответствует параметру функции, который может выразить этот набор данных на основе этого набора данных и соответствующих знаков (то есть формула, которая рассчитывает A и B в методе наименьших квадратов, но эта формула не может быть получена непосредственно в нейронной сети)
Получим установленную функцию (то есть установленная линия y^= ax+b в методе наименьших квадратов)
Затем, после того, как внести новые данные, соответствующее прогнозируемое значение y^может быть сгенерировано (в наименее квадратных методах оно должно привлечь y^= ax+b, чтобы получить прогнозируемый y^, как и алгоритм нейронной сети, но полученная функция гораздо более сложна, чем метод наименьших квадратов).
Процесс расчета нейронных сетей
Структура нейронной сети показана на рисунке ниже. Самым левым является входной слой, самый правый - выходной слой, а середина - несколько скрытых слоев. Каждый нейронный узел скрытого слоя и выходной слой накапливается путем умножения предыдущего узла слоя на его вес. Круг, помеченный «+1», является термином перехвата b. Для каждого узла вне входного уровня: y = w0*x0+w1*x1+…+wn*xn+b, мы можем знать, что нейронная сеть эквивалентна структуре многослойной логистической регрессии.
Процесс расчета алгоритма: входной слой запускается, рассчитывает слева направо и продвигается вперед слоем по слою, пока выходной слой не даст результат. Если существует разница между значением результата и целевым значением, вычислите справа налево, вычислите ошибку каждого слоя узла по слою и отрегулируйте все веса каждого узла. После достижения входного слоя в обратном направлении вычислите его снова вперед и перечислите вышеуказанные шаги, пока все параметры веса не сберутся к разумному значению. Поскольку компьютерные программы решают параметры уравнения, а математические методы различны, они обычно сначала выбирают параметры, а затем постоянно регулируют параметры, чтобы уменьшить ошибку до тех пор, пока не будет приближено правильное значение, большая часть машинного обучения постоянно является итеративным обучением. Давайте внимательно рассмотрим реализацию этого процесса из программы.
Алгоритм программы реализации нейронной сети
Реализация программы алгоритма нейронных сетей разделена на три процесса: инициализация, результаты прямого расчета и обратная модификация весов.
1. Процесс инициализации
Поскольку это нейронная сеть N-слоя, мы используем двухмерный слой массива для записи значения узла. Первым измерением является количество слоев, второе измерение - это положение узла слоя, а значение массива - значение узла; Аналогичным образом, значение по ошибке узла также записано аналогичным образом. Используйте трехмерный массив Layer_weight, чтобы записать веса каждого узла. Первым измерением является количество слоев, второе измерение-это положение узла слоя, третье измерение-это положение узла нижнего уровня, значение массива-это значение веса, достигающего более низкого уровня, а начальное значение-случайное число между 0-1. Чтобы оптимизировать скорость конвергенции, здесь используется регулировка веса импульса. Необходимо записать последнюю сумму регулировки веса и использовать трехмерный массив Layer_ween_delta для записи. Перехвата перехвата: программа устанавливает значение перехвата 1, так что ей необходимо только рассчитать его вес.
2. Рассчитайте результаты вперед
Функция S 1/(1+math.exp (-z)) используется для объединения значения каждого узла до 0-1, а затем вычислить его слой по слою до выходного слоя. Для выходного слоя на самом деле нет необходимости использовать функцию S. Мы рассматриваем выходной результат как значение вероятности от 0 до 1, поэтому также используется функция S, что также способствует однородности программы.
3. Поверно изменить вес
Как рассчитать ошибки в нейронных сетях, как правило, используйте функцию квадратной ошибки, следующим образом:
То есть квадраты ошибок множественных выходных терминов и соответствующих целевых значений накапливаются и делятся на 2. Фактически, это функция ошибки логистической регрессии. Что касается того, почему эта функция используется для расчета ошибки, какова математическая рациональность и как она получена, я полагаю, что программисты не хотят быть математиками, поэтому не входите в нее глубже. Что нам нужно сейчас сделать, так это то, как взять минимальное значение ошибки этой функции e и необходимо для ее производства. Если есть некоторые основы производной математики, вы можете попытаться сделать вывод, как получить следующую формулу из производных весов функции e:
Неважно, не сможем ли мы сделать это. Нам просто нужно использовать формулу результата. В нашей программе мы используем Layererr для записи минимизированной ошибки после получения веса E, а затем настроить вес в соответствии с минимальной ошибкой.
Обратите внимание, что здесь используется метод импульса для учета опыта предыдущей корректировки, чтобы не попасть в локальное минимальное значение. K ниже представляет количество итераций, MOBP - это термин импульса, а скорость - это шаг обучения:
ΔW (k+1) = mobp*Δw (k)+скорость*err*слой
Существует также много формул, используемых ниже, и разница в эффекте не слишком велика:
ΔW (k+1) = mobp*Δw (k)+(1-Mobp) скорость*err*слой
Чтобы улучшить производительность, обратите внимание, что реализация программы предназначена для расчета ошибки и некоторое время отрегулировать вес. Во -первых, позиционируйте положение на втором -последнем слое (то есть последний скрытый слой), а затем отрегулируйте весовой слой в обратном слое. Отрегулируйте вес L -слоя в соответствии с ошибкой, рассчитанной по слою L+1, и вычислите ошибку слоя L, и вычислите вес в следующий раз, когда он цикнет для расчета веса до конца первого слоя (входной слой).
краткое содержание
В течение всего процесса расчета значение узла меняется каждый раз, когда он рассчитывается и не нужно сохранено. Параметры веса и параметры ошибок должны быть сохранены и необходимо обеспечить поддержку следующей итерации. Поэтому, если мы задумаем распределенное многочасовое параллельное вычислительное решение, мы можем понять, почему существует концепция сервера параметров в других структурах.
Полная программа реализации многослойной нейронной сети
Следующая программа реализации bpdeep.java может использоваться непосредственно, и также легко изменить ее на любую другую языковую реализацию, такую как C, C#, Python и т. Д., Поскольку все они являются основными операторами, и нет других библиотек Java (кроме случайных функций).
import java.util.Random;public class BpDeep{ public double[][] layer;//Neural network nodes public double[][] layerErr;//Neural network node error public double[][][] layer_weight;//Neural layer node weight public double[][][] layer_weight_delta;//Neural layer node weight momentum public double mobp;//Momentum coefficient public double rate; // коэффициент обучения public bpdeep (int [] layernum, двойной скорость, двойной мобп) {this.mobp = mobp; this.rate = rate; Layer = new Double [layernum.length] []; layererr = new Double [layernum.length] []; layer_weight = new Double [layernum.length] [] []; layer_ween_delta = new Double [layernum.length] [] []; Случайный случайный = new Random (); for (int l = 0; l <layernum.length; l ++) {layer [l] = новый двойной [layernum [l]]; Layererr [l] = новый двойной [Layernum [l]]; if (l+1 <layernum.length) {layer_weight [l] = новый двойной [layermum [l] +1] [Layernum [l+1]]; layer_wehle_delta [l] = new Double [layernum [l] +1] [layernum [l+1]]; for (int j = 0; j <layernum [l] +1; j ++) для (int i = 0; i <layernum [l+1]; i ++) layer_weeps [l] [j] [i] = random.nextdouble (); // Случайная инициализация}}} // Выяснение слоя по сложному слою. l = 1; l <layer.length; l ++) {for (int j = 0; j <layer [l] .length; j ++) {double z = layer_weight [l-1] [слой [l-1] .length] [j]; for (int i = 0; i <layer [l-1] .length; i ++) {layer [l-1] [i] = l == 1? In [i]: слой [l-1] [i]; z+= layer_weight [l-1] [i] [j]*layer [l-1] [i]; } layer [l] [j] = 1/(1+math.exp (-z)); }} return Layer [layer.length-1]; } // обратно рассчитывать слой ошибки по слою и изменить весом обновления обновленного веса (двойной [] tar) {int l = layer.length-1; for (int j = 0; j <layererr [l] .length; j ++) layererr [l] [j] = слой [l] [j]*(1-layer [l] [j])*(tar [j] -layer [l] [j]); while (l-> 0) {for (int j = 0; j <layererr [l] .length; j ++) {double z = 0,0; for (int i = 0; i <layererr [l+1] .length; i ++) {z = z+l> 0? Layererr [l+1] [i]*layer_weight [l] [j] [i]: 0; layer_weem_delta [l] [j] [i] = mobp*layer_ween_delta [l] [j] [i]+скорость*layererr [l+1] [i]*layer [l] [j]; // имплантат слоя корректировки learmement_ -weight [l] [j] [i]+= слой_ -веса. if (j == layererr [l] .length-1) {layer_ween_delta [l] [j+1] [i] = mobp*layer_ween_delta [l] [j+1] [i]+скорость*Layererr [l+1] layer_weight [l] [j+1] [i]+= layer_ween_delta [l] [j+1] [i]; // перехватить регулировку веса}} Layererr [l] [j] = z*layer [l] [j]*(1-слойщик [l] [j]); // Запись}}}} public vid void (двойной [] двойной [] двойной [] двойной [] двойной [двойной [] in in in, double [in in in in in in in in, double [] in double [] in double [] in double [in in in in in in in double [in in in in in double [in in in in double [in in in in double [in in in in double [j]); Computeout (in); обновленная вес (TAR); }}Пример использования нейронных сетей
Наконец, давайте найдем простой пример, чтобы увидеть магические эффекты нейронных сетей. Чтобы облегчить наблюдение за распределением данных, мы выбираем двухмерные данные координат. Есть 4 данные ниже. Блок представляет собой тип данных 1, а треугольник представляет тип данных: 0. Вы можете видеть, что данные, принадлежащие типу блока, - (1, 2) и (2, 1), а данные, принадлежащие типу треугольника, являются (1, 1), (2, 2). Теперь проблема в том, что нам нужно разделить 4 данные на 1 и 0 на плоскости и использовать их, чтобы предсказать тип новых данных.
Мы можем использовать алгоритм логистической регрессии для решения задачи классификации выше, но логистическая регрессия получает линейную прямую линию в качестве разделительной линии. Вы можете видеть, что независимо от того, как расположена красная линия выше, образец всегда ошибочно разделен на разные типы. Следовательно, для приведенных выше данных только одна прямая линия не может правильно разделить свою классификацию. Если мы используем алгоритм нейронной сети, мы можем получить эффект классификации на рисунке ниже, что эквивалентно поиску объединения нескольких прямых линий для разделения пространства, которое выше по точностью.
Вот исходный код этой программы тестирования bpdeeptest.java:
import java.util.arrays; public class bpdeeptest {public static void main (string [] args) {// инициализировать базовую конфигурацию нейронной сети // Первый параметр - это целочисленное массив, представляющее количество слоев нейронной сети и количество узлов на уровень. Например, {3, 10, 10, 10, 10, 2} означает, что входной слой составляет 3 узла, выходной слой составляет 2 узла, а в среднем и 10 узлах на слое // второй параметр - это размер обучения, а третий параметр - коэффициент момента BPDeep bp = new bpdeep (new int [] {2, 2, 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0... // Установите данные выборки, соответствующие вышеуказанным двумерным данным координат Double [] [] data = new Double [] [] {{1,2}, {2,2}, {1,1}, {2,1}}; // Установить целевые данные, соответствующие классификации 4 данных координат [] [] [] target = new Double [] [] {{1,0}, {0,1}, {0,1}, {1,0}}; // Итеративное обучение 5000 раз для (int n = 0; n <5000; n ++) для (int i = 0; i <data.length; i ++) bp.train (data [i], target [i]); // Проверьте пример данных на основе результатов обучения для (int j = 0; j <data.length; j ++) {double [] result = bp.computeout (data [j]); System.out.println (Arrays.toString (data [j])+":"+arrays.tostring (result)); } // Прогнозируйте классификацию новых данных на основе результатов обучения double [] x = new Double [] {3,1}; double [] result = bp.computeout (x); System.out.println (Arrays.toString (x)+":"+arrays.tostring (result)); }} краткое содержание
Приведенная выше программа тестирования показывает, что нейронные сети имеют магические эффекты классификации. На самом деле, нейронные сети имеют определенные преимущества, но они не являются универсальными алгоритмами, близкими к человеческому мозгу. Много раз это может разочаровать нас. Нам также необходимо использовать множество данных из различных сценариев, чтобы наблюдать за его последствиями. Мы можем изменить 1-слойный скрытый слой на N-слой и настроить количество узлов, итераций, размер стадия обучения и коэффициентов импульса на слое, чтобы получить оптимизированный результат. Однако во многих случаях эффект скрытого слоя N-слоя не значительно улучшен, чем у слоя 1. Вместо этого расчет более сложный и трудоемкий. Наше понимание нейронных сетей требует больше практики и опыта.
Выше приведено весь контент, общий в этой статье о реализации алгоритмов глубоких нейронных сети с 70 строк кода Java. Я надеюсь, что это будет полезно для всех. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это.