Вдохновленный yoona.ai, стартапом, который изменит подход модных компаний к дизайну в будущем (Часть 1 и Часть 2). из-за них я начал глубже погружаться в машинное обучение, глубокое обучение,… искусственный интеллект, и я все еще не знаю, какое модное слово.

Я инженер, и это означает, что я должен запачкать руки. В конце моего проекта я хочу иметь возможность тренировать свой собственный GAN и генерировать вещи, которых (пока) не существует. GAN нужно много входных данных, если вы хотите добиться потрясающих результатов. То есть вы либо находите базу данных на таких платформах, как kaggle.com, либо, как в моем случае, создаете свою?

Вы, наверное, спросите себя, почему? Во-первых, я хочу узнать о трудностях, с которыми вы сталкиваетесь при попытке создать собственный набор данных, а во-вторых, в большинстве примеров, найденных в Интернете, все они используют одни и те же (MNIST, CIFAR10, Fashion-MNIST) и часто оттенки серого 28x28.

Одна из основных проблем, которую я нашел в Интернете, заключается в том, что либо статьи в значительной степени сосредоточены на математике для функций потерь, основах слоев, … все, что вам нужно, если вы хотите построить свою собственную сеть (которую вы могли бы получить чувство, что у вас тоже есть, но я очень сомневаюсь в этом) или они супер короткие, с использованием 3 слоев, где вы можете почувствовать, что этого достаточно. Они восхитительны для начала, но не тогда, когда вы хотите испачкать руки. На пути к науке о данных — отличное место с отличной статьей. https://towardsdatascience.com/

Еще одна проблема, о которой я наткнулся, - это знать, что искать. В зависимости от вашего варианта использования это может быть классификация изображений, обнаружение объектов, семантическая сегментация и т. д. Сколько объектов вы ожидаете? Будут ли они автономными? Вы собираетесь иметь людей, но хотите обнаружить их одежду? Светофор? … так много вариантов использования.

Мой вариант использования прост. Я собираюсь сделать несколько тысяч фотографий, которые хочу использовать для своей GAN. Одним из источников может быть магазин электронной коммерции. Моя проблема? Я хочу фотографии без людей.

Мой первый подход заключался в обнаружении лиц с помощью MTCNN (Github)/How-to (Ссылка). Это сработало довольно хорошо, чтобы отфильтровать мой набор данных по крайней мере на 50%, но проблема в том, что для каждого продукта у вас обычно есть около 5–6 изображений. Мне нужна именно одна передняя фотография. Вы поймете, что алгоритм не работает, если это спина человека, или если это крупный план продукта, изображение материала и т. д.

К сожалению, не мне пришла в голову идея поиска обнаружения аномалий, о чем будет отдельная статья. Поэтому мне пришлось использовать свои знания, которые я накопил за последние недели о CNN. Поэтому вместо создания многоклассового алгоритма классификации изображений я собираюсь привести его к двоичной версии (0 или 1).

Как написано в начале, для него не обязательно придумывать собственную сеть. Задач там каждый год хватает, искать лучшие решения и зачем изобретать что-то новое, если кто-то это уже сделал? Вам также не нужно обучать всю сеть с нуля, потому что есть предварительно обученные сети, которые уже научились делать определенные вещи. Ищите трансферное обучение и тонкую настройку. У Кераса есть несколько хороших статей, как это сделать. ("Связь")

Вы также можете найти хороший список сетевых реализаций, предлагаемых Keras (Link), с информацией о размере, количестве параметров, времени на шаг вывода и, что наиболее важно, точности Top-1 и 5.

Вы можете найти много статей для VGG и ResNet (Link), но после их тестирования я наткнулся на EfficientNet (Link), который дает хорошие результаты с гораздо меньшими параметрами, чем другие.

Для моего варианта использования этого достаточно, чтобы не начинать с нуля. Мы разделим наши данные на два каталога, воспользуемся предварительно обученной EfficientNet (обученной с помощью ImageNet).

Самые важные вещи, которые я узнал. При использовании предварительно обученной сети, в которой вы собираетесь изменить голову/классификатор (например, используя мультиклассовый классификатор для 1000 классов и применяя его для двоичного кода с 2 классами), ваш новый классификатор необученный. Использование необученного классификатора поверх предварительно обученной сети может привести к потере всего того, что было обучено. (трансферное обучение)

Во-вторых, то, что вы не найдете в большинстве статей о трансферном обучении и тонкой настройке, это тот факт, что вы должны держать слой пакетной нормализации в режиме вывода (означает обучаемый = ложный). Вы можете прочитать об этом здесь (Keras Docs)

После нашего первого обучения мы собираемся настроить нашу сеть. Это можно сделать, разморозив другие слои (по-прежнему оставляя слои BatchNormalization-Layers необучаемыми) и снова обучив их.

Создайте свою собственную модель EfficientNet

def build(input_shape, data_augmentation, trainable=False, dropout=0.2):
    inputs = keras.Input(shape=input_shape)
    x = data_augmentation(inputs)
    x = preprocess_input(x)

    baseModel = EfficientNetB3(weights="imagenet", include_top=False, input_tensor=x)
    baseModel.trainable = trainable

    headModel = baseModel.output
    headModel = layers.GlobalAveragePooling2D()(headModel)
    headModel = layers.Dropout(dropout)(headModel)
    outputs = layers.Dense(1, activation="sigmoid")(headModel)
    model = Model(inputs, outputs)

    return model

Каждая сеть EfficientNet оптимизирована для определенного размера изображения. Вы можете использовать его с другими, но рискуете иметь слишком тяжелую сеть, которая является избыточной, или слишком маленькую, которая не может достичь точности.

Строка «outputs» является критической, в зависимости от того, что вы хотите сделать. Если у вас есть несколько классов (2+), вы хотите указать количество классов и использовать «softmax» в качестве активации. функция. «softmax» направляет вас к «это будет один из классов».

В нашем случае мы используем «сигмоид», который равен либо 1, либо 0, поэтому у нас также есть только один класс.

Ваш input_shape с шириной, высотой, каналами (3 RGB, 1 серый) и специфичный для EfficientNet

'''
    EfficientNetB0 - (224, 224, 3)
    EfficientNetB1 - (240, 240, 3)
    EfficientNetB2 - (260, 260, 3)
    EfficientNetB3 - (300, 300, 3)
    EfficientNetB4 - (380, 380, 3)
    EfficientNetB5 - (456, 456, 3)
    EfficientNetB6 - (528, 528, 3)
    EfficientNetB7 - (600, 600, 3)
'''

Чего не хватает? Несколько обратных вызовов, поэтому наше обучение останавливается, когда прогресс застаивается и сохраняет модели.

callbacks = [
    EarlyStopping(monitor='val_loss', patience=30, mode='min', min_delta=0.0001),
    ModelCheckpoint("checkpoints/effnetb5-save_binary_{epoch:02d}-{val_loss:.2f}.hdf5", monitor='val_loss', mode='min', save_best_only=True)
]

model.compile(optimizer=keras.optimizers.Adam(learning_rate),
            loss=tf.keras.losses.BinaryCrossentropy(),
            metrics=keras.metrics.BinaryAccuracy())

model.summary()

model.fit(
    train_ds, epochs=epochs, callbacks=callbacks, validation_data=val_ds,
)

Основное различие между обучением и тонкой настройкой заключается в разблокировании/замораживании слоев и разной скорости обучения. В зависимости от ваших данных вы сможете получить довольно хороший классификатор бинарных изображений, который вы можете использовать. для фильтрации ваших данных.

Загрузите свою модель, загрузите изображение и предскажите :)

model = tf.keras.models.load_model(model_path)
model.summary()
img = cv2.imread(path)
# pre-process the image for classification
image = cv2.resize(image, image_size)
image = img_to_array(image)
image = np.expand_dims(image, axis=0)

preds = model.predict(image)[0]
if preds[0] <= confidenceMin:
  move_image(..)

Как было написано в начале, после реализации моего классификатора бинарных изображений, который работает довольно хорошо, я начал искать альтернативы и наткнулся на Обнаружение аномалий, о котором я поделюсь в другой статье.

Полная статья об EfficientNet на keras.io https://keras.io/examples/vision/image_classification_efficientnet_fine_tuning/

Дополнительные статьи











Полный код: