Шаг 212.
Глубокое обучение на Python. ... . Обучение сверточной нейронной сети с нуля на небольшом наборе данных. Конструирование сети

    На этом шаге мы рассмотрим особенности конструирования сети.

    Далее мы вновь реализуем модель с той же общей структурой, что и в первом примере: сверточная нейронная сеть будет организована как стек чередующихся слоев Conv2D (с функцией активации relu) и MaxPooling2D.

    Однако, так как мы имеем дело с большими изображениями и решаем более сложную задачу, мы сделаем сеть больше, добавив еще одну пару слоев Conv2D и MaxPooling2D. Это увеличит емкость модели и обеспечит дополнительное снижение размеров карт признаков, чтобы они не оказались слишком большими, когда достигнут слоя Flatten. Учитывая, что мы начнем с входов, имеющих размер 180 × 180 (выбор был сделан совершенно произвольно), в конце, точно перед слоем Flatten, получится карта признаков размером 7 × 7.


Глубина карт признаков в сети будет постепенно увеличиваться (с 32 до 256), а их размеры - уменьшаться (со 180 × 180 до 7 × 7). Этот шаблон вы будете видеть почти во всех сверточных нейронных сетях.

    Так как перед нами стоит задача бинарной классификации, сеть должна заканчиваться единственным признаком (слой Dense размером 1 и функцией активации sigmoid). Этот признак будет представлять вероятность принадлежности рассматриваемого изображения одному из двух классов.

    И еще одно небольшое отличие: модель будет начинаться со слоя Rescaling, преобразующего входные данные (значения которых изначально находятся в диапазоне [0, 255]) в диапазон [0, 1].


Пример 8.7. Создание небольшой сверточной нейронной сети для классификации изображений кошек и собак
import pathlib
from tensorflow import keras
from tensorflow.keras import layers

new_base_dir = pathlib.Path("cats_vs_dogs_small")

# Модель принимает изображения в формате RGB размерами 180 × 180
inputs = keras.Input(shape=(180, 180, 3))
# Привести входные данные к диапазону [0, 1] делением на 255
x = layers.Rescaling(1./255)(inputs)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)

    Посмотрим, как изменяются размеры карт признаков с каждым последующим слоем:


print(model.summary())

Model: "functional_2"

 Layer (type)                     Output Shape                  Param # 
 input_layer_2 (InputLayer)       (None, 180, 180, 3)                 0 
 rescaling_2 (Rescaling)          (None, 180, 180, 3)                 0 
 conv2d_10 (Conv2D)               (None, 178, 178, 32)              896 
 max_pooling2d_8 (MaxPooling2D)   (None, 89, 89, 32)                  0 
 conv2d_11 (Conv2D)               (None, 87, 87, 64)             18,496 
 max_pooling2d_9 (MaxPooling2D)   (None, 43, 43, 64)                  0 
 conv2d_12 (Conv2D)               (None, 41, 41, 128)            73,856 
 max_pooling2d_10 (MaxPooling2D)  (None, 20, 20, 128)                 0 
 conv2d_13 (Conv2D)               (None, 18, 18, 256)           295,168 
 max_pooling2d_11 (MaxPooling2D)  (None, 9, 9, 256)                   0 
 conv2d_14 (Conv2D)               (None, 7, 7, 256)             590,080 
 flatten_2 (Flatten)              (None, 12544)                       0 
 dense_2 (Dense)                  (None, 1)                      12,545 

 Total params: 991,041 (3.78 MB)
 Trainable params: 991,041 (3.78 MB)
 Non-trainable params: 0 (0.00 B)

    На этапе компиляции, как обычно, используем оптимизатор RMSprop. Так как модель заканчивается единственным сигмоидным выходом, используем функцию потерь binary_crossentropy (для напоминания: в таблице 1 164 шага приводится шпаргалка по использованию разных функций потерь в разных ситуациях) .


Пример 8.8. Настройка модели для обучения
model.compile(loss="binary_crossentropy",
              optimizer="rmsprop",
              metrics=["accuracy"])

    На следующем шаге мы рассмотрим предварительную обработку данных.




Предыдущий шаг Содержание Следующий шаг