Использование моделей глубокого обучения для классификации изображений.

Эта статья - плод моей стажировки в Harold Waste. Он суммирует результаты глубоких исследований моделей глубокого обучения для выполнения задачи классификации изображений отходов.

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

Я привожу несколько категорий образов отходов, которые мы рассмотрим в этой статье.

Где 2.03.00, 3.05.00 и 3.03.00 - разные версии макулатуры.

Более подробную информацию о перерабатываемых отходах можно найти в этом URL http://www.cepi.org/system/files/public/documents/publications/recycling/2013/CEPI_EN%20643_brochure_FINAL_0.pdf

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

Доступ к помеченным данным не всегда легко получить, для этого можно принять во внимание две возможности:

  • Выполнение увеличения данных для определенного помеченного набора данных
  • Использование метода парсинга для загрузки данных из Интернета

Модели как автокодировщики, RBM и DBN (Deep Belief Network: стек RBM) обучаются с помощью определенного процесса: во-первых, модель обучается с неконтролируемыми данными, чтобы узнать, как сопоставлять входные данные с выходными данными, в других случаях. слов, чтобы узнать, как восстановить его ввод из скрытого кода или так называемых функций.

Затем модель настраивается с использованием помеченных данных. Этот процесс называется полу-контролируемым обучением. Наконец, модель тестируется на невидимых данных, чтобы измерить ее точность и эффективность.

Небольшое руководство для понимания разработанного кода:

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

Кластеризация: возобновляет кластерную модель, вдохновленную k-means, поддерживаемую библиотекой Sklearn.

Deep_Learning: включает сценарии Python для моделей, разработанных во время моей стажировки (автоматический кодировщик FC, сверточный автоматический кодировщик, автоматический кодировщик шумоподавления, RBM, DBN, сверточная нейронная сеть, VGG16 с поддержкой передачи обучения…)

  • Папка приложения содержит графики обученной модели, файлы h5 для сохранения весов модели, файлы json для сохранения архитектур модели и файл python с подробным описанием процесса обучения и результатов кластеризации.
  • Папка служб, суммирует функции утилит, используемых для разработки моделей и выполнения задач кластеризации и классификации.

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

Floydhub гибок с точки зрения цен на экземпляры GPU и CPU, им также легко управлять, легко загружать и прикреплять к нему данные.

Управлять своим рабочим пространством и записными книжками jupyter также легко с помощью floydhub.

Процесс извлечения признаков

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

Современное состояние, предоставляет сложные модели, такие как автоматические кодировщики и сети глубокого убеждения (набор ограниченных машин Больцмана).

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

Модели будут пытаться улучшить свое представление данных, выполняя простое сравнение между входными данными и реконструированными входными данными, найденными в выходных данных.

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

Многие варианты RBM и автокодировщиков использовались для извлечения признаков.

  • Например, мы начинаем с двоичного RBM,

Наш RBM содержит 256 единиц в скрытом слое, использует сигмоид в качестве функции активации и был обучен с использованием SGD в течение 30 эпох с 1e-3 в качестве скорости обучения и достиг одной итерации контрастной дивергенции, вдохновленной Монте-Карло цепи Маркова (MCMC).

RBM =  BinaryRBM(n_hidden_units=256,
                 activation_function='sigmoid',
                 optimization_algorithm='sgd',
                 learning_rate=1e-3,
                 n_epochs=30,
                 contrastive_divergence_iter=1,
                 batch_size=64,
                 verbose=True)

Затем RBM обучается на наборе изображений для извлечения признаков.

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

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

DBN_Featuring = UnsupervisedDBN( hidden_layers_structure=[256, 256],
                 activation_function='sigmoid',
                 optimization_algorithm='sgd',
                 learning_rate_rbm=1e-3,
                 n_epochs_rbm=10,
                 contrastive_divergence_iter=1,
                 batch_size=32,
                 verbose=True)

Полный код полууправляемого обучения для DBN, где каждый RBM предварительно обучен на 10 эпох, а точная настройка модели выполняется за 50 эпох с помощью алгоритма SGD и повторно используется в качестве функции активации для скрытых слоев.

classifier = SupervisedDBNClassification(hidden_layers_structure=[256, 256],
                                         learning_rate_rbm=0.05,
                                         learning_rate=0.1,
                                         n_epochs_rbm=10,
                                         n_iter_backprop=50,
                                         batch_size=32,
                                         optimization_algorithm='sgd',
                                         activation_function='relu',
                                         dropout_p=0.1)
history = classifier.fit(x_train, y_train)

Модель вдохновлена ​​этим проектом на github

  • Наш второй интерес - это модели автокодировщиков, особенно сверточные автокодеры и автокодеры с шумоподавлением.

** Сверточный автоматический кодировщик

Мы развернули Conv AE с 16 уровнями, чередующимися между сверточными уровнями, Maxpooling, Upsampling и двумя командами исключения для регуляризации.

Модель разработана с использованием библиотеки Keras как таковой.

from keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, Dropout
from keras.models import Model
input_img = Input( shape=(x_train.shape[1],x_train.shape[2],x_train.shape[3]))
# encoder model 
x = Conv2D(16, (3,3), activation= 'relu', padding= 'same')(input_img)
x = MaxPooling2D( (2,2), padding= 'same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Dropout(DROPOUT)(x)
x = Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
encoded= Conv2D(8, (3,3), activation= 'relu', padding='same')(x)
x= UpSampling2D( (2,2))(encoded)
x= Conv2D(8, (3,3), activation= 'relu', padding='same')(x)
x= UpSampling2D( (2,2))(x)
x= Conv2D(8, (3,3), activation= 'relu', padding='same')(x)
x= UpSampling2D( (2,2))(x)
x= Dropout(DROPOUT)(x)
x= Conv2D(16, (3,3), activation= 'relu', padding='same')(x)
x= UpSampling2D( (2,2))(x)
decoded = Conv2D(x_train.shape[3], (3, 3), activation='sigmoid', padding='same')(x)
autoencoder_model= Model( input_img,decoded)

После этого модель обучается в течение 500 эпох с использованием RMSprop в качестве алгоритма оптимизации и категориальной кроссентропии для функции потерь (в отношении нашей задачи классификации n, где n ›= 3).

Мы использовали Tensorboard для отслеживания вариаций в пределах точности и функции потерь за эпохи, размер пакета был зафиксирован на 64. При обучении автокодировщиков важно часто отслеживать вариации функции потерь, а не точность, которая не очень репрезентативна в этой части.

autoencoder_model.compile(optimizer='RMSprop', loss='categorical_crossentropy', metrics=['accuracy'])
autoencoder_model.fit(x_train, x_train,
                epochs=EPOCHS,
                batch_size=BATCHE_SIZE,
                shuffle=SHUFFLE,
                validation_split=VALIDATION_SPLIT,
                callbacks=[TensorBoard(log_dir=Path_to_logs )])

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

encoder = Model( input_img,encoded)

и тогда нет необходимости повторно обучать кодировщик, он напрямую импортирует веса из автокодировщика.

Затем кодировщик можно протестировать на новом наборе невидимых данных.

** Автоматический кодировщик шумоподавления

Denoising AE аналогичен сверточным, но принимает на вход зашумленную версию данных и пытается восстановить чистую версию без шума.

Затем наша модель будет обучена восстанавливать четкую версию наших входных данных.

Обучение Denoising AE само по себе

autoencoder.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['categorical_accuracy'])
history = autoencoder.fit(x_train_noisy, x_train,
            epochs=EPOCHS,
            atch_size=BATCH_SIZE,
            shuffle=SHUFFLE,
            validation_split=VALIDATION_SPLIT,
            callbacks=[TensorBoard(log_dir=PATH_TO_SAVE_LOGS)])

Как и для Conv Auto Encoder, мы можем просто получить наши функции из модели кодировщика, извлеченной из шумоподавляющего AE.

encoder= Model(input_img,encoded)
encoder.summary()
features = encoder.predict(x_test)

Еще одна возможность, которую мы использовали, заключалась в том, чтобы извлечь выгоду из предварительно обученных моделей, особенно с лучшими показателями по сравнению с современными, такими как VGG16 или ResNet.

Итак, первое, что нужно было сделать, это загрузить модель из Интернета с помощью библиотеки Keras и удалить полностью подключенную часть модели, которая возвращает выходные данные для 1000 классов.

VGG16 изначально обучен на 10000 классах изображений в Imagenet. также возможно управление входной формой vgg16, в нашем случае мы устанавливаем входную форму 128x128x3

from keras.applications.vgg16 import VGG16
model =VGG16(weights='imagenet',classes=NUM_CLASSES,input_shape = (128,128,3),include_top=False)

После этого мы установили слои vgg16 как необучаемые, чтобы избежать изменения веса.

Вес - это интеллект данной модели.

Поэтому мы добавляем простые полносвязные слои (Flatten, Dense, Dense) с возможностью некоторых регуляризаторов, таких как Dropout.

Наш последний слой настроен как плотный слой с выходной формой NUM_CLASSES и softmax в качестве функции активации.

Результатом будет распределение вероятностей ввода по определенным меткам / классам.

Затем компилируется окончательная модель, и category_crossentropy устанавливается как функция потерь.

from keras.layers.core import Dense, Dropout, Flatten
from keras import regularizers
# Freeze the layers which you don't want to train. Here I am freezing the first 5 layers.
for layer in model.layers[:21]:
    layer.trainable = False
#Adding custom Layers 
x = model.output
x = Flatten()(x)
x = Dense(1024, activation="relu")(x)
x = Dropout(0.1)(x)
x = Dense(512, activation="relu")(x)
predictions = Dense(NUM_CLASSES, activation="softmax")(x)
# creating the final model 
model_final = Model(model.input, predictions)
# compile the model 
model_final.compile(loss='categorical_crossentropy', optimizer=OPTIMIZER, metrics=['accuracy'])
model_final.summary()

После этого обучения модель может быть проведена путем простого выполнения контролируемого обучения с помеченными данными.

history = model_final.fit(x_train, y_train, batch_size=BATCH_SIZE, 
            epochs=500,
            verbose=VERBOSE,
            shuffle=True,
            validation_split =VALIDATION_SPLIT,
            callbacks = [tensorboard])

Процесс кластеризации

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

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

Основным используемым алгоритмом кластеризации является метод k-средних, поддерживаемый библиотекой Sklearn.

Характеристики изменяются в соответствии с входными данными классификатора, затем модель кластеризации с именем оценщик обучается по reshaped_features.

n_cluster - это количество возможных кластеров, которые мы хотели бы иметь. n_init - это количество раз, когда алгоритм k-средних будет запускаться с разными начальными числами центроидов. Окончательные результаты будут лучшим результатом n_init последовательных прогонов с точки зрения инерции.

from sklearn.cluster import KMeans
features_reshaped = features.reshape( len(features ),np.prod( features.shape[1:]))
estimator = KMeans(init='k-means++', n_clusters = N_CLUSTER , n_init=14)
estimator.fit(features_reshaped)

После этого оценщик будет возвращать данные кластеров в кластеры «n_cluster».

all_predictions = estimator.predict(features_reshaped)

также возможна визуализация сгруппированных данных в гистограммы

Для определения эффективности кластеризации можно принять во внимание множество дополнительных мер, таких как измерение точности или чувствительности на кластер.

Распределение данных внутри кластеров

Точность на кластер

Мера чувствительности

Результаты по моделям кластеризации:

Модель 1:

  • Сверточный автоматический кодировщик

Гиперпараметры

BATCH_SIZE = 64
EPOCHS = 500
VERBOSE = True
VALIDATION_SPLIT = 0.2
SHUFFLE = True
OPTIMIZER = RMSprop
learning rate =2e-4
input_shape 128x128x3
Labeled data (626,128,128,3)
unlabeled data (2000,128,128,3)

Вывод :

Ошибка реконструкции AE: 0.6211

При использовании кластера K-средних у нас в основном три кластера в качестве выходных данных, визуализация кластеризованных данных как таковая:

Распределение данных внутри кластеров

Точность на кластер

Модель 2:

  • Автоматический кодировщик шумоподавления

Гиперпараметры

BATCH_SIZE = 64
EPOCHS = 500
VERBOSE = True
VALIDATION_SPLIT = 0.2
SHUFFLE = True
OPTIMIZER = RMSprop
learning rate =2e-4
input_shape 128x128x3
Labeled data (626,128,128,3)
unlabeled data (2000,128,128,3)

Вывод :

Ошибка реконструкции AE: 0,7833

Результаты кластеризации:

Распределение данных внутри кластеров

Точность на кластер

Модель 3

  • Ограниченная машина Больцмана
RBM =  BinaryRBM(n_hidden_units=256,
                 activation_function='sigmoid',
                 optimization_algorithm='sgd',
                 learning_rate=1e-3,
                 n_epochs=30,
                 contrastive_divergence_iter=1,
                 batch_size=64,
                    verbose=True)
RBM.fit(x_train)
[START] Pre-training step:
>> Epoch 1 finished     RBM Reconstruction error 1952.491901
>> Epoch 2 finished     RBM Reconstruction error 1922.482935
>> Epoch 3 finished     RBM Reconstruction error 1904.396054
>> Epoch 4 finished     RBM Reconstruction error 1891.619399
>> Epoch 5 finished     RBM Reconstruction error 1871.401569
>> Epoch 6 finished     RBM Reconstruction error 1856.040625
>> Epoch 7 finished     RBM Reconstruction error 1839.471314
>> Epoch 8 finished     RBM Reconstruction error 1819.748205
>> Epoch 9 finished     RBM Reconstruction error 1806.192314
>> Epoch 10 finished    RBM Reconstruction error 1799.971924
[END] Pre-training step

После обучения RBM неконтролируемым методом мы переходим к извлечению признаков.

features_train = RBM.transform(x_train)
features_test = RBM.transform(x_test)

Затем функции передаются в качестве входных данных в нашу модель кластеризации под названием оценщик:

estimator = KMeans(init='k-means++', n_clusters = 3 , n_init=10)
estimator.fit(features_reshaped)

Затем оценщик проверяется на невидимых данных, чтобы разделить их на кластеры.

features_test_reshaped = feature_test.reshape( len(feature_test ),np.prod( feature_test.shape[1:]))
all_predictions = estimator.predict(feature_test)

При построении результатов мы замечаем, что наши кластеры содержат разнородные данные, что означает, что кластеры могут содержать данные разных классов одновременно.

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

В качестве решения мы разработали более сложную модель, названную Deep Belief Network, которая обычно представляет собой стек RBM, где выходные данные RBM являются входными данными следующего, указанного выше.

DBN_Featuring = UnsupervisedDBN( hidden_layers_structure=[256, 256,256],
                 activation_function='sigmoid',
                 optimization_algorithm='sgd',
                 learning_rate_rbm=1e-3,
                 n_epochs_rbm=10,
                 contrastive_divergence_iter=1,
                 batch_size=32,
                verbose=True)

Обучение DBN проходит через промежуточные этапы, на которых обучается каждый RBM сразу.

DBN_Featuring.fit(x_train)
[START] Pre-training step:
>> Epoch 1 finished     RBM Reconstruction error 1952.491901
>> Epoch 2 finished     RBM Reconstruction error 1922.482935
>> Epoch 3 finished     RBM Reconstruction error 1904.396054
>> Epoch 4 finished     RBM Reconstruction error 1891.619399
>> Epoch 5 finished     RBM Reconstruction error 1871.401569
>> Epoch 6 finished     RBM Reconstruction error 1856.040625
>> Epoch 7 finished     RBM Reconstruction error 1839.471314
>> Epoch 8 finished     RBM Reconstruction error 1819.748205
>> Epoch 9 finished     RBM Reconstruction error 1806.192314
>> Epoch 10 finished    RBM Reconstruction error 1799.971924
>> Epoch 1 finished     RBM Reconstruction error 42.668121
>> Epoch 2 finished     RBM Reconstruction error 36.282013
>> Epoch 3 finished     RBM Reconstruction error 32.051567
>> Epoch 4 finished     RBM Reconstruction error 29.067530
>> Epoch 5 finished     RBM Reconstruction error 26.825274
>> Epoch 6 finished     RBM Reconstruction error 25.047325
>> Epoch 7 finished     RBM Reconstruction error 23.644447
>> Epoch 8 finished     RBM Reconstruction error 22.503990
>> Epoch 9 finished     RBM Reconstruction error 21.555744
>> Epoch 10 finished    RBM Reconstruction error 20.732342
>> Epoch 1 finished     RBM Reconstruction error 7.491046
>> Epoch 2 finished     RBM Reconstruction error 5.832964
>> Epoch 3 finished     RBM Reconstruction error 4.837579
>> Epoch 4 finished     RBM Reconstruction error 4.221423
>> Epoch 5 finished     RBM Reconstruction error 3.802794
>> Epoch 6 finished     RBM Reconstruction error 3.514032
>> Epoch 7 finished     RBM Reconstruction error 3.314745
>> Epoch 8 finished     RBM Reconstruction error 3.177018
>> Epoch 9 finished     RBM Reconstruction error 3.074382
>> Epoch 10 finished    RBM Reconstruction error 2.999290
[END] Pre-training step

Как вы можете видеть на этом рисунке, кластеры относительно более значимы, и мы можем легко обнаружить кластер, в котором класс 2.06.00 очень распространен, тогда как во втором кластере наш алгоритм находит элементы древовидных классов очень близко.

Многие шаги для улучшения этих результатов могут быть приняты во внимание, например, обучение все больше и больше DBN на больших наборах данных, оптимизация гиперпараметров.

Процесс классификации

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

Например, для Denoising AE часть кодирования может быть дополнена полностью подключенной частью поверх нее с выводом плотного слоя и функцией активации softmax.

from keras.models import Model
from keras.layers import Flatten, Dense, Dropout
from keras import regularizers
for layer in loaded_model_encoder.layers[:10]:
    loaded_model_encoder.trainable = False
#Adding custom Layers 
x = loaded_model_encoder.output
x = Flatten()(x)
x = Dense(1024, activation="relu")(x)
x = Dropout(0.1,name='dropout_10')(x)
x = Dense(512, activation="relu",kernel_initializer='uniform')(x)
predictions = Dense(NUM_CLASSES, activation="softmax")(x)
# creating the final model 
model_final_classifier = Model(loaded_model_encoder.input, predictions)
# compile the model 
model_final_classifier.compile(loss='categorical_crossentropy', optimizer='RMSprop', metrics=['accuracy'])

Затем модель классификатора настраивается с помеченными данными для выполнения задачи классификации.

history_classifier = model_final_classifier.fit(x_train, y_train, batch_size=128, epochs=300,
shuffle=True,validation_split =.1,
callbacks = [tensorboard])

Эволюция функции потерь и эволюция точности также отслеживаются с помощью тензорной таблицы.

Эволюция функции точности и потерь

Классификация с использованием сверточной АЭ достигла точности 51,14% по набору поездов и 34,57% по набору тестов.

Для автоматического кодировщика с шумоподавлением

Классификатор как таковой:

from keras.models import Model
from keras.layers import Flatten, Dense, Dropout
from keras import regularizers
for layer in loaded_model_encoder.layers[:10]:
    loaded_model_encoder.trainable = False
#Adding custom Layers 
x = loaded_model_encoder.output
x = Flatten()(x)
x = Dense(1024, activation="relu")(x)
x = Dropout(0.1,name='dropout_10')(x)
x = Dense(512, activation="relu")(x)
predictions = Dense(NUM_CLASSES, activation="softmax")(x)
# creating the final model 
model_final_classifier = Model(loaded_model_encoder.input, predictions)
# compile the model 
model_final_classifier.compile(loss='categorical_crossentropy', optimizer='RMSprop', metrics=['accuracy'])
model_final_classifier.summary()

Эволюция функции точности и потерь

Мы замечаем, что существует разрыв между наборами проверки и обучения, эти вариации могут быть обработаны с помощью методов регуляризации, и результаты следующие:

...
x = Dropout(0.1,name='dropout_10')(x)
x = Dense(512, activation="relu",kernel_initializer='uniform')(x)
predictions = Dense(NUM_CLASSES, activation="softmax")(x)
...

Достигнутые результаты

Классификация

Для задачи классификации с использованием тупосвязных моделей поверх экстракторов признаков

Трансферное обучение

Для vgg16, поддерживаемого методом передачи обучения, при этом полностью исключена часть, подключенная к верхней части модели.

Кластеризация

  • Точность кластеризации измеряется как среднее значение точности на кластер.

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

Наша цель состояла в том, чтобы достичь как минимум 50% потенциальной точности изображений отходов, используя модели глубокого обучения, такие как RBM, DBN и автоэнкодеры, которые мы смогли достичь с максимальной точностью 46,98%, но с переносом обучения через vgg16 мы смогли для достижения точности 69,84%, что было вполне достаточно.

Я надеюсь, что эта статья поможет вам познакомиться с миром машинного обучения и распознавания изображений.