Продолжая предыдущую статью, в этой статье мы рассмотрим линейную и логистическую регрессию с помощью Tensorflow и прольем свет на основные различия между версиями 1 и 2. Прежде чем мы начнем, было бы неплохо немного обсудить фреймворк.

Tensorflow был создан исследователями из Google как программная библиотека с открытым исходным кодом для Machine Intelligencefили производства и исследований. В настоящее время более зрелая версия называется сквознойплатформой машинного обучения с открытым исходным кодом. Tensorflow основан на вычислении на основе графа, концепции для представления математических вычислений. До версии 2 было очень трудно переварить и выбраться из многочисленных подпрограмм из-за отсутствия документации и готовых руководств — до сих пор. В качестве альтернативы другие фреймворки, такие как популярный Keras, пришли на помощь в качестве библиотеки-оболочки и предложили уровень (а может и больше) уровней абстракции над Tensorflow и, наконец, стали стандартом по умолчанию в TF v2.

Линейная регрессия v1

Теперь, когда мы уже знакомы с понятием линейной регрессии, мы можем пойти дальше и обучить очень простую модель линейной связи между X и Y.

Набор данных для нашего тематического исследования – Коэффициент рождаемости – ожидаемая продолжительность жизни. Он состоит из коэффициента рождаемости (X) и соответствующей ожидаемой продолжительности жизни (Y) для ряда стран. Предполагая, что связь между ними является линейной Y = w*X + b, мы можем обучить модель, которая вычисляет W и b.

TF v1 позволяет нам реализовать вычислительный граф с нуля, используя заполнители для представления нашего набора данных и скалярные переменные для веса и смещения, которые будут вычисляться с помощью обратного распространения.

Затем мы определяем формулу прогнозирования с помощью вычислений тензорного потока и используем ее встроенные функции для функции потерь MSE и оптимизатора градиентного спуска.

Теперь, когда мы определили компоненты вычислительного графа, нам нужно сообщить тензорному потоку, что мы собираемся вывести наши данные и обучить переменные. В tf v1 это достигается с помощью сеанса, где после инициализации графа мы выводим набор данных по вычислительному графу. Методы подготовки наборов данных могут быть отдельной главой, но они уже упрощены в v2. В этом случае используется feed dictapi.

Epoch 10: | Loss: 375.46, w: 3.51, b: 41.13
Epoch 20: | Loss: 130.94, w: -0.88, b: 61.19
Epoch 30: | Loss: 59.20, w: -3.26, b: 72.10
Epoch 40: | Loss: 38.30, w: -4.56, b: 78.04
Epoch 50: | Loss: 32.29, w: -5.27, b: 81.27
Train Time: 6.204496 seconds

Вы также можете заметить, что существует объект FileWriter, созданный перед обучением, и это указывает на запись вычислительного графа, визуализированного с помощью Tensorboard.

По умолчанию в v1 вам не разрешено просматривать содержимое переменных вне сеанса, и это проблема, когда вам нужно отлаживать свою модель. Единственный способ сделать это — включить активное выполнение, но это не действует как волшебная палочка, поскольку вам нужно реорганизовать свою программу. В последней версии Tensorflow активное выполнение является стандартным по умолчанию и оценивает операции немедленно, без построения вычислительных графов, что значительно упрощает начало работы, поскольку предлагает более естественный поток программирования в отличие от громоздкого стиля программирования в v1.

Линейная регрессия v2

Повторная реализация модели линейной регрессии с помощью простой нейронной сети в Tensorflow v2 значительно упрощает мониторинг вычислений и вычисление градиентов. Будем наивно говорить, что новый API от Keras tf.GradientTape заменил функционал tf.Session. GradientTape возвращает объект Tensor, который берет на себя любую назначенную операцию/вычисление и также может быть преобразован в np.array.

Weights и bias теперь являются tf.Variable объектами, что, кстати, в Tensorflow v1 считалось старым способом назначения переменных в отношении tf.get_variable.

Функция прогнозирования, потери и оптимизатор теперь могут быть определены так же просто, как написать строку кода на Python.

Процесс обучения легче усваивается и понимается, и для его сходимости требуется меньше времени, чем для API feed_dict.

Epoch: 100 | Loss: 652.59, w: 10.31, b: 30.24
Epoch: 200 | Loss: 324.81, w: 5.31, b: 47.55
Epoch: 300 | Loss: 169.67, w: 1.87, b: 59.46
Epoch: 400 | Loss: 96.24, w: -0.50, b: 67.65
Epoch: 500 | Loss: 61.48, w: -2.13, b: 73.29
Epoch: 600 | Loss: 45.03, w: -3.25, b: 77.16
Epoch: 700 | Loss: 37.24, w: -4.02, b: 79.83
Epoch: 800 | Loss: 33.56, w: -4.55, b: 81.67
Epoch: 900 | Loss: 31.81, w: -4.91, b: 82.93
Epoch: 1000 | Loss: 30.99, w: -5.17, b: 83.80
Train Time: 2.776154 seconds

Логистическая регрессия

Двигаясь вперед к более продвинутой реализации логистической регрессии с одной нейронной сетью, мы подойдем к многоклассовой классификациизадачи, используя набор данных MNIST, набор рукописных данных. цифры от 0 до 9.

Подготовка набора данных

Этот пример также можно считать учебным пособием по Tensorflow v1, в котором используется специальная терминология, встроенные процедуры и tf.data API, более быстрый метод по сравнению с заполнителями и feed_dict для загрузки набора данных.

На следующем шаге мы должны определить процесс для перебора выборок/цифр набора данных, скажем, итератор. Каждый раз, когда обрабатывается новая партия/образец, вызывается get_next(). При построении классификатора мы не будем обрабатывать выборки данных по одной, так как это замедлит обучение из-за размера набора данных. Таким образом, мы собираемся обрабатывать данные пакетами, чтобы ускорить процесс. Мы также явно определяем, чтобы не отбрасывать оставшиеся образцы в последней партии при итерации (обучение и тестирование), если они не соответствуют обучающему набору с drop_remainder=False

После каждой эпохи тензорному потоку необходимо перематывать набор данных на следующую эпоху и продолжать обучение. Операция инициализации определяется с помощью объекта iterator.make_initializer(), который получает часть набора данных.

Подробнее о том, как пакеты потребляются в процессе обучения, мы поговорим в следующем разделе.

В этом случае веса и смещения также должны соответствовать размерам набора данных.

Рассчитать убыток

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

Насколько эти вероятности приводят к правильному прогнозу, измеряется с помощью перекрестной энтропии, которая а) применяет активацию softmax к логитам, преобразуя выходные данные в нормализованные вероятности, суммированные до 1. ака прогнозы и б) вычисляет расстояние от истины.

Общие потери рассчитываются по среднему значению всех обучающих экземпляров.

# Sample output from a single 128 size batch
# Logits (10,128)
[[-0.02467263  0.0407119   0.03357347 ...  0.07849845 -0.04018284
   0.14606732] 
...
[-0.03187682  0.03064402  0.02814235 ...  0.12632789 -0.07327773
   0.16343306]]
# Softmax + Cross Entropy (128,)
[2.280719  2.3213248 ... 2.2659633 2.3112588]
# Batch Loss
2.315973

Оптимизатор

В диалекте tensorflowоптимизатор — это операция, которая используется для минимизации потерь. Он выполняется в session.run(), передается в списке вместе с вычислением потери. Это связано с тем, что график вычислений Tensorflow выполняет части, от которых зависит оптимизатор, такие потери и потери также зависят от входных данных, весов и смещения. Это видно из следующего графика, созданного в tensorboard.

optimizer=tf.train.GradientDescentOptimizer(0.001).minimize(loss)
# Training process
_, batch_loss, batch_acc = sess.run([optimizer, loss, accuracy])

Матрица точности и путаницы

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

# Sample output from a single 128 size batch
# Predictions (10,128)
[[0.099 0.10 0.11 ... 0.08 0.09 0.09]
...
[0.11 0.10 0.09  ... 0.08 0.10 0.10]]
# Correct Preds (128,)
[False True ... False False]
# Batch Accuracy
0.078
------------------------------------------------------------------Training...
Epoch 10 - Train loss: 0.875 - Train Accuracy: 83.16%
Epoch 20 - Train loss: 0.653 - Train Accuracy: 85.49%
Epoch 30 - Train loss: 0.564 - Train Accuracy: 86.53%
Epoch 40 - Train loss: 0.515 - Train Accuracy: 87.21%
Epoch 50 - Train loss: 0.483 - Train Accuracy: 87.73%
Epoch 60 - Train loss: 0.460 - Train Accuracy: 88.10%

Evaluating...
Test Validation loss: 0.067, Validation Accuracy: 89.09%

Обучение и пакетная обработка

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

Например, в наборе данных поезда из 55 тыс. выборок и batch_size=12811_будет 430 раз, когда drop_remainder=Falseи 429, когда True.

Последнее означает, что когда эпохе требуется еще один пакет для завершения, он просто отбрасывает его и немедленно истощает итератор (128x429=54912 выборок)

Выводы

Эта статья завершает расширенное исследование регрессии. Если вы новичок и не потратили много времени на то, чтобы углубиться в то, как работает вычислительный граф и выполняет всю магию под капотом, tensorflow версии 1.x дает вам шанс!

В следующей статье мы заставим многослойный персептрон (MLP) изучать наборы данных игровой площадки Tensorflow.

Исходный код: https://github.com/sniafas/ML-Projects/tree/master/Regression

Ссылки:

[1] https://huyenchip.com/

[2] https://www.tensorflow.org/guide/autodiff

[3] https://www.easy-tensorflow.com/tf-tutorials/basics/introduction-to-tensorboard

[4] https://stackoverflow.com/questions/34240703/what-is-logits-softmax-and-softmax-cross-entropy-with-logits