Использование трансферного обучения с EfficientNet и MobileNetV2

В этой статье я покажу вам, как создать классификацию рентгеновских изображений вируса Covide 19 с использованием трансферного обучения, а сеть будет основана на серии EfficientNet, которая достигла высочайшего уровня точности в ImageNet, будучи В 8,4 раза меньше и в 6,1 раза быстрее. И модель MobileNetV2… есть больше ссылок на MobileNetv2, вы можете прочитать это

весь код в google colab

Что такое Covid -19?

Коронавирусы - это группа вирусов, которые могут вызывать заболевания, от простуды и кашля до иногда более серьезных заболеваний. Ближневосточный респираторный синдром (БВРС-КоВ) и ТОРС-КоВ были тяжелыми случаями, с которыми мир уже столкнулся. SARS-CoV-2 (n-коронавирус) - это новый вирус семейства коронавирусов, впервые обнаруженный в 2019 году и ранее не обнаруженный у людей. Это стойкий вирус, который появился в Ухане в декабре 2019 года. Позднее Всемирная организация здравоохранения объявила его пандемией из-за высокой распространенности во всем мире. В настоящее время (15 мая 2020 г.) это приводит к 300 000 смертей по всему миру, в том числе 159 000 смертей только в Европе. Становится важным понять этот разброс. Здесь мы объясняем важность глубокого обучения в области компьютерного зрения в проблеме классификации этих изображений и знания, какая модель является лучшей по точности.

зачем переносить обучение?

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

Набор данных из kaggle

Что за болваны?

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

Почему EfficientNet?

По сравнению с другими моделями, обеспечивающими аналогичную точность ImageNet, EfficientNet намного меньше по размеру. Например, модель ResNet50 имеет в общей сложности 23 534 592 параметра, и даже несмотря на то, что она все еще не справляется с наименьшей эффективностью сети, которая в сумме принимает всего 5 330 564 параметра. Почему она настолько эффективна? Чтобы ответить на этот вопрос, мы углубимся в его базовую модель и строительный блок. Возможно, вы слышали о строительном блоке классической модели ResNet - это блок идентификации и свертки. Для EfficientNet его основным строительным блоком является мобильное перевернутое узкое место MBConv, которое впервые было представлено в MobileNetV2. За счет использования ярлыков непосредственно между узкими местами, которые соединяют гораздо меньшее количество каналов по сравнению с слоями расширения, в сочетании с разделимой по глубине сверткой, которая эффективно сокращает вычисления почти в k2 раз по сравнению с традиционными слоями. Где k обозначает размер ядра, определяя высоту и ширину окна двумерной свертки.

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

Передача обучения с EfficientNet и MobileNetV2

Трансферное обучение для классификации изображений более или менее не зависит от модели. Вы можете выбрать любую другую предварительно обученную модель ImageNet, такую ​​как MobileNetV2 или ResNet50, в качестве замены, если хотите. Предварительно обученная сеть - это просто сохраненная сеть, предварительно обученная на большом наборе данных, таком как ImageNet. Изученные функции могут оказаться полезными для множества различных задач компьютерного зрения, даже если эти новые задачи могут включать в себя классы, совершенно отличные от классов исходной задачи. EfficientNet построен для классификации ImageNet и содержит 1000 меток классов. Для нашего набора данных у нас только 2. Это означает, что последние несколько слоев для классификации нам не нужны. Их можно исключить при загрузке модели, указав для аргумента include_top значение False, и это относится и к другим моделям ImageNet, доступным в приложениях Keras. Мы ожидаем, что модель будет хорошо работать в нашем наборе данных Covide19-X Ray для ее классификации. если он обнаруживает, что чьи-то легкие инфицированы Covid-19 или не инфицированы по изображениям рентгеновского сканирования. Проблема классификации Covid-19 X Ray с относительно небольшим количеством образцов, самый простой способ начать - открыть этот блокнот в Colab, в то время как я объясню более подробную информацию здесь, в этом посте. Сначала перейдите на сайт kaggle и скопируйте api к набору данных. Конечно, у вас должна быть учетная запись в сервисах kaggle… .Перейдите по этой ссылке для набора данных за пределами

и скопируйте команду api для набора данных

О наборе данных

Классификационная маркировка базы данных для рентгеновских снимков грудной клетки была создана для трех случаев, классифицированных как случаи COVID-19, в дополнение к обычным изображениям и изображениям вирусной пневмонии. Есть 219 положительных изображений COVID-19, 1341 нормальных изображений и 1345 изображений вирусной пневмонии.

Хорошо, скопируйте эту команду API с изображения выше

kaggle datasets download -d tawsifurrahman/covid19-radiography-database

В блокноте google colab команда будет

!kaggle datasets download -d awsifurrahman/covid19-radiography-database

и напишите эту команду

from google.colab import files
files.upload()
!ls -lha kaggle.json
!pip install -q kaggle
!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/
!chmod 600 ~/.kaggle/kaggle.json
!kaggle datasets download -d awsifurrahman/covid19-radiography-database
# unzip folder dataset
!unzip /content/covid19-radiography-database.zip

для отображения некоторых изображений из набора данных

#load images
def show_images(dataset_path):
# size of the image: 48*48 pixels
pic_size = 48
# input path for the images
base_path = dataset_path
plt.figure(0, figsize=(12,20))
#cpt = 0
for expression in os.listdir(base_path + "/"):
for i in range(25):
# cpt = cpt + 1
plt.subplot(5,5,i+1)
img = load_img(base_path + "/" + expression + "/" +os.listdir(base_path + "/" + expression)[i], target_size=(pic_size, pic_size))
plt.imshow(img, cmap="gray")
plt.tight_layout()
plt.show()

Установите EfficientNet

#pip command install EfficientNet model by using
!pip install efficientnet

Импортированные библиотеки и модули

#Imported libraries and modules
import efficientnet.keras as efn
from sklearn.metrics import classification_report,accuracy_score,f1_score,confusion_matrix
import numpy as np
from keras.preprocessing.image import load_img, img_to_array
import matplotlib.pyplot as plt
import os
from keras.models import Model
from keras.utils import np_utils
import tensorflow as tf
from tensorflow.keras.models import load_model
from keras.utils.np_utils import to_categorical
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Activation,Dense, Dropout, Flatten, Conv2D
from keras.layers import  GlobalAveragePooling2D,BatchNormalization

загрузка предварительно обученной базовой модели конверсии

img_shape=224
import efficientnet.keras as efn
#using here EfficientNet series BO
baseModel =efn.EfficientNetB0(weights ='noisy-student', include_top=False, input_shape = (img_shape,img_shape,3))
baseModel.summary()

Чтобы создать наш собственный стек слоев классификации поверх сверточной базовой модели EfficientNet. Адаптируем GlobalAveragePooling2D. GlobalMaxPooling2D дает гораздо меньшее количество функций по сравнению со слоем Flatten, что эффективно уменьшает количество параметров.

x = baseModel.output
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(128, activation=”relu”)(x)
x = Dropout(0.3)(x)
x = Dense(64, activation=”relu”)(x)
predictions = Dense(3, activation=”softmax”)(x)
model = Model(inputs=baseModel.input, outputs=predictions)
for layer in baseModel.layers:
layer.trainable = False

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

data_gen= ImageDataGenerator(
horizontal_flip=True,
vertical_flip=True,
rotation_range=90,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=.1,
rescale=1/255,
fill_mode=’nearest’,
shear_range=0.1,
brightness_range=[0.5, 1.5],
validation_split=0.3)

Обратите внимание, что данные проверки не следует дополнять!

test_datagen = ImageDataGenerator(rescale=1.0 / 255)
train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
# All images will be resized to target height and width.
target_size=(height, width),
batch_size=batch_size,
# Since we use categorical_crossentropy loss, we need categorical labels
class_mode=”categorical”,
)
validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(height, width),
batch_size=batch_size,
class_mode=”categorical”,
)

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

model.compile(optimizer='adam', loss="categorical_crossentropy", metrics=['accuracy'])

окончательная подгонка модели

results = model.fit(train_generator,epochs=epochs,steps_per_epoch=train_generator.n/batch_size,validation_data=val_generator,validation_steps=val_generator.n/batch_size)

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

def model_efficientnetb0(no_classes):
#mport Model
img_shape=224
import efficientnet.keras as efn
model =efn.EfficientNetB0(weights ='noisy-student', include_top=False, input_shape = (img_shape,img_shape,3))
x = model.output
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(128, activation="relu")(x)
x = Dropout(0.3)(x)
x = Dense(64, activation="relu")(x)
predictions = Dense(no_classes, activation="softmax")(x)
model = Model(inputs=model.input, outputs=predictions)
return model
def model_efficientnetb7(no_classes):
#mport Model
img_shape=600
model =efn.EfficientNetB7(weights ='imagenet', include_top=False, input_shape = (img_shape,img_shape,3))
x = model.output
x = GlobalAveragePooling2D()(x)
x = Dropout(0.3)(x)
x = Dense(128, activation="relu")(x)
x = Dropout(0.3)(x)
x = Dense(64, activation="relu")(x)
predictions = Dense(no_classes, activation="softmax")(x)
model = Model(inputs=model.input, outputs=predictions)
return model

мы можем увидеть сводку для модели

no_classes=3
model=model_efficientnetb0(no_classes)
model.summary()

а также встроил все это в функцию

def model_train(dataset_path,model_name,epochs,batch_size,no_class,img_shape):
show_images(dataset_path)
no_classes=no_class
data_gen= ImageDataGenerator(
horizontal_flip=True,
vertical_flip=True,
rotation_range=90,
width_shift_range=0.1,
height_shift_range=0.1,
zoom_range=.1,
rescale=1/255,
fill_mode='nearest',
shear_range=0.1,
brightness_range=[0.5, 1.5],
validation_split=0.3)
#load the training data
train_generator = data_gen.flow_from_directory(
dataset_path,
target_size=(img_shape,img_shape),
batch_size=batch_size,class_mode='categorical',
subset='training',shuffle=True)
#load the training data
val_suffle=False
val_generator = data_gen.flow_from_directory(dataset_path,
target_size=(img_shape,img_shape),batch_size=batch_size,
class_mode='categorical',subset='validation',shuffle=val_suffle)
train_generator.next()[0].shape,train_generator.next()[1].shape
val_generator.next()[0].shape,val_generator.next()[1].shape
x,y = train_generator.next()
plt.figure(figsize=(10,10))
for i in range(8):
plt.subplot(4,2,i+1)
image = x[i]
label = y[i]
print (label)
plt.imshow(image)
plt.show()
if model_name=='efficientnetb0':
model=model_efficientnetb0(no_classes)
if model_name=='efficientnetb7':
model=model_efficientnetb7(no_classes)
model.compile(optimizer='adam', loss="categorical_crossentropy", metrics=['accuracy'])
results = model.fit(train_generator,epochs=epochs,steps_per_epoch=train_generator.n/batch_size,
validation_data=val_generator,validation_steps=val_generator.n/batch_size)
no_epochs=int(epochs)
plt.plot(results.history['accuracy'])
plt.plot(results.history['val_accuracy'])
plt.title(model_name+' Model Accuracy ')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.savefig(model_name+'_accuracy.png')
plt.show()
plt.savefig(model_name+'_accuracy.png')
plt.plot(results.history['loss'])
plt.plot(results.history['val_loss'])
plt.title(model_name+' Model Loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.savefig(model_name+'_loss.png')
plt.show()
plt.savefig(model_name+'_loss.png')
val_generator.reset()
pred=model.predict_generator(val_generator,steps=val_generator.n/batch_size,verbose=1)
predicted_class_indices=np.argmax(pred,axis=1)
labels = (train_generator.class_indices)
labels = dict((v,k) for k,v in labels.items())
y_pred=model.predict(val_generator,steps=val_generator.n/batch_size,verbose=1)
y_true = val_generator.classes
y_pred=np.argmax(y_pred, axis=1)
from sklearn.metrics import classification_report,accuracy_score,f1_score
print('accuracy_score:',accuracy_score(y_true,y_pred))
print('f1_score:',f1_score(y_true,y_pred,average='macro'))
class_label=list(train_generator.class_indices.keys())
print(classification_report(y_true, _pred,target_names=class_label))
class_names = val_generator.class_indices.keys()
#save model
model.save(model_name+'.h5')

и вычислите значение precision_score для набора данных проверки и прогноза

val_generator.reset()
pred=model.predict_generator(val_generator,steps=val_generator.n/batch_size,verbose=1)
predicted_class_indices=np.argmax(pred,axis=1)
labels = (train_generator.class_indices)
labels = dict((v,k) for k,v in labels.items())
y_pred=model.predict(val_generator,steps=val_generator.n/batch_size,verbose=1)
y_true = val_generator.classes
y_pred=np.argmax(y_pred, axis=1)
from sklearn.metrics import classification_report,accuracy_score,f1_score
print('accuracy_score:',accuracy_score(y_true,y_pred))
print('f1_score:',f1_score(y_true,y_pred,average='macro'))

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

def model_predict(img_path, model_path):
MODEL_PATH = model_path
print('Model loading...')
model=load_model(MODEL_PATH)
print('Model loaded. Started serving...')
image = cv2.imread(img_path)
image = cv2.resize(image, (img_shape,img_shape))
#image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
proba = model.predict(image)
confidence = proba.max() * 100
print('Class Name:',proba)
print('Confidence:',confidence)

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

dataset_path='/content/COVID-19 Radiography Database'
model_name='efficientnetb0'
epochs=10
batch_size=48
no_class=3
img_shape=224
model_train(dataset_path,model_name, epochs,batch_size,no_class,img_shape)

precision    recall  f1-score   support         COVID-19       0.68      1.00      0.81        65          NORMAL       0.97      0.87      0.92       402 Viral Pneumonia       0.93      0.96      0.94       403         accuracy                           0.92       870       macro avg       0.86      0.94      0.89       870    weighted avg       0.93      0.92      0.92       870

используя другую модель для MobileNetV2

dataset_path='/content/COVID-19 Radiography Database'
model_name='mobilenetv2'
epochs=10
batch_size=16
no_class=3
img_shape=224

Результат для MobileNetV2

precision    recall  f1-score   support         COVID-19       0.90      0.72      0.80        65          NORMAL       0.98      0.33      0.49       402 Viral Pneumonia       0.59      1.00      0.74       403         accuracy                           0.67       870       macro avg       0.82      0.68      0.68       870    weighted avg       0.79      0.67      0.63       870

Матрица неточностей для показателей (неточность, точность, матрица отзыва)

Нормализовать матрицу неточностей

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

Результат

мы видим, что Efficientnet B0 лучше и лучше MobileNetV2
по размеру параметров и точности для них обоих.

весь код в google colab

Ссылки

[1] https://www.dlology.com/blog/transfer-learning-with-efficientnet/

[2] Kaggle

[3] https://arxiv.org/abs/1905.11946

[4] https://www.kaggle.com/tawsifurrahman/covid19-radiography-database

[5] https://www.worldometer.info/coronavirus/