Итак, сверточные нейронные сети стали так популярны в наши дни! И всякий раз, когда вы слышите слово CNN, держу пари, в вашей голове всплывают различные наборы данных изображений. Да брось! Иногда такие вещи, как MNIST, CIFAR-10, слишком популярны, верно?
Что ж, это руководство научит вас создавать собственный набор данных и обучать на нем свою модель CNN. Да, я знаю, что в Интернете полно моделей, обученных MNIST, и очень немногие учат вас обучать пользовательскую модель. Что ж, приступим!
Мы обучим классификатор различать розы, подсолнухи и тюльпаны. Вы можете сослаться на мой GitHub для загрузки кода или файлов, связанных с кодом. Опять же, убедитесь, что все созданные вами папки и наборы данных находятся в одной папке. Вот GitHub: https://github.com/kaiwalya4850/Custom_CNN.
Вот ссылка для загрузки пользовательского набора данных: https://drive.google.com/open?id=1czBqp0Fk2F7fDoakizZPrSFRcUQ7WHow
Хорошо, этого было достаточно, верно? Давайте займемся серьезным кодированием!
Импортируйте наши любимые библиотеки! pip install, если на вашем компьютере их нет.
import numpy as np np.random.seed(1337) # for reproducibility from keras.datasets import mnist from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Input, Conv2D, MaxPool2D from keras.utils import np_utils from keras.models import Model import matplotlib.pyplot as plt import matplotlib import os from keras.models import Sequential import theano from PIL import Image from numpy import * from sklearn.utils import shuffle from sklearn.cross_validation import train_test_split
Теперь мы определяем batch_size (указывается, сколько изображений вы должны отправить для обучения в данный момент времени). nb_epoch — это количество раз, которое вы хотите запустить код. 200x200 — это форма, до которой будут изменяться изображения.
batch_size = 5 nb_classes = 3 nb_epoch = 32 # input image dimensions img_rows, img_cols = 200, 200 # number of convolutional filters to use nb_filters = 32 # size of pooling area for max pooling pool_size = (2, 2) ## 4 ELEMENTS, TOOK MAX OF IT # convolution kernel size kernel_size = (3, 3)
Теперь добавим пути к нашим папкам.
path1 = 'C:/Users/Kaiwalya/Desktop/ML/Datasets/flowers/Mixed/' #path of folder of images path2 ='C:/Users/Kaiwalya/Desktop/ML/Datasets/flowers/Mix_greyscale/' #path of folder to save images
Приведенный ниже скрипт выполняет поиск по заданному пути.
listing = os.listdir(path1)
Давайте напечатаем количество изображений, которые у нас есть в нашем наборе обучающих данных. Пользователи Python2 удаляют скобки в print.
num_samples=size(listing) print (num_samples)
Теперь давайте сохраним изображения в сером цвете. Вы можете преобразовать изображения в красный/зеленый/синий цвет в соответствии с вашими потребностями. Просто сделайте обратную косую черту для прямой, если вы получите какие-либо ошибки, потому что мне пришлось сделать это, когда я работал в облаке.
for file in listing: im = Image.open(path1 + '\\' + file) img = im.resize((img_rows,img_cols)) gray = img.convert('L') #need to do some more processing here gray.save(path2 +'\\' + file, "JPEG")
Снова. используя os.listdir для проверки файлов в папке. На этот раз он проверяет папку с изображениями в оттенках серого.
imlist = os.listdir(path2)
Давайте получим размер изображений.
img_data_list=[] im1 = array(Image.open('Mix_greyscale' + '\\'+ imlist[0])) # open one image to get size m,n = im1.shape[0:2] # get the size of the images imnbr = len(imlist) # get the number of images
Как вы знаете, изображение в основном представляет собой матрицу. Теперь давайте преобразуем эту матрицу в правильную форму массива, чтобы выполнить дальнейшую обработку массива. Просто обратитесь к GitHub, если вы обнаружите какие-либо намеренные ошибки!
immatrix = array([array(Image.open('Mix_greyscale'+'\\'+im2)).flatten() for im2 in imlist],'f')
Итак, как ваша машина узнает, что это роза, или подсолнух, или тюльпан? Потому что он может просто определить особенности, а не имена! Итак, давайте просто пометим изображения. Я назвал их по порядку. Сначала 177 роз, затем 177 подсолнухов и 177 тюльпанов.
label=np.ones((num_samples,),dtype = int) label[0:178]=0 ##Python needs +1 of the total label[178:354]=1 ## ie, if 177 images, write till 178 label[354:]=2 ## because last image is'nt counted
Давайте перемешаем все изображения, чтобы не получить самую раздражающую проблему! Да, переобучение! И да, вы можете присвоить random_state любое число.
data,Label = shuffle(immatrix,label, random_state=2) train_data = [data,Label]
Давайте посмотрим случайное изображение. Вы получите что-то вроде «(531, 40000)», где 40000 — это 200x200, помните, что мы изменили размер изображений.
img=immatrix[167].reshape(img_rows,img_cols) plt.imshow(img) plt.imshow(img,cmap='gray') print (train_data[0].shape) print (train_data[1].shape)
Итак, теперь, когда все определено и настроено, давайте напишем что-нибудь для обучения всему этому! Разделяем данные, для всего этого использовали встроенную библиотеку от sk-learn.
(X, y) = (train_data[0],train_data[1]) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=4)
Теперь изменим форму массива для лучшего обучения. Это часть кода, которая имеет вариации. Вы увидите что-то другое в документации keras или scikit.
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1) X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1) input_shape = (1, img_rows, img_cols)
Итак, давайте распечатаем и посмотрим, что именно мы изменили.
X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train /= 255 X_test /= 255 print('X_train shape:', X_train.shape) print(X_train.shape[0], 'train samples') print(X_test.shape[0], 'test samples')
Применение одноразового кодирования.
Y_train = np_utils.to_categorical(y_train, nb_classes) Y_test = np_utils.to_categorical(y_test, nb_classes)
Данные проверки построения.
split = 0.7 split_value = int(0.7 * len(X_train)) X_val = X_train[split_value:] Y_val = Y_train[split_value:] X_train = X_train[:split_value] Y_train = Y_train[:split_value]
Визуализация изображений и проверка, все ли идеально.
fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(16, 9)) for i, axes in enumerate(ax.flat): axes.imshow(X_train[i, :, :, 0], cmap='gray')
Строительные слои. Это одна из важных частей любой модели CNN. И вы можете изменить/добавить/удалить любое количество слоев, которые вы хотите. Я добавил несколько слоев в слои, которые использовались для обучения набора данных MNIST. Прежде чем завершить эти слои. Я менял их много и много раз.
inp = Input(shape=[200, 200, 1]) ## GREY SCALE 200X200 IMAGE ## BUILD LAYERS, KERNEL SIZE IS FILTER SIDE layer1 = Conv2D(filters=nb_filters, kernel_size=kernel_size, strides=(1, 1), ## STEPS WE WANT TO SHIFT padding='same', ## IF WE DONT, WE MAY HAVE SMALLER SIZE OF IMAGE IN OUTPUT ## LIKE MAYBE WE'LL LOSE A DIMENSION, WE WANT SAME DIMENSION SO USE IT! activation='relu')(inp) layer1_maxpool = MaxPool2D(pool_size=(2, 2), padding='same')(layer1) ## ATTACH ARCHITECTURE OF LAYER1, BY layer1 layer2 = Conv2D(filters=nb_filters, kernel_size=kernel_size, strides=(1, 1), padding='same', activation='relu')(layer1_maxpool) layer2_maxpool = MaxPool2D(pool_size=(2, 2), padding='same')(layer2) layer2x = Conv2D(filters=nb_filters, kernel_size=kernel_size, strides=(1, 1), padding='same', activation='relu')(layer2_maxpool)## AFTER THIS OUTPUT IS 14X14, AND HAVE 32 KERNELS, 14X14X32 layer2x_maxpool = MaxPool2D(pool_size=(2, 2), padding='same')(layer2x) layer3x = Conv2D(filters=nb_filters, kernel_size=kernel_size, strides=(1, 1), padding='same', activation='relu')(layer2x_maxpool) layer3x_maxpool = MaxPool2D(pool_size=(2, 2), padding='same')(layer3x) layer3 = Flatten()(layer3x_maxpool) layer4 = Dense(units=128, activation='relu')(layer3) layer5 = Dense(units=nb_classes, activation='softmax')(layer4)
Layer5 содержит все данные модели. Поэтому мы используем это на реальных этапах обучения модели. У этого также были оптимизаторы, их много, и вы можете настроить этот. Просто зайдите в документацию.
model = path2 model = Model(inputs=inp, outputs=layer5) ## DEFINE ACTUAL MODEL, INP. OUTPUT IS LAYER5 ## THIS CONTAINS WHOLE CNN MODEL. NOW GO FOR OPTIMISER AND ALL model.compile(loss='categorical_crossentropy',## SGD IS LIKE EXTENSION OF BINARY CROSS ENTROPY optimizer='sgd', metrics=['accuracy'])
В следующей строке будут показаны обучаемые параметры. И они меняются каждый раз, когда вы играете со слоями.
model.summary()
Итак, поехали! обучение начинается!
history = model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,verbose=1, validation_data=(X_val, Y_val))
Давайте посмотрим на наш тестовый результат.
score = model.evaluate(X_test, Y_test, verbose=0) print('Test score:', score[0]) print('Test accuracy:', score[1])
Построим график и посмотрим, как менялись параметры в процессе обучения.
plt.plot(history.history['acc']) plt.plot(history.history['val_acc']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()
Давайте, наконец, посмотрим на обучение, точность тестирования и точность проверки.
train_loss=history.history['loss'] val_loss=history.history['val_loss'] train_acc=history.history['acc'] val_acc=history.history['val_acc'] xc=range(nb_epoch) plt.figure(1,figsize=(7,5)) plt.plot(xc,train_loss) plt.plot(xc,val_loss) plt.xlabel('num of Epochs') plt.ylabel('loss') plt.title('train_loss vs val_loss') plt.grid(True) plt.legend(['train','val']) print (plt.style.available) # use bmh, classic,ggplot for big pictures plt.style.use(['classic']) plt.figure(2,figsize=(7,5)) plt.plot(xc,train_acc) plt.plot(xc,val_acc) plt.xlabel('num of Epochs') plt.ylabel('accuracy') plt.title('train_acc vs val_acc') plt.grid(True) plt.legend(['train','val'],loc=4) print (plt.style.available) # use bmh, classic,ggplot for big pictures plt.style.use(['classic'])
Хорошо! Вот и все. Попробуйте добавить матрицу путаницы, чтобы глубже заглянуть в вашу модель. Попробуйте улучшить эти графики. Моя модель временами сильно портилась. Думаю, тот, кого я тренировал, тоже не на высоте. Но все дело в настройке, ударе, следе и достижении пункта назначения! Не стесняйтесь связаться с нами, если возникнут какие-либо вопросы! Надеюсь, это помогло! Спасибо за чтение!