Введение в набор данных

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

Импорт набора данных

В отличие от популярных наборов данных MNist или Fashion Mnist, мы выбрали набор данных, который нуждался в предварительной обработке. Набор данных был получен через kaggle.

Мы используем Google Collaboratory и Google Диск для хранения нашего набора данных и запуска нашего кода. После загрузки набора данных на наш диск мы запускаем следующий код, чтобы смонтировать диск Google в нашей IDE Python. Это позволяет легко ссылаться на набор данных:

from google.colab import drive
drive.mount('/content/drive')

Набор данных состоит из 4242 помеченных изображений цветов. Изображения разделены на 5 классов: ромашка, роза, подсолнух, тюльпан и одуванчик.

import os
print(os.listdir('/content/drive/My Drive/FInal AI Project/flowers/flowers'))

Теперь мы импортируем все модели, которые потребуются для нашего проекта.

Библиотеки, используемые для этой модели, состоят из:

  • Инструменты визуализации и обработки данных, такие как numpy и pandas, а также matplotlib и seaborn.
  • Инструменты выбора модели, такие как sklearn.model_selection для train_test_split и метрики, такие как оценка точности
  • LabelEncoder для быстрого кодирования
  • ImageDataGenerator для предварительной обработки изображений
  • Модели Keras и слои для модели
  • Слои, специфичные для CNN, такие как Dropout, Flatten, Activation, Conv2D, MaxPooling2D, BatchNormalization
  • Тензорный поток
import warnings
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
# data visualisation and manipulation
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
import seaborn as sns
#configure
# sets matplotlib to inline and displays graphs below the corressponding cell.
%matplotlib inline
style.use('fivethirtyeight')
sns.set(style='whitegrid',color_codes=True)
#model selection
from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score,precision_score,recall_score,confusion_matrix,roc_curve,roc_auc_score
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import LabelEncoder
#preprocess.
from keras.preprocessing.image import ImageDataGenerator
#dl libraraies
from keras import backend as K
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam,SGD,Adagrad,Adadelta,RMSprop
from keras.utils import to_categorical
# specifically for cnn
from keras.layers import Dropout, Flatten,Activation
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization
import tensorflow as tf
import random as rn
# specifically for manipulating zipped images and getting numpy arrays of pixel values of images.
import cv2
import numpy as np
from tqdm import tqdm
import os
from random import shuffle
from zipfile import ZipFile
from PIL import Image

Предварительная обработка данных

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

Мы определяем каталоги, чтобы легко импортировать

X=[]
Z=[]
IMG_SIZE=150
FLOWER_DAISY_DIR='/content/drive/My Drive/FInal AI Project/flowers/flowers/daisy'
FLOWER_SUNFLOWER_DIR='/content/drive/My Drive/FInal AI Project/flowers/flowers/sunflower'
FLOWER_TULIP_DIR='/content/drive/My Drive/FInal AI Project/flowers/flowers/tulip'
FLOWER_DANDI_DIR='/content/drive/My Drive/FInal AI Project/flowers/flowers/dandelion'
FLOWER_ROSE_DIR='/content/drive/My Drive/FInal AI Project/flowers/flowers/rose'

Затем мы используем make_train_data для изменения размера изображений и добавляем массив пикселей к нашему X и добавляем метки к нашему Y.

def assign_label(img,flower_type):
return flower_type
def make_train_data(flower_type,DIR):
for img in tqdm(os.listdir(DIR)):
label=assign_label(img,flower_type)
path = os.path.join(DIR,img)
img = cv2.imread(path,cv2.IMREAD_COLOR)
img = cv2.resize(img, (IMG_SIZE,IMG_SIZE))
X.append(np.array(img))
Z.append(str(label))

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

make_train_data('Daisy',FLOWER_DAISY_DIR)
make_train_data('Sunflower',FLOWER_SUNFLOWER_DIR)
make_train_data('Tulip',FLOWER_TULIP_DIR)
make_train_data('Dandelion',FLOWER_DANDI_DIR)
make_train_data('Rose',FLOWER_ROSE_DIR)
print(len(X))

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

Если вы напечатаете уникальный список значений Z, вы получите следующее:

['Tulip', 'Daisy', 'Dandelion', 'Sunflower', 'Rose']

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

Следующим шагом является метка, кодирующая массив Y с использованием прямого кодирования (например, ромашка -> 0, роза -> 1, тюльпан -> 2 и т. д.).

le=LabelEncoder()
Y=le.fit_transform(Z)
Y=to_categorical(Y,5)
X=np.array(X)
X=X/255

Затем мы разделяем данные на обучающие и тестовые наборы. Для этого мы используем разделение 0,75/0,25, чтобы убедиться, что мы тестируем нашу модель на достаточном количестве изображений, чтобы избежать переобучения.

x_train,x_test,y_train,y_test=train_test_split(X,Y,test_size=0.25,random_state=42)
np.random.seed(42)
rn.seed(42)
tf.random.set_seed(42)

Разработка модели

Сверточный слой

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

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

Изображение ниже дает нам представление о том, как слой узнает об изображении через ядро/фильтр:

Модель свертки имеет следующие гиперпараметры:

Размер фильтра: это количество фильтров, на которых сверточные слои будут учиться.

размер ядра: это целое число или кортеж/список из 2 целых чисел, указывающий высоту и ширину окна свертки 2D.

Padding: этот параметр объясняет, как вести себя на границах и краях изображения.

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

Объединение слоев

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

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

Мы используем последовательный метод построения модели:

model = Sequential()
model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same',activation ='relu', input_shape = (150,150,3)))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same',activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(filters =96, kernel_size = (3,3),padding = 'Same',activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(filters = 96, kernel_size = (3,3),padding = 'Same',activation ='relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dense(5, activation = "softmax"))

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

model.compile(optimizer=Adam(lr=0.001),loss='categorical_crossentropy',metrics=['accuracy'])

Архитектура модели

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

History = model.fit(x_train,y_train,validation_data = (x_test,y_test),epochs = 5)

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

Интерпретация производительности нашей модели

History.history

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

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

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

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

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

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

plt.plot(History.history['loss'])
plt.plot(History.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epochs')
plt.legend(['train', 'test'])
plt.show()

plt.plot(History.history['accuracy'])
plt.plot(History.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epochs')
plt.legend(['train', 'test'])
plt.show()

Чтобы интерпретировать это, мы можем посмотреть, например, на случай B (большие потери, высокая точность). Если мы получаем подобные результаты, это может помочь в интерпретации в том смысле, что мы можем понять, что модель способна правильно классифицировать большинство классов данных, за исключением некоторых, в отношении которых она допускает действительно большие ошибки (это означает, что она не понимает шаблоны данных). этот определенный класс). Имея эту информацию, вы можете вернуться к данным и посмотреть, почему модель может совершать эти ошибки, и попытаться их исправить.

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

В нашем случае мы наблюдаем потери при поездке и тестировании около 0,7 и 0,9 соответственно, а точность при поездке и тестировании составляет около 0,75 и 0,67. Это указывает на низкие потери и низкую точность, что означает, что мы делаем небольшие ошибки на многих изображениях.

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

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

Вывод

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

Полный код вы можете найти здесь