Распознавание позы — это задачи в области Компьютерного зрения (CV) – определение позы человека на изображении. Причина, по которой так много энтузиастов машинного обучения привлекает оценка позы, заключается в ее широком разнообразии приложений и полезности.
Обычно такое распознавание выполняется путем нахождения ключевых точек – суставов, изгибов тела, контрастных переходов цвета (например, от волос на голове к коже лица). Основываясь на этих ключевых точках, мы можем сравнивать различные позы и делать выводы. Это активно используется в области дополненной реальности, анимации, игр и робототехники.
Рассмотрим пример. Для начала импортируем необходимые библиотеки:
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import os
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
import keras
from PIL import Image
from keras.preprocessing import image
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten,Dense,Dropout,BatchNormalization
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import cv2
from keras.layers import Input, Lambda, Dense, Flatten
from tensorflow.keras.applications import VGG16, InceptionResNetV2
from keras import regularizers
from tensorflow.keras.optimizers import Adam,RMSprop,SGD,Adamax
Разделим Датасет (Dataset), который уже разделен на Тренировочные (Train Data) и Тестовые данные (Test Data):
train_dir = '../input/yoga-poses-dataset/DATASET/TRAIN' #directory with training images
test_dir = '../input/yoga-poses-dataset/DATASET/TEST' #directory with testing images
Речь пойдет о таких изображениях:
Встроенная функция Keras ImageDataGenerator()
собирает картинки в Пакеты (Batch) для пошагового обучения. width_shift_range
определяет, какого разрешения будет пакет, horizontal_flip
– поворачивает картинки, если необходимо. validation_split
резервирует часть изображений для дальнейшей проверки эффективности модели:
train_datagen = ImageDataGenerator(width_shift_range= 0.1,
horizontal_flip = True,
rescale = 1./255,
validation_split = 0.2)
test_datagen = ImageDataGenerator(rescale = 1./255,
validation_split = 0.2)
flow_from_directory
применяет настройки бэтчинга выше и дополняет их. Здесь мы видим цветовую схему RGB, размер пакета batch_size
, тип набора subset
– тренировочный или валидационный:
train_generator = train_datagen.flow_from_directory(directory = train_dir,
target_size = (224,224),
color_mode = 'rgb',
class_mode = 'categorical',
batch_size = 16,
subset = 'training')
validation_generator = test_datagen.flow_from_directory(directory = test_dir,
target_size = (224,224),
color_mode = 'rgb',
class_mode = 'categorical',
subset = 'validation')
Система распознала, что у нас пять классов и почти тысяча изображений:
Found 866 images belonging to 5 classes.
Found 92 images belonging to 5 classes.
Инициируем экземпляр Последовательной модели (Sequential Model), что позволяет нам задавать настройки каждого слоя от начала до конца. Здесь мы задаем настройки Пулинга (Pooling), то есть как картинки будут "сжиматься", Функцию активации (Activation Function). Последняя помогает Модели (Model) освоить сложные закономерности в данных. Сверточная нейронная сеть (CNN), вызываемая методом Conv2D(),
специализируется на изображениях среди прочих видов данных и способна распознавать предметы на них):
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(64, (3,3), activation='relu',padding = 'Same', input_shape=(224, 224, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Dropout(0.25),
#tf.keras.layers.Conv2D(128, (3,3), activation='relu',padding = 'Same'),
#tf.keras.layers.MaxPooling2D(2,2),
#tf.keras.layers.Dropout(0.25),
#tf.keras.layers.Conv2D(128, (3,3), activation='relu',padding = 'Same'),
#tf.keras.layers.MaxPooling2D(2,2),
#tf.keras.layers.Dropout(0.25),
tf.keras.layers.Conv2D(128, (3,3), activation='relu',padding = 'Same'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Dropout(0.25),
tf.keras.layers.Conv2D(256, (3,3), activation='relu',padding = 'Same'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Dropout(0.25),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(5, activation='softmax')
])
С самого начала модель, скорее всего, свою наивысшую результативность не покажет, так что ей понадобится Оптимизатор (Optimizer) – алгоритм, который помогает повысить производительность. Для модели, работающей с изображениями, подойдет Кросс-энтропия (Cross Entropy). В этом случае рассчитывается средняя ошибка между реальным и предсказанным значениями. Обучение пройдет в 50 эпох:
optimizer = Adam(lr=0.001)
model.compile(loss='categorical_crossentropy',
optimizer = optimizer,
metrics=['accuracy'])
epochs = 50
batch_size = 16
Посмотрим сводные характеристики модели:
model.summary()
Не будем особо вдаваться в подробности во имя удобоваримости материала, но упомянем, что у нашей модели несколько слоев, которые распознают объекты на изображении, причем между ними встречаются:
MaxPooling2D
, сокращающие размеры картинокDropout
Layer) – некая маска, что сводит на нет вклад некоторых нейронов в следующий слой и оставляет без изменений все остальные во избежание Переобучения (Overfitting)Flatten
, которые схлапывают многомерные выходные данные в одномерные. Именно в таком формате следующий слой и сможет принять информацию и распознавать позы.Dense
: рабочая лошадка в этом сэндвиче, принимает предобработанные предшественниками данные и распознает запрошенное:Загрузим сжатые изображения директивой ImageFile.LOAD_TRUNCATED_IMAGES
, выставленной в значение True:
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
Парой ячеек выше мы задали настройки модели, теперь пришло время запустить ее обучение:
history = model.fit(train_generator, epochs = epochs,validation_data = validation_generator)
Показатели сейчас начнут стремительно меняться:
Epoch 1/50
55/55 [==============================] - 52s 833ms/step - loss: 6.2334 - accuracy: 0.2734 - val_loss: 1.6744 - val_accuracy: 0.2500
...
Epoch 50/50
55/55 [==============================] - 34s 610ms/step - loss: 0.0571 - accuracy: 0.9901 - val_loss: 0.5342 - val_accuracy: 0.8696
Всего за 50 эпох, то есть подходов, модель увеличила свою Точность измерений (Accuracy) с 25% до 86%.
Заглянув в ноутбук, вы заметите, что точность 86% – не максимальная за всю историю обучения, бывало и 91%! Что же произошло? Давайте проиллюстрируем хронологию изменения Accuracy:
fig, ax = plt.subplots(1,2)
train_acc = history.history['accuracy']
train_loss = history.history['loss']
fig.set_size_inches(12,4)
ax[0].plot(history.history['accuracy'])
ax[0].plot(history.history['val_accuracy'])
ax[0].set_title('Training Accuracy vs Validation Accuracy')
ax[0].set_ylabel('Accuracy')
ax[0].set_xlabel('Epoch')
ax[0].legend(['Train', 'Validation'], loc='upper left')
ax[1].plot(history.history['loss'])
ax[1].plot(history.history['val_loss'])
ax[1].set_title('Training Loss vs Validation Loss')
ax[1].set_ylabel('Loss')
ax[1].set_xlabel('Epoch')
ax[1].legend(['Train', 'Validation'], loc='upper left')
plt.show()
Валидационные потери обозначаются на графике справа оранжевым цветом. Если добавить еще десяток-другой эпох с новыми данными, возможно, точность "устаканится", то есть ее разброс станет предсказуемым. Тогда модель достигнет Сходимости (Convergence). Сейчас об этом судить рановато.
Проведем Оценку (Evaluation) модели, то есть рассчитаем ключевые показатели ее эффективности:
train_loss, train_acc = model.evaluate(train_generator)
test_loss, test_acc = model.evaluate(validation_generator)
print("final train accuracy = {:.2f} , validation accuracy = {:.2f}".format(train_acc*100, test_acc*100))
В данном случае, мы рассчитали точность accuracy
и потери loss
:
55/55 [==============================] - 29s 520ms/step - loss: 0.0158 - accuracy: 0.9965
3/3 [==============================] - 4s 1s/step - loss: 0.5342 - accuracy: 0.8696
final train accuracy = 99.65 , validation accuracy = 86.96
В дальнейшем мы сможем подгружать новые изображения и запрашивать позу, как описано в этой статье с использованием тех же данных.
Ноутбук, не требующий дополнительной настройки на момент написания статьи, можно скачать здесь.
Автор оригинальной статьи: Ayush Gupta, Aayush Mishra
© Лена Капаца. Все права защищены.