Machine Learning, Нейронные сети

Задача классификации. Сможет ли нейросеть отличить собаку от кошки?

Время прочтения: 3 мин.

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

Прежде всего нам предстоит разделить этот набор на 3 категории: обучающая, тестовая и проверочная. Первая предназначена для обучения модели. Рекомендуется искусственно увеличивать этот набор, фрагментируя, переворачивая или отзеркаливая изображения.

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

data_augmentation = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal'),
  tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),
])
for image, _ in train_dataset.take(1):
  plt.figure(figsize=(10, 10))
  first_image = image[0]
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    augmented_image = data_augmentation(tf.expand_dims(first_image, 0))
    plt.imshow(augmented_image[0] / 255)
    plt.axis('off')

Следующим шагом является подготовка набора данных, для загрузки в нейронную сеть. Все изображения должны иметь одинаковый размер и находиться в одном цветовом пространстве. Как правило, используется пространство RGB. В нем каждый пиксель имеет значения, лежащие в диапазоне от 0 до 255. Для обучения нужно использовать как можно меньшие значения, поэтому значения каждого пикселя делятся на 255, чтобы в итоге они лежали в пределе от 0 до 1.

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
normalization_layer = layers.experimental.preprocessing.Rescaling(1./255)

Теперь можно переходить к созданию и обучению модели

num_classes = 2

model = Sequential([
  layers.experimental.preprocessing.Rescaling(1./255, input_shape=(img_height, img_width, 3)),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

epochs=10
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)

В процессе обучения модель оценивает точность работы после каждой эпохи. Делает это она на проверочных данных. Так как после каждой эпохи этот набор не меняется, нейросеть запоминает их и к последней эпохе оценка становится необъективна. Последующая проверка на тестовых данных показывает реальную точность работы обученной модели. Обычно она отличается на 5-7%. Как видно из графика ниже наш случай не исключение. При этом точность работы все равно довольно высокая.

Теперь необходимо сохранить обученную модель.

history.save('Cats_vs_Dogs')

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

image_batch, label_batch = test_dataset.as_numpy_iterator().next()
predictions = model.predict_on_batch(image_batch).flatten()
predictions = tf.nn.sigmoid(predictions)
predictions = tf.where(predictions < 0.5, 0, 1)
print('Predictions:\n', predictions.numpy())
print('Labels:\n', label_batch)


plt.figure(figsize=(10, 10))
for i in range(9):
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(image_batch[i].astype("uint8"))
  plt.title(class_names[predictions[i]])
  plt.axis("off")

Как видно из фото выше, программа работает довольно точно. Всего лишь в одном изображении она ошиблась и нашла собаку вместо кошки. Но стоит признать, что фотография и правда довольно тяжелая.

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

Советуем почитать