0x00 сводка
Alink — это платформа алгоритмов машинного обучения нового поколения, разработанная Alibaba на основе вычислительного движка реального времени Flink.Это первая в отрасли платформа машинного обучения, которая поддерживает как пакетные, так и потоковые алгоритмы. Эта и последующие статьи помогут вам проанализировать реализацию многоуровневого персептрона в Alink.
Поскольку общедоступная информация Alink слишком мала, нижеследующее - все предположения, и обязательно будут упущения и ошибки. Я надеюсь, что все укажут, и я обновлю их в любое время.
0x01 Фоновая концепция
Почти все алгоритмы глубокого обучения можно описать как довольно простой рецепт: конкретный набор данных, функция стоимости, процесс оптимизации и модель..
1.1 Нейронная сеть с прямой связью
Нейронная сеть с прямой связью(Feedforward Neural Network, FNN) каждый нейрон делится на разные группы в соответствии с порядком получения информации, и каждую группу можно рассматривать как нейронный слой. Нейроны в каждом слое получают выходные данные нейронов предыдущего слоя и выводят нейроны следующего слоя. Информация во всей сети распространяется в одном направлении, и нет обратного распространения информации (что не то же самое, что обратное распространение ошибки), то есть обратной связи во всей сети нет, и сигнал распространяется в одном направлении от входной слой к выходному слою, который может быть представлен направленным ациклическим графом. В нейронной сети с прямой связью 0-й слой называется входным слоем, последний слой называется выходным слоем, а остальные промежуточные слои называются скрытыми слоями.
Нейронная сеть обратной связиНейроны могут получать не только сигналы от других нейронов, но и свои собственные сигналы обратной связи. По сравнению с нейронной сетью с прямой связью, нейроны в нейронной сети с обратной связью имеют функцию памяти и имеют разные состояния в разное время. Распространение информации в нейронной сети с обратной связью может быть односторонним или двусторонним, поэтому его можно представить ориентированным циклическим графом или неориентированным графом.
Основная цель сети с прямой связью — аппроксимировать некоторую функцию f*. Например, функция регрессии y = f*(x) сопоставляет вход x со значением y. Сеть прямого распространения определяет отображение y = f(x; θ) и изучает значение параметра θ, чтобы приблизить результат к оптимальной функции.
Например, у нас есть три функции f(1), f(2) и f(3), соединенные в цепочку, чтобы сформировать f(x)=f(3)(f(2)(f(1)(x)) ). ЭтиЦепная структура является наиболее часто используемой структурой в нейронных сетях.. В этом случае f(1) называется первым уровнем сети, f(2) — вторым уровнем и так далее. Полная длина цепи называется глубиной модели. Именно из-за этого термина появилось название «глубокое обучение».
Теперь возникает вопрос, зачем нам нужна сеть с прямой связью, когда у нас есть линейная модель машинного обучения? Это связано с тем, что линейные модели ограничены линейными функциями, а нейронные сети — нет. Когда наши данные не являются линейно разделимой линейной моделью, мы сталкиваемся с проблемой аппроксимации, с которой нейронные сети справляются довольно легко. Скрытые слои используются для добавления нелинейности и изменения представления данных, чтобы лучше обобщить функцию.
1.2 Обратное распространение
Как понимать это «обратное распространение»?По сути, основная идея DL состоит в том, чтобы найти соответствующие веса «w» и «b», которые удовлетворяют требованиям функции глобальной ошибки Loss.Тогда возникает проблема: когда полученная ошибка Loss не соответствует требованиям (то есть ошибка слишком велика), ошибка, полученная выходным слоем, может быть передана скрытому слою с помощью «обратного распространения» и присвоена различным Нейроны настраиваются для корректировки «веса» каждого нейрона до тех пор, пока потери не будут соответствовать требованиям. Это основная концепция «распространения ответа на ошибку»..
Здесь мы должны сначала прояснить запутанное понятие, которое часто используется в некоторых местахобратное распространениеОтноситься ко всему алгоритму обучения глубокой модели, на самом деле, это неточно.Общий алгоритм обучения можно разделить на два аспекта:
- Как информация о стоимости передается на каждый уровень глубокой модели?
- На основе информации, переданной этому слою, как должны обновляться параметры этого слоя?
В конкретной структуре информация течет вперед по организационной структуре, что мы называем прямым распространением, Соответственно, обратное распространение относится к потоку информации от задней части к передней вдоль структуры.
В нейронной сети с прямой связью прямое распространение является входом, и оно постепенно абстрагируется в функции в процессе, а обратное распространение — это информация о стоимости текущего выходного значения и ожидаемого результата или ошибки, информация, передаваемая в каждый слой Это информация о стоимости между выходным значением этого слоя и «ожидаемым выходом» этого слоя.
В современных основных средах обратное распространение сочетается с информацией о стоимости и градиентами, чтобы использовать преимуществаВычислительный графреализовать. Следовательно, обратное распространение недоступно только в нейронных сетях или глубоких моделях и не может представлять весь алгоритм обучения глубоких моделей.То, что оно представляет, — это только первая проблема, то есть как обновлять параметры на основе информации о стоимости и как оптимизировать более эффективно Это проблема алгоритма оптимизации. Наиболее эффективные современные алгоритмы оптимизации в основном основаны на градиентном спуске, и над ним было проделано много инновационной работы.
Обобщить процесс обучения глубоких моделейА именно: для данной структуры сети и показателей производительности подробно определяется функция затрат/ошибок/целевой функции, входные данные достигают выходного слоя посредством прямого распространения, а выходные данные, генерируемые каждым или группой входных данных, рассчитываются в соответствии с определенными Функция стоимости Информация о стоимости передается на каждый уровень глубокой модели посредством обратного распространения, и параметры обновляются на каждом уровне на основе градиента информации о стоимости к параметрам до тех пор, пока не будет выполнено условие остановки и обучение не будет завершено.
1.3 Функция стоимости
Что делает функция стоимости, так это показывает разницу между приближением, которое предлагает наша модель, и фактическим целевым значением, которого мы пытаемся достичь.
Обычно функция стоимости содержит по крайней мере один компонент, который позволяет статистически оценить процесс обучения.Наиболее распространенной функцией стоимости является отрицательное логарифмическое правдоподобие, оценка максимального правдоподобия, полученная в результате минимизации функции стоимости. Функция стоимости может также содержать дополнительные условия, такие как условия регуляризации..
В некоторых случаях из-за вычислительных причин мы не можем вычислить функцию стоимости. В этом случае, пока у нас есть способ аппроксимировать его градиент, мы все еще можем аппроксимировать цель минимизации с помощью итеративной численной оптимизации.
Как и алгоритмы машинного обучения, сети с прямой связью также обучаются с использованием методов обучения на основе градиента, в которых такие алгоритмы, как стохастический градиентный спуск, используются для минимизации функции стоимости. Весь процесс обучения сильно зависит от выбора нашей функции стоимости, которая выбирается более или менее так же, как и другие параметрические модели.
Для функции стоимости алгоритма обратного распространения она должна удовлетворять двум свойствам:
-
Функция стоимости должна быть выражена как среднее значение.
-
Функция стоимости не может зависеть от каких-либо активаций сети рядом с выходным слоем.
Форма функции стоимости в основном C(W, B, Sr, Er), где W — вес нейронной сети, B — смещение сети, Sr — вход одной обучающей выборки, а Er — ожидаемый результат обучающей выборки.
1.4 Процесс оптимизации
1.4.1 Итерационный метод
В начале обучения модели алгоритма вес w и смещение b назначаются случайным образом, Теоретически он может появиться где угодно на всем изображении функции, поэтому как заставить его найти нужное нам значение.
Здесь вводится идея «итерации»: мы можем попробовать, подставив разные точки слева и справа, Предполагая, что точка слева от текущего x меньше, чем точка справа, тогда мы можем сделать x станьте точкой слева, а затем продолжайте пробовать, пока не будет найден «минимум». Вот почему алгоритмические модели требуют времени для повторения и обучения.
1.4.2 Градиентный спуск
При использовании итеративного метода возникает другая проблема: такая пошаговая попытка, хотя окончательный результат состоит в том, чтобы найти нужное нам значение, есть ли способ сдвинуть его, когда он далек от "крайнего значения" Когда шаг больше, когда он близок к «экстремальному значению», шаг перемещения становится меньше (для предотвращения пересечения экстремального значения) для достижения более быстрой и точной «сходимости». Если это образ «квадратичной функции», то чем ближе точка к «минимуму», тем меньше «частная производная» функции в этой точке (частная производная есть «наклон функции в этой точке»). точка"). Далее вводится следующий метод:
Основная идея градиентного спуска: Xn представляет собой «размер шага» движения, а последняя часть представляет собой «частную производную» текущей точки в функции, что означает, чем ближе точка к крайней точке , чем меньше «частная производная» , тем «длина шага» хода короткая, и наоборот, если она находится далеко от крайней точки, «длина шага» следующего хода больше.
Изменяя эту формулу на нашу модель алгоритма, мы находим взаимосвязь между «размером движущегося шага» и потерями и (w, b) для достижения быстрой «сходимости».
Благодаря сочетанию «итеративного метода» и «метода градиентного спуска» мы достигаем циклической итерации, каждое обновление будет все ближе и ближе к крайней точке, пока обновленное значение не станет очень маленьким или в пределах нашего диапазона ошибок, обучение закончено, а полученная в это время (w, b) и есть искомая модель.
1.5 Связанные формулы
Ниже приведены соответствующие формулы, которые взяты для справки при чтении.
1.5.1 Взвешенное суммирование h
hj представляет собой взвешенную сумму всех входных данных для текущего узла.
1.5.2 Выходное значение нейрона а
- a_j представляет собой выходное значение нейрона скрытого слоя.
- g() представляет функцию активации, w — вес, а x — вход.
- a_j=x_jk — выходное значение нейрона текущего слоя, равное входному значению нейрона следующего слоя.
1.5.3 Выходное значение y выходного слоя
- y представляет значение выходного слоя, который является конечным результатом.
- h_k представляет собой сумму входных весов нейрона выходного слоя k.
1.5.4 Функция активации g(h)
Используя сигмовидную функцию:
Производная сигмовидной функции:
Подставьте aj=g(hj), чтобы получить
1.5.5 Функция потерь E
Используйте функцию ошибки суммы квадратов
- Квадрат нужен для того, чтобы точки ошибки на обоих концах гиперплоскости не компенсировали друг друга (y−t имеет положительные и отрицательные значения).
- Предыдущий коэффициент принимается равным 1/2, поэтому, когда градиентный спуск используется позже, 2 после квадратной производной можно сместить при вычислении градиента (частной производной).
1.5.6 Обратное распространение ошибки — обновление весов
Используйте градиентный спуск, чтобы найти оптимальное решение, то есть найти частную производную функции потерь E по весу w
Правую часть уравнения можно интерпретировать как: Если мы хотим знать, как ошибка E вывода изменяется при изменении веса w, мы можем наблюдать, как ошибка E изменяется с входным значением h функции активации, и входное значение функции активации Как h зависит от веса w.
h_k представляет собой сумму всех входных весов нейрона выходного слоя k, то есть входное значение функции активации g(h).
1.5.7 Инкрементный член выходного слоя δo
Первый элемент справа более важен, он называется добавочным членом δ (ошибка или дельта-член), и его продолжают получать по цепному правилу, и, наконец, получается добавочный член выходного слоя.
Затем можно обновить веса w выходного слоя.
1.5.8 Обновление веса выходного слоя wjk
Используйте градиентный спуск для функции потерь, чтобы обновить веса:
так получить
ai — выходное значение предыдущего слоя, то есть входное значение xi выходного слоя.
0x02 Пример кода
Пример кода этой статьи выглядит следующим образом:
public class MultilayerPerceptronClassifierExample {
public static void main(String[] args) throws Exception {
BatchOperator data = Iris.getBatchData();
MultilayerPerceptronClassifier classifier = new MultilayerPerceptronClassifier()
.setFeatureCols(Iris.getFeatureColNames())
.setLabelCol(Iris.getLabelColName())
.setLayers(new int[]{4, 5, 3})
.setMaxIter(100)
.setPredictionCol("pred_label")
.setPredictionDetailCol("pred_detail");
BatchOperator res = classifier.fit(data).transform(data);
res.print();
}
}
Радужная оболочка определяется следующим образом
public class Iris {
final static String URL = "https://alink-release.oss-cn-beijing.aliyuncs.com/data-files/iris.csv";
final static String SCHEMA_STR
= "sepal_length double, sepal_width double, petal_length double, petal_width double, category string";
public static BatchOperator getBatchData() {
return new CsvSourceBatchOp(URL, SCHEMA_STR);
}
public static StreamOperator getStreamData() {
return new CsvSourceStreamOp(URL, SCHEMA_STR);
}
public static String getLabelColName() {
return "category";
}
public static String[] getFeatureColNames() {
return new String[] {"sepal_length", "sepal_width", "petal_length", "petal_width"};
}
}
0x03 Общая логика обучения
Класс MultilayerPerceptronTrainBatchOp — это реализация пакетного обучения.
protected BatchOperator train(BatchOperator in) {
return new MultilayerPerceptronTrainBatchOp(this.getParams()).linkFrom(in);
}
Так что это все еще старый способ, просто взгляните на функцию linkFrom в MultilayerPerceptronTrainBatchOp.
Общая идея такова:
- 1) Получите некоторую метаинформацию, такую как имя метки, имя столбца функции, тип функции и т. д.;
- 2) Получить тестовые данные
trainData = getTrainingSamples
; - 3) Обучение
- 3.1) Получить начальные веса
initialWeights = getInitialWeights();
- 3.2) Построить топологию
topology = FeedForwardTopology.multiLayerPerceptron
- 3.3) Создайте тренажер
FeedForwardTrainer
.- 3.3.1) Инициализировать модель
- 3.3.2) Построить целевую функцию
- 3.3.3) Тренер построит оптимизатор на основе целевой функции, где оптимизатор
L-BFGS
.
- 3.4) Тренируйтесь, чтобы получить окончательные веса
weights = trainer.train
- 3.1) Получить начальные веса
- 4) Выходная модель
DataSet<Row>;
- 5) поставить
DataSet<Row>
Преобразовать в таблицу;
@Override
public MultilayerPerceptronTrainBatchOp linkFrom(BatchOperator<?>... inputs) {
BatchOperator<?> in = checkAndGetFirst(inputs);
// 1)获取一些元信息,比如label名称,特征列名,特征类型等。
final String labelColName = getLabelCol();
final String vectorColName = getVectorCol();
final boolean isVectorInput = !StringUtils.isNullOrWhitespaceOnly(vectorColName);
final String[] featureColNames = isVectorInput ? null :
(getParams().contains(FEATURE_COLS) ? getFeatureCols() :
TableUtil.getNumericCols(in.getSchema(), new String[]{labelColName}));
final TypeInformation<?> labelType = in.getColTypes()[TableUtil.findColIndex(in.getColNames(),
labelColName)];
DataSet<Tuple2<Long, Object>> labels = getDistinctLabels(in, labelColName);
// 此处程序变量如下:
labelColName = "category"
vectorColName = null
isVectorInput = false
featureColNames = {String[4]@6412}
0 = "sepal_length"
1 = "sepal_width"
2 = "petal_length"
3 = "petal_width"
labelType = {BasicTypeInfo@6414} "String"
labels = {MapOperator@6415}
// 2)获取测试数据
// get train data
DataSet<Tuple2<Double, DenseVector>> trainData =
getTrainingSamples(in, labels, featureColNames, vectorColName, labelColName);
// train 3)训练
final int[] layerSize = getLayers();
final int blockSize = getBlockSize();
// 3.1)获取初始权重
final DenseVector initialWeights = getInitialWeights();
// 3.2)获取拓扑
Topology topology = FeedForwardTopology.multiLayerPerceptron(layerSize, true);
// 3.3)构建训练器
FeedForwardTrainer trainer = new FeedForwardTrainer(topology,
layerSize[0], layerSize[layerSize.length - 1], true, blockSize, initialWeights);
// 3.4)训练获取最终权重
DataSet<DenseVector> weights = trainer.train(trainData, getParams());
// output model 4)输出模型
DataSet<Row> modelRows = weights
.flatMap(new RichFlatMapFunction<DenseVector, Row>() {
@Override
public void flatMap(DenseVector value, Collector<Row> out) throws Exception {
List<Tuple2<Long, Object>> bcLabels = getRuntimeContext().getBroadcastVariable("labels");
Object[] labels = new Object[bcLabels.size()];
bcLabels.forEach(t2 -> {
labels[t2.f0.intValue()] = t2.f1;
});
MlpcModelData model = new MlpcModelData(labelType);
model.labels = Arrays.asList(labels);
model.meta.set(ModelParamName.IS_VECTOR_INPUT, isVectorInput);
model.meta.set(MultilayerPerceptronTrainParams.LAYERS, layerSize);
model.meta.set(MultilayerPerceptronTrainParams.VECTOR_COL, vectorColName);
model.meta.set(MultilayerPerceptronTrainParams.FEATURE_COLS, featureColNames);
model.weights = value;
new MlpcModelDataConverter(labelType).save(model, out);
}
})
.withBroadcastSet(labels, "labels");
// 5)把DataSet<Row>转成Table
setOutput(modelRows, new MlpcModelDataConverter(labelType).getModelSchema());
}
3.1 Пример общей логической схемы
Общая логическая схема примера выглядит следующим образом: для лучшего понимания порядок шагов инициализации был изменен.
----------------------------------------------------------------------------------------
│ │
│ │
┌──────────────────────┐ ┌────────────────────┐
│ multiLayerPerceptron │ 构建拓扑 │ getTrainingSamples │ 获取训练数据
└──────────────────────┘ └────────────────────┘
│ │ <label index, vector>
│ │
│ │
┌──────────────────────┐ │
│ FeedForwardTopology │ 拓扑,里面包含 layers │
└──────────────────────┘ layers是拓扑的各个层,比如AffineLayer │
│ │
│ │
│ │
┌────────────┐ ┌────────────────────┐
│ initModel │ 初始化模型 │trainData = stack() │
└────────────┘ └────────────────────┘
│ │ 把训练数据压缩成向量
│ │
│ │
┌─────────────────────────────┐ │
│ FeedForwardTrainer(topology)│ 生成训练器 │
└─────────────────────────────┘ │
│ │
│ │
│ │
┌──────────────────────────┐ │
│ AnnObjFunc 目标函数 │ 基于FeedForwardTopology生成优化目标函数 │
│ [topology,topologyModel] │ 成员变量 topology 是神经网络的拓扑 │
└──────────────────────────┘ 成员变量 topologyModel 是计算模型 │
│ │
│ │
│ │
┌──────────────────────────┐ │
│ AnnObjFunc.topologyModel │ 生成目标函数中的拓扑模型 │
└──────────────────────────┘ │
│ │
│ │
│ │
┌───────────────────────────────────────┐ │
│ optimizer = new Lbfgs(..annObjFunc..) │ 生成优化器(训练过程中) │
└───────────────────────────────────────┘ 基于目标函数生成 │
│ │
│ │
│ │
┌──────────────────────────────────┐ │
│ optimizer.initCoefWith(initCoef) │ 初始化优化器 │
└──────────────────────────────────┘ │
│ │
│ │
│ <--------------------------------------------------------│
│
┌──────────────────────────────────────────────┐
│ optimizer.optimize() │ 优化器L-BFGS迭代训练
│ │ │
│ │ │
│ ┌──────────────────────────┐ │
│ │ 计算梯度(利用拓扑模型) │ │
│ │ 1. 计算各层的输出 │ │
│ │ 2. 计算输出层损失 │ │
│ │ 3. 计算各层的Delta │ │
│ │ 4. 计算各层梯度 │ │
│ └──────────────────────────┘ │
│ │ │
│ │ │
│ ┌──────────────────────────┐ │
│ │ 计算方向 │ │
│ │这里没有用到目标函数的拓扑模型 │ │
│ └──────────────────────────┘ │
│ │ │
│ │ │
│ ┌──────────────────────────┐ │
│ │ 计算损失(利用拓扑模型) │ │
│ │ 1. 计算各层的输出 │ │
│ │ 2. 计算输出层损失 │ │
│ └──────────────────────────┘ │
│ │ │
│ │ │
│ ┌──────────────────────────┐ │
│ │ 更新模型 │ │
│ │这里没有用到目标函数的拓扑模型 │ │
│ └──────────────────────────┘ │
│ │ │
│ │ │
└──────────────────────────────────────────────┘
│
│
----------------------------------------------------------------------------------------
Изображение выше может быть искажено на телефоне, поэтому вы также можете увидеть изображение ниже:
3.2 Обзор логики обучающего вызова L-BFGS
Для приведенного выше рисунка необходимо пояснить, что L-BFGS — это наш оптимизатор, и несколько ключевых шагов заключаются в следующем:
-
CalcGradient()
Рассчитать градиент -
CalDirection(...)
Рассчитать направление -
CalcLosses(...)
Рассчитать потери -
UpdateModel(...)
обновить модель
Структура алгоритма в основном не изменилась, разница заключается в конкретной целевой функции и функции потерь. Например, линейная регрессия использует UnaryLossObjFunc, а функция потерь — SquareLossFunc. Многослойный персептрон, используемая здесь целевая функция: AnnObjFunc.
В частности, для многослойного перцептрона шаги, связанные с целевой функцией в L-BFGS, следующие:
CalcGradient вычисляет градиент
- 1) позвонить
AnnObjFunc.updateGradient;
- 1.1) Вызов модели топологии в целевой функции
topologyModel.computeGradient
вычислять- 1.1.1) Рассчитать выход каждого слоя;
forward(data, true)
- 1.1.2) Рассчитать потери выходного слоя;
labelWithError.loss
- 1.1.3) Рассчитать дельту каждого слоя;
layerModels.get(i).computePrevDelta
- 1.1.4) Рассчитать градиент каждого слоя;
layerModels.get(i).grad
- 1.1.1) Рассчитать выход каждого слоя;
- 1.1) Вызов модели топологии в целевой функции
CalDirection Вычисляет направление
- Здесь не используется топологическая модель целевой функции.
CalcLosses рассчитать убытки
- 1) позвонить
AnnObjFunc.calcSearchValues;
Он будет внутренне звонитьcalcLoss
рассчитать убытки;- 1.1) звонок
topologyModel.computeGradient
рассчитать убытки- 1.1.1) Рассчитать выход каждого слоя;
forward(data, true)
- 1.1.2) Рассчитать потери выходного слоя;
labelWithError.loss
- 1.1.1) Рассчитать выход каждого слоя;
- 1.1) звонок
UpdateModel обновляет модель
- Здесь не используется топологическая модель целевой функции.
3.3 Получение обучающих данных
Функция getTrainingSamples получит обучающие данные из необработанных входных данных.
Пример необработанных данных
5.1 3.5 1.4 0.2 Iris-setosa
5 2 3.5 1 Iris-versicolor
5.1 3.7 1.5 0.4 Iris-setosa
6.4 2.8 5.6 2.2 Iris-virginica
6 2.9 4.5 1.5 Iris-versicolor
В основном делается следующим образом:
- 1) Получить метаданные, такие как индекс столбца признаков и индекс столбца меток;
- 2) Транслировать метки, которые позже будут использоваться в функции открытия;
- 3) Нужно инвертировать в открытой функции
label : index
отображение - 4) В функции карты есть две последовательности выполнения, которые преобразуются в
<label index, vector>
такой бинарный- 4.1) В исходном вводе есть векторы, например 5.1 3.5 1.4 0.2 Iris-setosa5.1 3.5 1.4 0.2, жирным шрифтом являются векторы.
- 4.2) В исходном вводе нет вектора, такого как 5,1 3,5 1,4 0,2 Iris-setosa;
Конкретный код выглядит следующим образом:
private static DataSet<Tuple2<Double, DenseVector>> getTrainingSamples(
BatchOperator data, DataSet<Tuple2<Long, Object>> labels,
final String[] featureColNames, final String vectorColName, final String labelColName) {
// 1)获取元数据,比如特征列的index,label列的index;
final boolean isVectorInput = !StringUtils.isNullOrWhitespaceOnly(vectorColName);
final int vectorColIdx = isVectorInput ? TableUtil.findColIndex(data.getColNames(), vectorColName) : -1;
final int[] featureColIdx = isVectorInput ? null : TableUtil.findColIndices(data.getSchema(),
featureColNames);
final int labelColIdx = TableUtil.findColIndex(data.getColNames(), labelColName);
// 程序变量如下
isVectorInput = false
vectorColIdx = -1
featureColIdx = {int[4]@6443}
0 = 0
1 = 1
2 = 2
3 = 3
labelColIdx = 4
DataSet<Row> dataRows = data.getDataSet();
return dataRows
.map(new RichMapFunction<Row, Tuple2<Double, DenseVector>>() {
transient Map<Comparable, Long> label2index;
@Override
public void open(Configuration parameters) throws Exception {
List<Tuple2<Long, Object>> bcLabels = getRuntimeContext().getBroadcastVariable("labels");
this.label2index = new HashMap<>();
// 得倒一个label : index 的映射
bcLabels.forEach(t2 -> {
Long index = t2.f0;
Comparable label = (Comparable) t2.f1;
this.label2index.put(label, index);
});
// 变量是
this = {MultilayerPerceptronTrainBatchOp$2@11578}
label2index = {HashMap@11580} size = 3
"Iris-versicolor" -> {Long@11590} 2
"Iris-virginica" -> {Long@11592} 1
"Iris-setosa" -> {Long@11594} 0
}
@Override
public Tuple2<Double, DenseVector> map(Row value) throws Exception {
Comparable label = (Comparable) value.getField(labelColIdx);
Long labelIdx = this.label2index.get(label);
if (isVectorInput) { // 4.1)如果原始输入中有vector
Vector vec = VectorUtil.getVector(value.getField(vectorColIdx));
// 转换为 <label index, vector> 这样的二元组
if (null == vec) {
return new Tuple2<>(labelIdx.doubleValue(), null);
} else {
return new Tuple2<>(labelIdx.doubleValue(),
(vec instanceof DenseVector) ? (DenseVector) vec
: ((SparseVector) vec).toDenseVector());
}
} else { // 4.2)如果原始输入中没有vector
int n = featureColIdx.length;
DenseVector features = new DenseVector(n);
for (int i = 0; i < n; i++) {
double v = ((Number) value.getField(featureColIdx[i])).doubleValue();
features.set(i, v);
}
// 转换为 <label index, vector> 这样的二元组
return Tuple2.of(labelIdx.doubleValue(), features);
}
}
})
.withBroadcastSet(labels, "labels"); // 2)把labels广播,在open函数中使用;
}
3.4 Построение топологии
FeedForwardTopology.multiLayerPerceptron
Завершены работы по построению топологии нейронной сети прямого распространения.
public static FeedForwardTopology multiLayerPerceptron(int[] layerSize, boolean softmaxOnTop) {
List<Layer> layers = new ArrayList<>((layerSize.length - 1) * 2);
for (int i = 0; i < layerSize.length - 1; i++) {
layers.add(new AffineLayer(layerSize[i], layerSize[i + 1]));
if (i == layerSize.length - 2) {
if (softmaxOnTop) {
layers.add(new SoftmaxLayerWithCrossEntropyLoss());
} else {
layers.add(new SigmoidLayerWithSquaredError());
}
} else {
layers.add(new FuntionalLayer(new SigmoidFunction()));
}
}
return new FeedForwardTopology(layers);
}
Вспомните концепцию: нейронные сети с прямой связью называются сетями, потому что они часто представлены комбинацией множества различных функций. Модель связана с ориентированным ациклическим графом, который описывает, как функции складываются вместе.
Каждый нейрон начинается с входного слоя, получает входные данные предыдущего этапа и выводит на следующий этап до выходного слоя. Отзывов во всей сети нет. Каждый слой содержит несколько нейронов, нейроны одного слоя не связаны друг с другом, а передача информации между слоями осуществляется только в одном направлении. Первый слой называется входным слоем. Последний слой является выходным слоем. Середина — это скрытый слой, называемый скрытым слоем. Скрытый слой может быть одним слоем. Он также может быть многослойным.
FeedForwardTopology — это топология нейронной сети с прямой связью, то есть логическое представление вышеуказанных слоев сети. Эта топология содержит несколько слоев от скрытого слоя до выходного слоя.
/**
* The topology of a feed forward neural network.
*/
public class FeedForwardTopology extends Topology {
/**
* All layers of the topology.
*/
private List<Layer> layers;
}
Построенные переменные топологии примерно таковы, разделены на четыре слоя:
- Аффинный слой
AffineLayer
. Аффинное преобразование = линейное преобразование + перевод, т.е.h = WX + b
; - функциональный слой
FuntionalLayer
, функция которогоSigmoidFunction
, который является активационным слоем, соответствующим предыдущему аффинному слою; - Аффинный слой
AffineLayer
; - выходной слой
SoftmaxLayerWithCrossEntropyLoss
;
Здесь аффинный слой и функциональный слой вместе составляют скрытую единицу. Большинство скрытых единиц можно описать как принимающие входной вектор x и вычисляющие аффинное преобразование.z = wTx+b
, а затем использовать поэлементную нелинейную функцию g(z). Большинство скрытых единиц различаются только видом функции активации g(z).
Теперь распечатайте конкретные переменные во время работы программы, чтобы все могли лучше понять. Видно, что параметры нейронной сети заданы согласно коду примера.setLayers(new int[]{4, 5, 3})
, различные слои здесь также установлены соответственно: 4, 5, 3.
this = {FeedForwardTopology@4951}
layers = {ArrayList@4944} size = 4
0 = {AffineLayer@4947} // 仿射层
numIn = 4
numOut = 5
1 = {FuntionalLayer@4948}
activationFunction = {SigmoidFunction@4953} // 激活函数
2 = {AffineLayer@4949} // 仿射层
numIn = 5
numOut = 3
3 = {SoftmaxLayerWithCrossEntropyLoss@4950} // 激活函数
3.4.1 AffineLayer
даy=A*x+b
Представление , то есть различной информации о конфигурации аффинного слоя, свойств слоя аффинных преобразований.
public class AffineLayer extends Layer {
public int numIn;
public int numOut;
public AffineLayer(int numIn, int numOut) {
this.numIn = numIn;
this.numOut = numOut;
}
@Override
public LayerModel createModel() {
return new AffineLayerModel(this);
}
...
}
3.4.2 FuntionalLayer
даy = f(x)
представление. здесьactivationFunction
этоf(x)
public class FuntionalLayer extends Layer {
public ActivationFunction activationFunction;
@Override
public LayerModel createModel() {
return new FuntionalLayerModel(this);
}
}
3.4.3 SoftmaxLayerWithCrossEntropyLoss
3.4.3.1 Softmax
Выходная функция в основном использует функцию Softmax, которая определяется следующим образом:
Выходной вектор softmax — это вероятность, то есть вероятность того, что образец принадлежит каждому классу! Его роль в логистической регрессии заключается в преобразовании значений линейного прогноза в вероятности класса.
Предположениеz_i = W_i + b_i
является результатом линейного предсказания i-й категории. Результат внесения его в Softmax состоит в том, чтобы сначала взять экспоненту для каждого z_i, чтобы она стала неотрицательной, а затем разделить ее на сумму всех элементов для нормализации. Теперь каждый σ_i = σ_i(z) Его можно интерпретировать как вероятность того, что наблюдаемые данные x принадлежат категории i, или вероятность (вероятность).
Следовательно, цель обучения W полносвязного слоя состоит в том, чтобы сделать выходной W.X, рассчитанный слоем softmax, с наибольшей вероятностью предсказания, соответствующей истинной метке.
3.4.3.2 softmax loss
Разобравшись с softmax, давайте поговорим о потерях softmax. Что означает потеря softmax? детали следующим образом:
- Л - убыток.
- Sj — это j-е значение выходного вектора S softmax, которое представляет вероятность того, что эта выборка принадлежит к j-й категории.
- Перед yj стоит символ суммирования, а диапазон j также равен от 1 до числа категорий T, поэтому y является вектором 1*T, и только одно из значений T в нем равно 1, а другие значения Т-1 равны 0. Итак, какая позиция имеет значение 1? Ответ заключается в том, что значение позиции, соответствующей истинной метке, равно 1, а остальные равны 0.
Таким образом, эта формула на самом деле имеет более простой вид:
Конечно, в это время следует ограничиться тем, что j является реальной меткой, указывающей на текущий образец.
3.4.3.3 cross entropy
Разобравшись с потерями softmax, вы можете взглянуть на перекрестную энтропию. corss entropy означает перекрестную энтропию, и ее формула выглядит следующим образом:
Большинство современных нейронных сетей обучаются с использованием максимального правдоподобия. Это означает, что функция стоимости представляет собой отрицательное логарифмическое правдоподобие, что эквивалентно перекрестной энтропии между обучающими данными и распределением модели. Точная форма функции стоимости меняется вместе с моделью.
В теории информации кросс-энтропия представляет собой два распределения вероятностей p, q, где p представляет собой истинное распределение, а q представляет неверное распределение.В том же наборе событий неверное распределение q используется для представления необходимости возникновения события. , среднее количество битов. Перекрестная энтропия может использоваться в качестве функции потерь в нейронных сетях (машинное обучение), p представляет собой распределение реальных меток, а q — прогнозируемое распределение меток обученной модели, Функция потерь перекрестной энтропии может измерять сходство между p и кв.
Как вы думаете, это похоже на формулу потери softmax? Когда вход P перекрестной энтропии является выходом softmax, перекрестная энтропия равна потерям softmax. Pj — это j-е значение входного вектора вероятности P, поэтому, если ваша вероятность получена по формуле softmax, то перекрестная энтропия — это потеря softmax.
Одним из преимуществ использования максимальной вероятности для получения функции стоимости является то, что это снижает нагрузку на разработку функции стоимости для каждой модели. Задание модели p(y|x) автоматически определяет функцию стоимости logp(y|x). Градиент функции стоимости должен быть достаточно большим и предсказуемым, чтобы обеспечить хорошее руководство для алгоритма обучения.
3.4.3.4 SoftmaxLayerWithCrossEntropyLoss
SoftmaxLayerWithCrossEntropyLoss
представляет собой слой softmax с перекрестной потерей энтропии, то есть слой softmax с перекрестной потерей энтропии.
public class SoftmaxLayerWithCrossEntropyLoss extends Layer {
@Override
public LayerModel createModel() {
return new SoftmaxLayerModelWithCrossEntropyLoss();
}
}
3.5 Создание тренажера
Вспомнить пример кода
.setLayers(new int[]{4, 5, 3})
Здесь задается структура нейронной сети. Входной слой — 4, скрытый слой — 5, выходной слой — 3.
Код для создания тренера выглядит следующим образом:
FeedForwardTrainer trainer = new FeedForwardTrainer(topology,
layerSize[0], layerSize[layerSize.length - 1], true, blockSize,
initialWeights);
FeedForwardTrainer — это тренажер для нейронных сетей с прямой связью.
public class FeedForwardTrainer implements Serializable {
private Topology topology;
private int inputSize;
private int outputSize;
private int blockSize; // 数据分块大小,默认值64,在压缩时候被stack函数调用到
private boolean onehotLabel;
private DenseVector initialWeights;
}
Переменная печатается следующим образом
trainer = {FeedForwardTrainer@6456}
topology = {FeedForwardTopology@6455}
layers = {ArrayList@4963} size = 4
0 = {AffineLayer@6461}
1 = {FuntionalLayer@6462}
2 = {AffineLayer@6463}
3 = {SoftmaxLayerWithCrossEntropyLoss@6464}
inputSize = 4
outputSize = 3
blockSize = 64
onehotLabel = true
initialWeights = null
Мы видим, что основной переменной для обучения является FeedForwardTrainer, которая содержит топологию модели топологии, состоящую из четырех слоев.
Мы также заранее показываем оптимизатор и целевую функцию, используемые тренером. Тренер использует оптимизатор для оптимизации целевой функции.
Здесь оптимизатор — Lbfgs, а целевая функция, которую он содержит, — AnnObjFunc, которая содержит топологию и топологическую модель.
public class AnnObjFunc extends OptimObjFunc {
private Topology topology;
private transient TopologyModel topologyModel = null;
}
Модель топологии генерируется в соответствии с топологией, здесь FeedForwardModel, а модели, соответствующие каждому слою, — это AffineLayerModel, FuntionalLayerModel и т. д.
Роль каждой модели слоя заключается в расчете потерь, градиента и т. д. Например, AffineLayerModel.eval — это простое аффинное преобразование WX + b.
На данный момент завершена первая часть многослойного персептрона. Пожалуйста, с нетерпением ждите следующего.
0xEE Личная информация
★★★★★★Думая о жизни и технологиях★★★★★★
Публичный аккаунт WeChat: мысли Росси
Если вы хотите получать своевременные новости о статьях, написанных отдельными лицами, или хотите видеть технические материалы, рекомендованные отдельными лицами, обратите внимание.
ссылка 0xFF
Введение в сети глубокой прямой связи в глубоком обучении
Глубокое изучение китайского перевода
Введение в глубокое обучение — Аффинный слой (аффинный слой — матричный продукт)
Машинное обучение — соответствующие формулы многослойного персептрона MLP
Авария многослойного персептрона
Нейронная сеть (многослойный персептрон) Обнаружение мошенничества с кредитными картами (1)
【Машинное обучение】Искусственная нейронная сеть ИНС
Вывод формулы для искусственной нейронной сети (ИНС)
Подробный анализ softmax и softmax loss
Функция потерь Softmax и расчет градиента
Softmax vs. Softmax-Loss: Numerical Stability
[Технический обзор] Потеря Softmax и ее варианты в одной статье
Введение в нейронные сети с прямой связью: почему это важно?
Базовое понимание глубокого обучения: нейронные сети с прямой связью в качестве примера
Модели контролируемого обучения и регрессии
Машинное обучение — нейронные сети с прямой связью
Продукт AI: нейронная сеть с прямой связью BP и проблема градиента