В этом посте мы продолжим руководство по базовой классификации на TensorFlow из прошлого поста.
Предобработка данных
Данные должны быть предобработаны перед тренировкой сети. Если вы посмотрите на первое изображение в тренировочном наборе, вы увидите, что значения пикселей попадают в диапазон от 0 до 255:
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
Мы масштабируем эти значения в диапазон от 0 до 1 до того как отдать эти данные модели нейронной сети. Для этого конвертируем тип данных компонентов изображения из целочисленного (integer) в нецельночисловое (float) и разделим на 255.
Важно, что тренировочный и тестовый набор предобрабатываются одинаком образом.
train_images = train_images / 255.0
test_images = test_images / 255.0
Отобразим первые 25 изображений из тренировочного набора и покажем имя класса под каждым изображением. Проверим что данные в корректном формате и готовы для построения и тренировки сети.
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
Построение модели
Создание нейронной сети требует конфигурирования слоев модели, а затем компилирования модели.
Установка слоев
Базовым стройтельным блоком нейронной сети является слой. Слои извлекают представления из данных переданных им. Эти представления более значимы для рассматриваемой проблемы.
Большая часть сетей глубокого обучения состоит из связанных вместе простых слоев. Большинство слоев, таких как tf.keras.layers.Dense, имеют параметры, которые изучены (созданы) в ходе тренировки.
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation=tf.nn.relu),
keras.layers.Dense(10, activation=tf.nn.softmax)
])
Первый слой в этой сети, tf.keras.layers.Flatten, преобразует формат изображений из 2х-мерного массива (28 на 28 пикселей) в одномерный массив 28 * 28 = 784 пикселей. Рассматривайте этот слой как разложенные из стека и построенные в линию слои пикселей в изображении. Этот слой не имеет параметров для обучения, это только преобразование данных.
После того как пиксели сплюснуты сеть состоит из последовательности двух tf.keras.layers.Dense слоев. Это плотносвязанные или полностью связанные нейронные слои. Первый Dense слой имеет 128 узлов (или нейронов). Второй (последний) слой - 10-узловой софтмакс слой - он возвращает массив десяти счетов вероятностей, которые в сумме равны 1. Каждый узел содержит счет, который показывает вероятность того, что текущее изображение принадлежит к одному из 10 классов.
Компилирование модели
Перед тем как модель готова к тренировке она требуется еще в нескольких настройках. следующие настройки добавляются на этапе компиляции модели:
- Функция потери - она измеряет насколько аккуратна модель в ходе тренировки. Мы хотим минимизировать эту функцию, чтобы управлять моделью в правильном направлении.
- Оптимизатор - управляет тем как модель обновляется, основываясь на данных, которых видит, и функции потери.
- Метрики - используются для наблюдения за тренировочным и тестовым шагами. Следующий пример использует аккуратность, порцию изображений, которые классифицированы правильно.
model.compile(optimizer=tf.train.AdamOptimizer(), loss='sparse_categorical_crossentropy', metrics=['accuracy'])
Тренировка модели
Тренировка модели нейронной сети требует следующих шагов:
- Передать модели тренировочные данные - в этом примере, train_images и train_labels массивы.
- Модель обучается связывать изображения с метками.
- Мы предалагем модели сделать прогнозы на тестовом наборе - в этом примере, test_images массив. Мы проверяем, что прогнозы соотвествуют меткам из test_labels массива.
Чтобы начать тренировку вызовем model.fit метод - модель "приспосабливается" ("fit") к тренировочным данным:
model.fit(train_images, train_labels, epochs=5)
Epoch 1/5
60000/60000 [==============================] - 2s 36us/step - loss: 0.4989 - acc: 0.8249
Epoch 2/5
60000/60000 [==============================] - 2s 34us/step - loss: 0.3787 - acc: 0.8634
Epoch 3/5
60000/60000 [==============================] - 2s 34us/step - loss: 0.3378 - acc: 0.8763
Epoch 4/5
60000/60000 [==============================] - 2s 35us/step - loss: 0.3141 - acc: 0.8859
Epoch 5/5
60000/60000 [==============================] - 2s 35us/step - loss: 0.2938 - acc: 0.8915
В то время как модель тренируется потеря и аккуратность отображаются. Эта модель достигла аккуратности около 0.88 (или 88%) на тренировочных данных.
Оценка аккуратности
Далее сравним как модель применяется к тестовым данным:
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('Test accuracy:', test_acc)
10000/10000 [==============================] - 0s 20us/step
Test accuracy: 0.8741
Оказалось, что аккуратность на тестовом наборе немного меньше, чем на тренировочном наборе. Этот промежуток между тренировочной аккуратностью и тестовой аккуратностью - пример переобучения. Переобучение - это когда модель машинного обучения выполняет работу хуже на новых данных, чем на тренировочных.
Оценка аккуратности
С тренированной моделью мы можем делать прогнозы по изображениям:
predictions = model.predict(test_images)
Здесь модель выполнила прогнозирование меток для каждого изображения в тестовом наборе. Взглянем на первый прогноз:
predictions[0]
array([1.2189614e-05, 9.8493892e-08, 2.6474936e-06, 4.6750273e-08, 2.2893637e-07, 4.9046555e-04, 4.9265759e-06, 9.2500690e-03, 2.6400221e-05, 9.9021286e-01], dtype=float32)
Прогноз - это массив из 10 чисел. Они описывают "уверенность" модели в том, что изображение соответствует каждому из 10 разных видов одежды. Мы можем увидеть которая из меток имеет наибольшее значение уверенности:
np.argmax(predictions[0])
9
Таким образом модель более всего уверенна, что это изображение - ботильон, или class_names[9] (девятый элемент массива class_names). И мы можем проверить тестовую метку, чтобы увидеть правильно ли это:
test_labels[0]
9
Мы можем создать граф, чтобы увидеть полный набор 10 каналов.
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array[i], true_label[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
Теперь взглянем на нулевое изображение, прогнозы, и массив прогнозов.
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions, test_labels)
Создадим график для нескольких изображений. Правильно спрогнозированные метки - синие, а неправильно спрогнозированные - красные. Число отображает процент (из 100) для прогнозируемой метки. Следует отметить, что модель может ошибаться даже при высокой уверенности.
# Сделаем график первых X тестовых изображений, их прогнозируемые метки и действительная метка
# Окрасим правильные прогнозы синим, а неправильные - красным
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions, test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions, test_labels)
В итоге, используем тренированную модель, чтобы сделать прогноз для одного изображения.
# Возьмем изображение из тестового набора
img = test_images[0]
print(img.shape)
(28, 28)
tf.keras модели оптимизированы, чтобы делать прогнозы на пакете, или коллекции, или всех примерах разом. Поэтому даже хотя мы используем одно изображение нам необходимо добавить его в лист:
# Добавим изображение в пакет, где только один член
img = (np.expand_dims(img,0))
print(img.shape)
(1, 28, 28)
Теперь сделаем прогноз:
predictions_single = model.predict(img)
print(predictions_single)
[[1.2189591e-05 9.8493892e-08 2.6474886e-06 4.6750095e-08 2.2893614e-07 4.9046462e-04 4.9265759e-06 9.2500662e-03 2.6400170e-05 9.9021286e-01]]
plot_value_array(0, predictions_single, test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
model.predict возвращает лист из листов, по одному для каждого изображения в пакете данных. Возьмем прогнозы для нашего (единственного) изображения в пакете:
np.argmax(predictions_single[0])
9
И, как и раньше, модель прогнозирует метку 9.
На этом наше руководство о базовой классификации с TensorFlow завершается. О других методах использования TensorFlow читайте в последующих постах.