Модель нейронной сети

Модель нейронной сети

Категория статьи: Нейронные сети

Проект: 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
_________________________________________________________________