Категория статьи: Нейронные сети
Проект: Shazam своими руками
Описание структуры модели нейронной сети
Всем привет!
В этой статье я подготовлю несложную структуру модели нейронной сети для распознавания музыкальных композиций.
Первое, что нужно сделать - это создать директорию для хранения модели. Я создаю директорию сразу на Google диске.
# Директория для сохранения и загрузки модели нейронной сети
model_dir = 'drive/My Drive/EvgenyKondratev.ru/Shazam/model'
# Создаем директорию если она не существует
create_dir_if_not_exists(model_dir, True)
Если диск еще не смонтирован это можно сделать так:
from google.colab import drive
drive.mount('/content/drive', force_remount=True)
Добавим вспомогательную функцию, которая будет возвращать количество файлов, подготовленных для обучения и количество классов на которых была обучена модель (если модель уже обучалась ранее) Эта функция необходима для формирования последнего слоя модели
Немножко о структуре имени файла модели. Имя файла выглядит так: 00000000XXXX.hdf5, где XXXX - количество классов на которых обучалась модель. Например 000000000240.hdf5, это значит, что модель обучалась распознавать 240 композиций
def get_file_cl_and_model_cl(train_dir, model_directory, echo=True):
# Возьмем все файлы (в нашем случае это каталоги) из директории train
train_files = sorted(os.listdir(train_dir))
# Фильтруем файлы от системных
train_files = list(filter(lambda x: x[0] != '.', train_files))
class_count = 0
if len(train_files) > 0:
# Номер последней директории (в имени директории) + 1 будет соответствовать количеству классов для обучения модели
class_count = int(train_files[-1]) + 1
if echo:
print(f"class_count = {class_count}")
# Возьмем все файлы моделей из директории для сохранения и загрузки модели
model_files = sorted(os.listdir(model_directory))
# Фильтруем файлы от системных
model_files = list(filter(lambda x: x[0] != '.', model_files))
model_class_count = 0
if len(model_files) > 0:
# Получаем количество классов на которых обучалась модель
model_class_count = int(model_files[-1].split('.')[0])
if echo:
print(f"model_class_count = {model_class_count}")
return (class_count, model_class_count)
Функция создания модели полносвязной нейронной сети
import tensorflow as tf
from tensorflow.keras.models import Model, load_model
from tensorflow.keras.layers import Input, Flatten, Dense, BatchNormalization, Activation
from tensorflow.keras.optimizers import Adam
def create_dense_model(input_shape, train_dir, model_directory):
# Получаем количество классов для обучения и количество классов на которых обучалась последняя модель
class_count, model_class_count = get_file_cl_and_model_cl(train_dir, model_directory)
model_files = sorted(os.listdir(model_directory))
# Фильтруем файлы от системных
model_files = list(filter(lambda x: x[0] != '.', model_files))
model = None
if class_count == 0:
return (model, class_count)
# Если модель еще ни разу не обучалась или количество классов для обучения
# отличаются от количества классов на которых обучалась модель
if model_class_count == 0 or class_count != model_class_count:
# Создаем слои модели
input_img = Input(shape=input_shape)
x = input_img
x = Flatten(name='shazam_flatten')(x)
x = BatchNormalization(name="shazam_bn_1")(x)
x = Dense(lhp.n_mels * 2, name='shazam_dense_1')(x)
x = BatchNormalization(name="shazam_bn_2")(x)
x = Activation('relu')(x)
x = Dense(lhp.n_mels, name='shazam_dense_2')(x)
x = BatchNormalization(name="shazam_bn_3")(x)
x = Activation('relu')(x)
# Если модель уже обучалась и количество классов для нового обучения больше чем в модели
if model_class_count != 0 and class_count > model_class_count:
last_model_filename = os.path.join(model_directory, model_files[-1])
if os.path.exists(last_model_filename):
last_layer = x
inner_model = Model(input_img, last_layer)
# Загружаем веса модели по имени слоев
inner_model.load_weights(last_model_filename, by_name=True)
print(f"Загружена часть весов модели из файла '{last_model_filename}'!")
# Создаем последний слой с количеством нейронов равным количеству классов для обучения
x = Dense(class_count, name='shazam_dense_3', activation='softmax')(x)
# Создаем модель
model = Model(input_img, x)
# Компилируем модель. Используем оптимизатор Adam
# Функция потерь Многоклассовая кросэнтропия (categorical_crossentropy)
# Будем наблюдать за метрикой accuracy (Точность)
model.compile(optimizer=Adam(learning_rate=0.01),
loss="categorical_crossentropy",
metrics=['accuracy'])
else:
# В противном случае грузим всю модель
last_model_filename = os.path.join(model_directory, model_files[-1])
model = load_model(last_model_filename)
print(f"Загружены веса для всей модели из файла '{last_model_filename}'!")
# Выводим информацию о модели
model.summary()
# Возвращаем модель и количество классов для обучения
return (model, class_count)
Создаем модель
input_shape = (lhp.n_mels, lhp.n_timeframe, 1)
model, cl_count = create_dense_model(input_shape, train_dir, model_dir)
Summary модели выглядит так
class_count = 40
model_class_count = 0
Model: "functional_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 512, 80, 1)] 0
_________________________________________________________________
shazam_flatten (Flatten) (None, 40960) 0
_________________________________________________________________
shazam_bn_1 (BatchNormalizat (None, 40960) 163840
_________________________________________________________________
shazam_dense_1 (Dense) (None, 1024) 41944064
_________________________________________________________________
shazam_bn_2 (BatchNormalizat (None, 1024) 4096
_________________________________________________________________
activation (Activation) (None, 1024) 0
_________________________________________________________________
shazam_dense_2 (Dense) (None, 512) 524800
_________________________________________________________________
shazam_bn_3 (BatchNormalizat (None, 512) 2048
_________________________________________________________________
activation_1 (Activation) (None, 512) 0
_________________________________________________________________
shazam_dense_3 (Dense) (None, 40) 20520
=================================================================
Total params: 42,659,368
Trainable params: 42,574,376
Non-trainable params: 84,992
_________________________________________________________________