Итак, сверточные нейронные сети стали так популярны в наши дни! И всякий раз, когда вы слышите слово 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'])

Хорошо! Вот и все. Попробуйте добавить матрицу путаницы, чтобы глубже заглянуть в вашу модель. Попробуйте улучшить эти графики. Моя модель временами сильно портилась. Думаю, тот, кого я тренировал, тоже не на высоте. Но все дело в настройке, ударе, следе и достижении пункта назначения! Не стесняйтесь связаться с нами, если возникнут какие-либо вопросы! Надеюсь, это помогло! Спасибо за чтение!