Обложка: Первое знакомство с нейронными сетями на примере Tensorflow 2

Первое знакомство с нейронными сетями на примере Tensorflow 2

Григорий Бузмарев
Григорий Бузмарев

Вackend-разработчик TAGES

Далее будут описаны основные шаги создания нейронный сетей при работе с Tensorflow. Прежде чем начать, необходимо выбрать среду разработки. Я рекомендую использовать для несложных сетей https://colab.research.google.com. Это бесплатная среда разработки написаная командой Google специально для решений в области машинного обучения и нейронных сетей.

Основные шаги:

  1. Предобработка данных.
  2. Построение модели.
  3. Компиляция модели.
  4. Обучение модели.
  5. Оценка модели.

Предобаботка данных

Результат вашей работы наполовину зависит от того, как хорошо вы подготовите данные для модели. Пропущенные данные или неправильная размерность может свести на нет все усилия. Поэтому важно уделить этому этапу и время, и внимание.

По сути для обработки данных можно использовать то, что удобнее. Можно писать свои функции на Python или использовать библиотеку sklearn.preprocessing. В самом tensorflow тоже есть средства для предобработки в модуле tf.keras.preprocessing. В частности большой выбор инструментов для изображений и текста.

На что обратить внимание в первую очередь:

  1. Пропуски в данных. Ситуацию можно исправить несколькими способами. Если таких записей немного, и ими можно пренебречь, то их можно удалить. Также их можно заменить: это может быть среднее значение или наиболее часто используемое для данной фичи.
  2. Нормализация данных. Приведение значение к определенному диапазону. Например [-1; 1] или z-масштабирование (в sklearn это StandardScaler).
  3. Обработка категориальных данных. Как правило, это создание под каждую категорию своей фичи. Можно использовать OneHotEncoder из sklearn или get_dummies в pandas.

Также необходимо разбить данные на 3 выборки:

  • обучающую,
  • валидационную,
  • тестовую.

Обучающий набор данных — это то, на чём непосредственно обучается модель. Валидация нужна для проверки вашей модели. В процессе обучения сеть может слишком сильно подстроиться под данные, на которых обучается. В результате такая модель не сможет работать с данными отличными от обучающего набора. Это явление называется переобучением. Чтобы избежать этого нужен валидационный набор на котором контролируется, как модель предсказывает. Тестовый набор используется только один раз, когда сеть полностью обучена, для финальной оценки. После этого сеть не доучивается и не изменяется. Обычно на валидационный набор выделяется 20-30% данных и на тестовый 5-10%.

Построение модели

Проще всего создать модель с помощью класса Sequential, который принимает список слоев. Чтобы посмотреть содержимое модели нужно вызвать метод summary(). Важно назначить размер входных данных. Это можно сделать с помощью атрибута input_shape в первом слое.

import tensorflow as tf

model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(32, activation='relu', input_shape=(10,), name='hidden_layer_1'),
  tf.keras.layers.Dropout(0.2, name='dropout'),
  tf.keras.layers.Dense(10, name='hidden_layer_2')
])
model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
hidden_layer_1 (Dense)       (None, 32)                352       
_________________________________________________________________
dropout (Dropout)            (None, 32)                0         
_________________________________________________________________
hidden_layer_2 (Dense)       (None, 10)                330       
=================================================================
Total params: 682
Trainable params: 682
Non-trainable params: 0
_________________________________________________________________

Слои можно добавлять и последовательно, используя метод add(). Например, добавим пару дополнительных слоев и вызовем summary().

model.add(tf.keras.layers.Dense(5, activation='relu', name='hidden_layer_3'))
model.add(tf.keras.layers.Dense(2, name='output'))
model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
hidden_layer_1 (Dense)       (None, 32)                352       
_________________________________________________________________
dropout (Dropout)            (None, 32)                0         
_________________________________________________________________
hidden_layer_2 (Dense)       (None, 10)                330       
_________________________________________________________________
hidden_layer_3 (Dense)       (None, 5)                 55        
_________________________________________________________________
output (Dense)               (None, 2)                 12        
=================================================================
Total params: 749
Trainable params: 749
Non-trainable params: 0
_________________________________________________________________

Заметьте, к модели добавилось ещё два слоя. Внизу указывается количество параметров, которые нужно обучить. Соответственно, чем больше параметров, тем дольше будет обучаться ваша сеть.

Sequential удобен если у вас небольшая сеть с последовательной структурой, где слои следуют друг за другом, есть только один вход и один выход. Но что делать если модель должна быть немного хитрее? Для этого в tensorflow есть функциональный API. Перепишем модель выше.

input = tf.keras.Input(shape=(10,), name='input')
layer_1 = tf.keras.layers.Dense(32, activation='relu', name='hidden_layer_1')(input)
dropout = tf.keras.layers.Dropout(0.2, name='dropout')(layer_1)
layer_2 = tf.keras.layers.Dense(10, name='hidden_layer_2')(dropout)
layer_3 = tf.keras.layers.Dense(5, activation='relu', name='hidden_layer_3')(layer_2)
output = tf.keras.layers.Dense(2, name='output')(layer_3)

model_2 = tf.keras.Model(
    inputs=input,
    outputs=output,
)

model_2.summary()
Model: "model_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input (InputLayer)           [(None, 10)]              0         
_________________________________________________________________
hidden_layer_1 (Dense)       (None, 32)                352       
_________________________________________________________________
dropout (Dropout)            (None, 32)                0         
_________________________________________________________________
hidden_layer_2 (Dense)       (None, 10)                330       
_________________________________________________________________
hidden_layer_3 (Dense)       (None, 5)                 55        
_________________________________________________________________
output (Dense)               (None, 2)                 12        
=================================================================
Total params: 749
Trainable params: 749
Non-trainable params: 0
_________________________________________________________________

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

tf.keras.utils.plot_model(model_2, show_shapes=True)

С помощью функционального API можно создать структуру с несколькими входами и выходами.

# Назначим два отдельных входа
input_1 = tf.keras.Input(shape=(10,), name='input_1')
input_2 = tf.keras.Input(shape=(20,), name='input_2')

# Определим структуру для обработки первого входа
layer_1 = tf.keras.layers.Dense(32, name='layer_1')(input_1)

# Для второго входа
layer_2 = tf.keras.layers.Dense(32, name='layer_2')(input_2)
layer_3 = tf.keras.layers.Dense(16, name='layer_3')(layer_2)

# Объединим
concatenate = tf.keras.layers.concatenate([layer_1, layer_3])

# Определим два выхода
output_1 = tf.keras.layers.Dense(1, name='output_1')(concatenate)
output_2 = tf.keras.layers.Dense(1, name='output_2')(concatenate)

model_3 = tf.keras.Model(
    inputs=[input_1, input_2],
    outputs=[output_1, output_2],
)

tf.keras.utils.plot_model(model_3, show_shapes=True)

Компиляция модели

После того как структура модели готова, её нужно скомпилировать. Для этого у модели есть метод compile(). Главное, что можно определить при компиляции — это функция потерь. По сути, от неё зависит результат обучения. Например, среднеквадратичная ошибка сильнее «наказывает» модель за выбросы чем средняя абсолютная ошибка. Что именно использовать, зависит от задачи. Если вам нужно предсказать цену жилья, то, скорее всего, выбросы плохо повлияют на результат. В этом случае больше подойдёт средняя абсолютная ошибка. Если вы предсказываете движение цен на фондовом рынке, то слишком большое отклонение от цены будет во вред, и здесь лучше среднеквадратичная ошибка.

Ещё один важный параметр — это алгоритм оптимизации. Хорошо подобранный оптимизатор позволит вам быстрее обучить модель и по возможности избежать локальных минимумов.

model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(5, input_shape=(10,), name='hidden_layer_1'),
  tf.keras.layers.Dense(2, name='output')
])

model.compile(
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), # Функция потерь
    optimizer='Adam', # Оптимизатор
    metrics=[ # Метрики
        'accuracy', # Если у объекта назначено имя, то можно вызвать объект с его помощью
        tf.keras.metrics.Precision()
    ]
)

Обучение модели

После того как модель скомпилирована её нужно обучить. Для этого применяется метод fit(). Он принимает входные данные и ожидаемые ответы сети. Можно указать массив с валидационными данными, максимальное количество эпизодов и многое другое. Простой пример:

import numpy as np

# Инициализируем набор данных случайными цифрами.
X = np.array(np.random.random((100, 5))) # Матрица 100 на 10 с диапазоном значений [0;1]
Y = np.array(np.random.random((100))) # Вектор длины 100 с диапазоном значений [0;1]

# Создадим модель
model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(3, input_shape=(5,)),
  tf.keras.layers.Dense(1)
])

# Скомпилируем
model.compile(
    optimizer='Adam',
    loss='mse',
    metrics=['mean_absolute_error']
)

# Обучим
model.fit(
    X, # Набор входных данных
    Y, # Набор правильных ответов
    validation_split=0.2, # Этот параметр автоматически выделит часть обучающего набора на валидационные данные. В данном случа 20%
    epochs=10, # Процесс обучения завершится после 10 эпох
    batch_size = 8 # Набор данных будет разбит на пакеты (батчи) по 8 элементов набора в каждом. 
)
Epoch 1/10
10/10 [==============================] - 0s 16ms/step - loss: 0.2524 - mean_absolute_error: 0.4273 - val_loss: 0.2713 - val_mean_absolute_error: 0.4401
Epoch 2/10
10/10 [==============================] - 0s 3ms/step - loss: 0.2353 - mean_absolute_error: 0.4063 - val_loss: 0.2420 - val_mean_absolute_error: 0.4183
Epoch 3/10
10/10 [==============================] - 0s 5ms/step - loss: 0.2256 - mean_absolute_error: 0.4017 - val_loss: 0.2348 - val_mean_absolute_error: 0.4122
Epoch 4/10
10/10 [==============================] - 0s 4ms/step - loss: 0.2203 - mean_absolute_error: 0.3968 - val_loss: 0.2309 - val_mean_absolute_error: 0.4095
Epoch 5/10
10/10 [==============================] - 0s 4ms/step - loss: 0.2166 - mean_absolute_error: 0.3937 - val_loss: 0.2251 - val_mean_absolute_error: 0.4045
Epoch 6/10
10/10 [==============================] - 0s 3ms/step - loss: 0.2094 - mean_absolute_error: 0.3857 - val_loss: 0.2262 - val_mean_absolute_error: 0.4072
Epoch 7/10
10/10 [==============================] - 0s 3ms/step - loss: 0.2056 - mean_absolute_error: 0.3810 - val_loss: 0.2251 - val_mean_absolute_error: 0.4072
Epoch 8/10
10/10 [==============================] - 0s 3ms/step - loss: 0.1999 - mean_absolute_error: 0.3757 - val_loss: 0.2174 - val_mean_absolute_error: 0.4004
Epoch 9/10
10/10 [==============================] - 0s 3ms/step - loss: 0.1950 - mean_absolute_error: 0.3710 - val_loss: 0.2134 - val_mean_absolute_error: 0.3971
Epoch 10/10
10/10 [==============================] - 0s 3ms/step - loss: 0.1909 - mean_absolute_error: 0.3661 - val_loss: 0.2093 - val_mean_absolute_error: 0.3935
<tensorflow.python.keras.callbacks.History at 0x7f2e99ae3d90>

В выводе показывается результат выполнения каждой эпохи. Выводится номер эпохи, количество пакетов, затраченное на эпоху время и ошибки. Loss — это расчитанная функция потерь, mean_absolute_error — это метрика указанная при компиляции. Если указать дополнительные метрики, то они тоже будут присутствовать в выводе. Все ошибки с префиксом «val_» — это то же самое только для валидационного набора данных.

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

# Если ошибка не уменьшается на протяжении указанного количества эпох, то процесс обучения прерывается и модель инициализируется весами с самым низким показателем параметра "monitor"
early_stopping = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', # указывается параметр, по которому осуществляется ранняя остановка. Обычно это функция потреть на валидационном наборе (val_loss)
    patience=2, # количество эпох по истечении которых закончится обучение, если показатели не улучшатся
    mode='min', # указывает, в какую сторону должна быть улучшена ошибка
    restore_best_weights=True # если параметр установлен в true, то по окончании обучения модель будет инициализирована весами с самым низким показателем параметра "monitor"
)

# Сохраняет модель для дальнейшей загрузки
model_checkpoint = tf.keras.callbacks.ModelCheckpoint(
    filepath='my_model', # путь к папке, где будет сохранена модель
    monitor='val_loss',
    save_best_only=True, # если параметр установлен в true, то сохраняется только лучшая модель
    mode='min'
)

# Сохраняет логи выполнения обучения, которые можно будет посмотреть в специальной среде TensorBoard
tensorboard = tf.keras.callbacks.TensorBoard(
    log_dir='log', # путь к папке где будут сохранены логи
)

Обучим эту же модель, но уже с используя обратные вызовы.

model.fit(
    X,
    Y,
    validation_split=0.2,
    epochs=50,
    batch_size = 8,
    callbacks = [
        early_stopping,
        model_checkpoint,
        tensorboard
    ]
)
Epoch 1/50
10/10 [==============================] - 0s 10ms/step - loss: 0.1864 - mean_absolute_error: 0.3616 - val_loss: 0.2080 - val_mean_absolute_error: 0.3932
INFO:tensorflow:Assets written to: my_model/assets
Epoch 2/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1831 - mean_absolute_error: 0.3582 - val_loss: 0.2025 - val_mean_absolute_error: 0.3879
INFO:tensorflow:Assets written to: my_model/assets
Epoch 3/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1808 - mean_absolute_error: 0.3549 - val_loss: 0.2050 - val_mean_absolute_error: 0.3918
Epoch 4/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1753 - mean_absolute_error: 0.3484 - val_loss: 0.1978 - val_mean_absolute_error: 0.3846
INFO:tensorflow:Assets written to: my_model/assets
Epoch 5/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1715 - mean_absolute_error: 0.3442 - val_loss: 0.1938 - val_mean_absolute_error: 0.3808
INFO:tensorflow:Assets written to: my_model/assets
Epoch 6/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1679 - mean_absolute_error: 0.3398 - val_loss: 0.1908 - val_mean_absolute_error: 0.3780
INFO:tensorflow:Assets written to: my_model/assets
Epoch 7/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1654 - mean_absolute_error: 0.3370 - val_loss: 0.1876 - val_mean_absolute_error: 0.3748
INFO:tensorflow:Assets written to: my_model/assets
Epoch 8/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1615 - mean_absolute_error: 0.3333 - val_loss: 0.1866 - val_mean_absolute_error: 0.3747
INFO:tensorflow:Assets written to: my_model/assets
Epoch 9/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1588 - mean_absolute_error: 0.3297 - val_loss: 0.1824 - val_mean_absolute_error: 0.3700
INFO:tensorflow:Assets written to: my_model/assets
Epoch 10/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1562 - mean_absolute_error: 0.3267 - val_loss: 0.1813 - val_mean_absolute_error: 0.3699
INFO:tensorflow:Assets written to: my_model/assets
Epoch 11/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1534 - mean_absolute_error: 0.3227 - val_loss: 0.1768 - val_mean_absolute_error: 0.3647
INFO:tensorflow:Assets written to: my_model/assets
Epoch 12/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1502 - mean_absolute_error: 0.3192 - val_loss: 0.1757 - val_mean_absolute_error: 0.3643
INFO:tensorflow:Assets written to: my_model/assets
Epoch 13/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1474 - mean_absolute_error: 0.3161 - val_loss: 0.1736 - val_mean_absolute_error: 0.3624
INFO:tensorflow:Assets written to: my_model/assets
Epoch 14/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1455 - mean_absolute_error: 0.3135 - val_loss: 0.1695 - val_mean_absolute_error: 0.3574
INFO:tensorflow:Assets written to: my_model/assets
Epoch 15/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1429 - mean_absolute_error: 0.3102 - val_loss: 0.1677 - val_mean_absolute_error: 0.3558
INFO:tensorflow:Assets written to: my_model/assets
Epoch 16/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1420 - mean_absolute_error: 0.3100 - val_loss: 0.1685 - val_mean_absolute_error: 0.3579
Epoch 17/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1399 - mean_absolute_error: 0.3079 - val_loss: 0.1617 - val_mean_absolute_error: 0.3488
INFO:tensorflow:Assets written to: my_model/assets
Epoch 18/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1362 - mean_absolute_error: 0.3027 - val_loss: 0.1607 - val_mean_absolute_error: 0.3482
INFO:tensorflow:Assets written to: my_model/assets
Epoch 19/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1346 - mean_absolute_error: 0.3015 - val_loss: 0.1592 - val_mean_absolute_error: 0.3470
INFO:tensorflow:Assets written to: my_model/assets
Epoch 20/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1324 - mean_absolute_error: 0.2989 - val_loss: 0.1581 - val_mean_absolute_error: 0.3463
INFO:tensorflow:Assets written to: my_model/assets
Epoch 21/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1307 - mean_absolute_error: 0.2973 - val_loss: 0.1547 - val_mean_absolute_error: 0.3423
INFO:tensorflow:Assets written to: my_model/assets
Epoch 22/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1289 - mean_absolute_error: 0.2946 - val_loss: 0.1525 - val_mean_absolute_error: 0.3402
INFO:tensorflow:Assets written to: my_model/assets
Epoch 23/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1271 - mean_absolute_error: 0.2926 - val_loss: 0.1513 - val_mean_absolute_error: 0.3390
INFO:tensorflow:Assets written to: my_model/assets
Epoch 24/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1255 - mean_absolute_error: 0.2908 - val_loss: 0.1491 - val_mean_absolute_error: 0.3373
INFO:tensorflow:Assets written to: my_model/assets
Epoch 25/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1241 - mean_absolute_error: 0.2892 - val_loss: 0.1488 - val_mean_absolute_error: 0.3367
INFO:tensorflow:Assets written to: my_model/assets
Epoch 26/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1226 - mean_absolute_error: 0.2883 - val_loss: 0.1465 - val_mean_absolute_error: 0.3347
INFO:tensorflow:Assets written to: my_model/assets
Epoch 27/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1211 - mean_absolute_error: 0.2865 - val_loss: 0.1443 - val_mean_absolute_error: 0.3330
INFO:tensorflow:Assets written to: my_model/assets
Epoch 28/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1196 - mean_absolute_error: 0.2851 - val_loss: 0.1423 - val_mean_absolute_error: 0.3312
INFO:tensorflow:Assets written to: my_model/assets
Epoch 29/50
10/10 [==============================] - 0s 5ms/step - loss: 0.1181 - mean_absolute_error: 0.2838 - val_loss: 0.1406 - val_mean_absolute_error: 0.3298
INFO:tensorflow:Assets written to: my_model/assets
Epoch 30/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1176 - mean_absolute_error: 0.2837 - val_loss: 0.1401 - val_mean_absolute_error: 0.3290
INFO:tensorflow:Assets written to: my_model/assets
Epoch 31/50
10/10 [==============================] - 0s 5ms/step - loss: 0.1157 - mean_absolute_error: 0.2813 - val_loss: 0.1370 - val_mean_absolute_error: 0.3265
INFO:tensorflow:Assets written to: my_model/assets
Epoch 32/50
10/10 [==============================] - 0s 5ms/step - loss: 0.1146 - mean_absolute_error: 0.2805 - val_loss: 0.1354 - val_mean_absolute_error: 0.3250
INFO:tensorflow:Assets written to: my_model/assets
Epoch 33/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1135 - mean_absolute_error: 0.2792 - val_loss: 0.1336 - val_mean_absolute_error: 0.3234
INFO:tensorflow:Assets written to: my_model/assets
Epoch 34/50
10/10 [==============================] - 0s 5ms/step - loss: 0.1120 - mean_absolute_error: 0.2777 - val_loss: 0.1329 - val_mean_absolute_error: 0.3225
INFO:tensorflow:Assets written to: my_model/assets
Epoch 35/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1110 - mean_absolute_error: 0.2769 - val_loss: 0.1326 - val_mean_absolute_error: 0.3218
INFO:tensorflow:Assets written to: my_model/assets
Epoch 36/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1109 - mean_absolute_error: 0.2765 - val_loss: 0.1320 - val_mean_absolute_error: 0.3209
INFO:tensorflow:Assets written to: my_model/assets
Epoch 37/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1092 - mean_absolute_error: 0.2749 - val_loss: 0.1285 - val_mean_absolute_error: 0.3181
INFO:tensorflow:Assets written to: my_model/assets
Epoch 38/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1080 - mean_absolute_error: 0.2737 - val_loss: 0.1273 - val_mean_absolute_error: 0.3169
INFO:tensorflow:Assets written to: my_model/assets
Epoch 39/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1075 - mean_absolute_error: 0.2735 - val_loss: 0.1268 - val_mean_absolute_error: 0.3161
INFO:tensorflow:Assets written to: my_model/assets
Epoch 40/50
10/10 [==============================] - 0s 5ms/step - loss: 0.1064 - mean_absolute_error: 0.2715 - val_loss: 0.1242 - val_mean_absolute_error: 0.3136
INFO:tensorflow:Assets written to: my_model/assets
Epoch 41/50
10/10 [==============================] - 0s 3ms/step - loss: 0.1060 - mean_absolute_error: 0.2717 - val_loss: 0.1223 - val_mean_absolute_error: 0.3116
INFO:tensorflow:Assets written to: my_model/assets
Epoch 42/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1044 - mean_absolute_error: 0.2692 - val_loss: 0.1221 - val_mean_absolute_error: 0.3111
INFO:tensorflow:Assets written to: my_model/assets
Epoch 43/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1036 - mean_absolute_error: 0.2685 - val_loss: 0.1216 - val_mean_absolute_error: 0.3104
INFO:tensorflow:Assets written to: my_model/assets
Epoch 44/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1032 - mean_absolute_error: 0.2679 - val_loss: 0.1206 - val_mean_absolute_error: 0.3092
INFO:tensorflow:Assets written to: my_model/assets
Epoch 45/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1021 - mean_absolute_error: 0.2667 - val_loss: 0.1190 - val_mean_absolute_error: 0.3076
INFO:tensorflow:Assets written to: my_model/assets
Epoch 46/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1014 - mean_absolute_error: 0.2660 - val_loss: 0.1177 - val_mean_absolute_error: 0.3062
INFO:tensorflow:Assets written to: my_model/assets
Epoch 47/50
10/10 [==============================] - 0s 6ms/step - loss: 0.1010 - mean_absolute_error: 0.2655 - val_loss: 0.1171 - val_mean_absolute_error: 0.3053
INFO:tensorflow:Assets written to: my_model/assets
Epoch 48/50
10/10 [==============================] - 0s 4ms/step - loss: 0.1002 - mean_absolute_error: 0.2649 - val_loss: 0.1149 - val_mean_absolute_error: 0.3030
INFO:tensorflow:Assets written to: my_model/assets
Epoch 49/50
10/10 [==============================] - 0s 4ms/step - loss: 0.0997 - mean_absolute_error: 0.2641 - val_loss: 0.1145 - val_mean_absolute_error: 0.3023
INFO:tensorflow:Assets written to: my_model/assets
Epoch 50/50
10/10 [==============================] - 0s 6ms/step - loss: 0.0987 - mean_absolute_error: 0.2633 - val_loss: 0.1130 - val_mean_absolute_error: 0.3007
INFO:tensorflow:Assets written to: my_model/assets
<tensorflow.python.keras.callbacks.History at 0x7f2e99fa4910>

Как мы видим, процесс обучения остановился раньше, поскольку модель не улучшалась. В результате есть и сохраненная модель, её можно восстановить методом tf.saved_model.load(). Если не использовать ModelCheckpoint, то модель можно сохранить методом save().

model.save("my_model")
model_restore = tf.saved_model.load("my_model")
INFO:tensorflow:Assets written to: my_model/assets

Можно посмотреть и как модель обучалась. Для этого нужно вызвать TensorBoard.

%load_ext tensorboard
%tensorboard --logdir "log"
The tensorboard extension is already loaded. To reload it, use:
  %reload_ext tensorboard
Reusing TensorBoard on port 6006 (pid 287), started 0:01:15 ago. (Use '!kill 287' to kill it.)

иллюстрация: нейронные сети

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

Оценка модели

Последнее, что нам осталось — оценить обученную модель. Для этого есть метод evaluate(). Для примера создадим тестовые данные:

X_test = np.array(np.random.random((10, 5)))
Y_test = np.array(np.random.random((10)))

res = model.evaluate(X_test, Y_test)
print("loss and mean_absolute_error", res)
1/1 [==============================] - 0s 21ms/step - loss: 0.1259 - mean_absolute_error: 0.3187
loss and mean_absolute_error [0.1258658617734909, 0.3187190890312195]

Чтобы получить предсказанные значения, используйте predict().

predictions = model.predict(X_test)
print(predictions)
[[0.2159217 ]
[0.2733177 ]
[0.43817037]
[0.7428887 ]
[0.2788944 ]
[0.41930375]
[0.39496648]
[0.30358872]
[0.28828645]
[0.3757842 ]]

Заключение

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

Хинт для программистов: если зарегистрируетесь на соревнования Huawei Cup, то бесплатно получите доступ к онлайн-школе для участников. Можно прокачаться по разным навыкам и выиграть призы в самом соревновании.

Перейти к регистрации