Привет, Антон! Давай знакомиться! Меня зовут Дмитрий Махортов, и я буду проверять твой проект. Сразу предлагаю общение на «ты» 🙂, но если тебе это не комфортно, то дай знать, и мы перейдем на «вы».
Моя основная цель — не указать на совершенные тобою ошибки, а поделиться своим опытом и помочь тебе погрузиться в увлекательный мир работы с данными и вырасти в крепкого профи. Это отдаленная цель. А ближайшая - сделать твою работу еще лучше )).
Все ключевые этапы в работе выполнены, и я вижу что с проектом ты справшяешься. Есть моменты, которые нужно доработать, но я уверен, у тебя все получится.
Расскажу как обычно проходит проверка:
Бывают моменты, которые требуют пристального внимания. Комментарии по ним выделены красным цветом и обозначены значком 🛑. После их доработки проект будет принят. 🙂
Зеленым цветом и значком ✅ отмечены удачные и элегантные решения, на которые можно опираться в будущих проектах. Или советы «со звездочкой», которые помогут тебе в будущем.
Жёлтым цветом и значком ⚠️ выделено то, что в следующий раз можно сделать по-другому. Ты можешь учесть эти комментарии при выполнении будущих заданий или доработать проект сейчас (однако это не обязательно).
Давай работать над проектом в диалоге: если ты что-то меняешь в проекте по моим рекомендациям — пиши об этом. Выбери для своих комментариев какой-то заметный цвет, так мне будет легче отследить изменения. Пожалуйста, не перемещай, не изменяй и не удаляй мои комментарии. Всё это поможет выполнить повторную проверку твоего проекта оперативнее.
Можешь использовать этот комментарий. Просто удали этот текст и вместо него напиши свой 🙂
Определение возраста покупателей¶
Исследовательский анализ данных¶
Исследовательский анализ данных¶
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from PIL import Image
dp = pd.read_csv('/datasets/faces/labels.csv')
train_datagen = ImageDataGenerator(rescale=1./255)
train_gen_flow = train_datagen.flow_from_dataframe(
dataframe=dp,
directory='/datasets/faces/final_files/',
x_col='file_name',
y_col='real_age',
target_size=(150, 150),
batch_size=32,
class_mode='raw',
seed=12345)
Found 7591 validated image filenames.
dp.shape
(7591, 2)
dp.hist(bins=100,figsize =(12,4), grid =True)
plt.xlabel("Age")
plt.ylabel("Count");
<AxesSubplot:xlabel='real_age'>
или
Text(0, 0.5, 'Count')
Это можно сделать достаточно просто, если добавить точку с запятой после последней команды в ячейке. sns.boxplot(labels["real_age"]);
Исправил, теперь вывод чистый
print('Размеры 3-х случайных картинок')
print(Image.open('/datasets/faces/final_files/000001.jpg').size)
print(Image.open('/datasets/faces/final_files/000000.jpg').size)
print(Image.open('/datasets/faces/final_files/000101.jpg').size)
Размеры 3-х случайных картинок (784, 784) (114, 114) (159, 159)
features, target = next(train_gen_flow)
fig = plt.figure(figsize=(12,12))
for i in range(15):
fig.add_subplot(5, 5, i+1)
plt.imshow(features[i])
plt.xticks([])
plt.yticks([])
plt.tight_layout()
Промежуточный вывод:
1) Выборка у нас небольшая 7591 фото. Возможны проблемы с качеством обучения
2) Основные данные по возрасту это люди от 18-55
3) На фото присутствуют посторонние предметы, которые перекрывают часть лица. Что в свою очередь опять может понизить качество обучения модели.
4) У нас много фото возраст людей на них 0-3, а на возрасте 10 лет провал. Это странно и возможно придется
пересмотреть выборку в сторону ее уменьшения или дополнения.
5) Размеры картинок различны, скорее всего потребуется подбор параметров(размера) при подготовки данных для сверточной
неросети.
- Размер датасета
- Распределение целевого признака (возраста)
- Особенности изображений, входящих в датасет
А вот перебор размера картинки не нужен, и даже вреден, т.к. нейронная сеть ResNet обучалась на изображениях 224х224
Обучение модели¶
import pandas as pd
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.applications.resnet import ResNet50
from tensorflow.keras.layers import GlobalAveragePooling2D, Dense, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing.image import ImageDataGenerator
def load_train(path):
dp = pd.read_csv(path + 'labels.csv')
datagen = ImageDataGenerator(validation_split=0.25, horizontal_flip=True, rescale=1./255)
train_gen_flow = datagen.flow_from_dataframe(
dataframe=dp,
directory=path + 'final_files/',
x_col='file_name',
y_col='real_age',
target_size=(150, 150),
batch_size=16,
class_mode='raw',
subset='training',
seed=12345)
return train_gen_flow
def load_test(path):
dp = pd.read_csv(path + 'labels.csv')
datagen = ImageDataGenerator(validation_split=0.25, rescale=1./255)
test_gen_flow = datagen.flow_from_dataframe(
dataframe=dp,
directory=path + 'final_files/',
x_col='file_name',
y_col='real_age',
target_size=(150, 150),
batch_size=16,
class_mode='raw',
subset='validation',
seed=12345)
return test_gen_flow
def create_model(input_shape):
backbone = ResNet50(input_shape=input_shape,
weights='imagenet',
include_top=False)
model = Sequential()
model.add(backbone)
model.add(GlobalAveragePooling2D())
model.add(Flatten())
model.add(Dense(1, activation='relu'))
optimizer = Adam(lr=0.0001)
model.compile(optimizer=optimizer, loss='mean_squared_error',
metrics=['mae'])
return model
def train_model(model, train_data, test_data, batch_size=None, epochs=10,
steps_per_epoch=None, validation_steps=None):
if steps_per_epoch is None:
steps_per_epoch = len(train_data)
if validation_steps is None:
validation_steps = len(test_data)
model.fit(train_data,
validation_data=test_data,
batch_size=batch_size,
epochs=epochs,
steps_per_epoch=steps_per_epoch,
validation_steps=validation_steps,
verbose=2)
return model
Молодец, что используешь агументацию для обучающего набора.
Правильный выбор лосс-функции, также хорошо подобран шаг обучения.
Спасибо за замечание. Это уже не первая модель которую я обучил в этом проекте. Но интерес взял верх и я попробовал так скажем подпортить параметры и увидеть насколько система может быть гибкой.(какие потери я получу).
Алгоритм преобразовании
Результат вывода модели.¶
Train for 356 steps, validate for 119 steps
Epoch 1/10 356/356 - 48s - loss: 213.4883 - mae: 10.6899 - val_loss: 300.9090 - val_mae: 12.8964
Epoch 2/10 356/356 - 39s - loss: 89.9290 - mae: 7.1792 - val_loss: 186.7818 - val_mae: 10.3903
Epoch 3/10 356/356 - 39s - loss: 60.4960 - mae: 5.9512 - val_loss: 84.7497 - val_mae: 6.9163
Epoch 4/10 356/356 - 39s - loss: 41.5414 - mae: 4.9469 - val_loss: 87.8140 - val_mae: 6.9623
Epoch 5/10 356/356 - 38s - loss: 31.2862 - mae: 4.2713 - val_loss: 90.4213 - val_mae: 7.2782
Epoch 6/10 356/356 - 38s - loss: 23.9235 - mae: 3.7421 - val_loss: 75.2556 - val_mae: 6.6893
Epoch 7/10 356/356 - 39s - loss: 18.4742 - mae: 3.2763 - val_loss: 92.3198 - val_mae: 7.1538
Epoch 8/10 356/356 - 43s - loss: 14.9359 - mae: 2.9527 - val_loss: 79.9512 - val_mae: 6.6451
Epoch 9/10 356/356 - 43s - loss: 16.6256 - mae: 3.0558 - val_loss: 78.2054 - val_mae: 6.5181
Epoch 10/10 356/356 - 43s - loss: 14.9587 - mae: 2.9326 - val_loss: 74.2041 - val_mae: 6.4021 WARNING:tensorflow:sample_weight modes were coerced from
119/119 - 11s - loss: 74.2041 - mae: 6.4021 Test MAE: 6.4021
Анализ обученной модели¶
Вывод: Наша модель успешно обучилась. Значение метрики MAE остановилось на значении 6.4. Это хуже эталонных 5.4 о готорых говориться в статье, но условия задачи мы выполнили с отличием т.к. наша метрика менее 7. Параметры нашей модели: 1) Используем готовую сверточную сеть ResNet50 при этом мы ее ограничиваем 2)Далее используем GlobalAveragePooling2D() происходит сопротивление переобучению сверточной нейронной сети. 3) Следом идет слой Flatten() для более коректной передачи на нейрон массива данных ( из 2D в 1D) 4) Итоговый слой это нейрон c функцией активации ReLu, что позволяет избежать затухания сигмоиды Особое замечание: качество модели можно улучшить путем подбора у ImageDataGenerator размера картинки, к которому приводятся все изображения из датасета.
Чек-лист¶
- Jupyter Notebook открыт
- Весь код выполняется без ошибок
- Ячейки с кодом расположены в порядке исполнения
- Исследовательский анализ данных выполнен
- Результаты исследовательского анализа данных перенесены в финальную тетрадь
- MAE модели не больше 8
- Код обучения модели скопирован в финальную тетрадь
- Результат вывода модели на экран перенесён в финальную тетрадь
- По итогам обучения модели сделаны выводы
Давай подведем итоги. Ты провел содержательный EDA, а также использовал предобученную модель и c помощью finetuning и transfer-learning обучил нейронку определять возраст покупателей. Требуемая точность получена.
Что нужно сделать обязательно: Пожалуйста доработай оформление гистограммы
Жду твой проект на финальное ревью :)
- "Дип Лернинг на пальцах" (https://www.youtube.com/playlist?list=PL5FkQ0AF9O_o2Eb5Qn8pwCDg7TniyV1Wb).
- Отличный бесплатный курс от Школы глубокого обучения МФТИ (https://stepik.org/org/dlschool), старт курса каждые пол года. Два семестра, один по основам и компьютерному зрению, второй по обработке естественного языка.
- "Нейронные сети и компьютерное зрение" от Samsung Research Russia (https://stepik.org/course/50352/syllabus). Есть также продолжение по NLP.
Проект принят. Поздравляю и желаю дальнейших успехов!