Введение в глубокое обучение (2) Обучение и использование модели Keras

Keras

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

1. Введение в Керас

Keras: библиотека глубокого обучения на основе Python.

001.png

Keras — это высокоуровневый API нейронной сети, написанный на Python, который позволяетTensorFlow,CNTK, или TheanoРаботает как бэкенд. Keras был разработан с упором на возможность быстрого экспериментирования. *Возможность преобразовывать свои идеи в экспериментальные результаты с минимальной задержкой — ключ к хорошему исследованию.

  • Keras уделяет первостепенное внимание опыту разработчиков
  • Keras широко применяется в промышленности и научных кругах.
  • Keras может легко превращать модели в продукты
  • Keras поддерживает несколько серверных движков, не привязывая вас к одной экосистеме.
  • Разработка Keras поддерживается ключевыми компаниями в экосистеме глубокого обучения. Разработка Keras в основном поддерживается Google, а API Keras упакован в TensorFlow как tf.keras. Кроме того, Microsoft поддерживает серверную часть CNTK для Keras. Amazon AWS разрабатывает поддержку MXNet. Другие компании, предоставляющие поддержку, включают NVIDIA, Uber, Apple (через CoreML) и другие.

2. Наш существующий набор данных показан ниже.

009.jpg

Мы обучим модель CNN на основе этого набора данных, чтобы распознавать эти классифицированные изображения и сделать точность распознавания более 97%.

3. Структура каталогов нашего проекта CNN и Keras выглядит следующим образом:

├── dataset
│   ├── bulbasaur
│   ├── charmander
│   ├── mewtwo
│   ├── pikachu
│   └── squirtle
├── examples
│   ├── bulbasaur_001.jpeg
│   ├── bulbasaur_002.jpeg
│   ├── charmander_001.jpeg
│   ├── charmander_002.jpg
│   ├── mewtwo_001.jpg
│   ├── mewtwo_002.jpg
│   ├── pikachu_001.jpg
│   ├── pikachu_002.jpg
│   ├── squirtle_001.jpg
│   └── squirtle_002.jpg
├── pokedex
│   ├── pokedex
│   ├── pokedex.xcodeproj
│   ├── pokedexTests
│   └── pokedexUITests
├── pyimagesearch
│   ├── __pycache__
│   ├── __init__.py
│   └── smallervggnet.py
├── classify.py
├── coremlconverter.py
├── lb.pickle
├── plot.png
├── pokedex.mlmodel
├── pokedex.model
├── search_bing_api.py
└── train.py

У нас есть четыре каталога:

  1. В каталоге набора данных хранятся пять загруженных нами классифицированных изображений.Имя каждого подкаталога представляет категорию изображений в подкаталоге, которая будет использоваться в качестве метки изображения во время обучения модели.
  2. Каталог примеров содержит изображения, которые мы используем для тестирования модели.
  3. pyimagesearch, в котором хранится наш класс модели SmallerVGGNet, который мы будем делать в этом посте.
  4. Каталог pokedex, в котором хранится проект iOS-приложения, о котором мы расскажем в следующей статье.

В корневом каталоге есть еще 8 файлов

  1. plot.png : Наши графики точности и потерь при поездке/валидации, которые будут сгенерированы после прогона.
  2. lb.pickle: файл, сериализованный нашим LabelBinarizer, содержащий индекс метки и соответствующий механизм поиска имени метки.
  3. pokedex.model: это файл модели сверточной нейронной сети Keras, который мы сохранили после сериализации.
  4. train.py: мы используем этот скрипт для обучения модели Keras CNN, построения графика точности/потери обучения, сериализации модели и меток Keras CNN и сохранения на диск.
  5. classify.py: наш тестовый скрипт
  6. pokedex.model: модель Keras CNN, сгенерированная запуском обучающего скрипта.
  7. coremlconverter.py: скрипт преобразования модели, запустите этот скрипт, чтобы преобразовать модель Keras CNN в модель Core ML.
  8. pokedex.mlmodel: запустите модель Core ML, сгенерированную coremlconverter.py. Мы будем использовать в следующих статьях

4. Создайте модель SmallerVGGNet со следующей структурой.

002.png

Нажмите, чтобы просмотреть полную структуру модели

Создайте сценарий smallvggnet.py, сохраните его в каталоге pyimagesearch и вставьте следующий код.

# import the necessary packages
from keras.models import Sequential
from keras.layers.normalization import BatchNormalization
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dropout
from keras.layers.core import Dense
from keras import backend as K

class SmallerVGGNet:
	@staticmethod
	def build(width, height, depth, classes):
		# initialize the model along with the input shape to be
		# "channels last" and the channels dimension itself
		model = Sequential()
		inputShape = (height, width, depth)
		chanDim = -1

		# if we are using "channels first", update the input shape
		# and channels dimension
		if K.image_data_format() == "channels_first":
			inputShape = (depth, height, width)
			chanDim = 1

					# CONV => RELU => POOL
		model.add(Conv2D(32, (3, 3), padding="same",
			input_shape=inputShape))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(MaxPooling2D(pool_size=(3, 3)))
		model.add(Dropout(0.25))

				# (CONV => RELU) * 2 => POOL
		model.add(Conv2D(128, (3, 3), padding="same"))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(Conv2D(128, (3, 3), padding="same"))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(MaxPooling2D(pool_size=(2, 2)))
		model.add(Dropout(0.25))

		# first (and only) set of FC => RELU layers
		model.add(Flatten())
		model.add(Dense(1024))
		model.add(Activation("relu"))
		model.add(BatchNormalization())
		model.add(Dropout(0.5))

		# softmax classifier
		model.add(Dense(classes))
		model.add(Activation("softmax"))

		# return the constructed network architecture
		return model

Создайте новый скрипт __init__.py и сохраните его в каталоге pyimagesearch, чтобы Python мог распознать этот каталог как модуль.Мы будем использовать класс SmallerVGGNet, который мы написали в обучающем скрипте через модуль.

5. Реализуйте наш обучающий скрипт Keras CNN

Создайте новый скрипт train.py и вставьте следующий код

# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")

# import the necessary packages
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import Adam
from keras.preprocessing.image import img_to_array
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from pyimagesearch.smallervggnet import SmallerVGGNet
import matplotlib.pyplot as plt
from imutils import paths
import numpy as np
import argparse
import random
import pickle
import cv2
import os

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
	help="path to input dataset (i.e., directory of images)")
ap.add_argument("-m", "--model", required=True,
	help="path to output model")
ap.add_argument("-l", "--labelbin", required=True,
	help="path to output label binarizer")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
	help="path to output accuracy/loss plot")
args = vars(ap.parse_args())

# initialize the number of epochs to train for, initial learning rate,
# batch size, and image dimensions
EPOCHS = 100
INIT_LR = 1e-3
BS = 32
IMAGE_DIMS = (96, 96, 3)

# initialize the data and labels
data = []
labels = []

# grab the image paths and randomly shuffle them
print("[INFO] loading images...")
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)

# loop over the input images
for imagePath in imagePaths:
	# load the image, pre-process it, and store it in the data list
	image = cv2.imread(imagePath)
	image = cv2.resize(image, (IMAGE_DIMS[1], IMAGE_DIMS[0]))
	image = img_to_array(image)
	data.append(image)

	# extract the class label from the image path and update the
	# labels list
	label = imagePath.split(os.path.sep)[-2]
	labels.append(label)

# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
print("[INFO] data matrix: {:.2f}MB".format(
	data.nbytes / (1024 * 1000.0)))

# binarize the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)

# partition the data into training and testing splits using 80% of
# the data for training and the remaining 20% for testing
(trainX, testX, trainY, testY) = train_test_split(data,
	labels, test_size=0.2, random_state=42)

# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=25, width_shift_range=0.1,
	height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
	horizontal_flip=True, fill_mode="nearest")

# initialize the model
print("[INFO] compiling model...")
model = SmallerVGGNet.build(width=IMAGE_DIMS[1], height=IMAGE_DIMS[0],
	depth=IMAGE_DIMS[2], classes=len(lb.classes_))
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="categorical_crossentropy", optimizer=opt,
	metrics=["accuracy"])

# train the network
print("[INFO] training network...")
H = model.fit_generator(
	aug.flow(trainX, trainY, batch_size=BS),
	validation_data=(testX, testY),
	steps_per_epoch=len(trainX) // BS,
	epochs=EPOCHS, verbose=1)

# save the model to disk
print("[INFO] serializing network...")
model.save(args["model"])

# save the label binarizer to disk
print("[INFO] serializing label binarizer...")
f = open(args["labelbin"], "wb")
f.write(pickle.dumps(lb))
f.close()

# plot the training loss and accuracy
plt.style.use("ggplot")
plt.figure()
N = EPOCHS
plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, N), H.history["acc"], label="train_acc")
plt.plot(np.arange(0, N), H.history["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="upper left")
plt.savefig(args["plot"])

6. Обучите модель Keras CNN

Запустите следующую команду в терминале

$python train.py --dataset dataset --model pokedex.model --labelbin lb.pickle
Using TensorFlow backend.
[INFO] loading images...
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile

....

[INFO] data matrix: 165.67MB
[INFO] compiling model...

Epoch 1/100
19/19 [==============================] - 26s 1s/step - loss: 2.0648 - acc: 0.5099 - val_loss: 1.5347 - val_acc: 0.6818
Epoch 2/100
19/19 [==============================] - 22s 1s/step - loss: 1.2485 - acc: 0.6371 - val_loss: 0.9233 - val_acc: 0.7662
Epoch 3/100
19/19 [==============================] - 24s 1s/step - loss: 1.1295 - acc: 0.6336 - val_loss: 1.3024 - val_acc: 0.7013
Epoch 4/100
19/19 [==============================] - 23s 1s/step - loss: 1.0230 - acc: 0.6530 - val_loss: 1.1989 - val_acc: 0.6688
Epoch 5/100
19/19 [==============================] - 23s 1s/step - loss: 0.9785 - acc: 0.6683 - val_loss: 1.0938 - val_acc: 0.6818
Epoch 6/100
19/19 [==============================] - 22s 1s/step - loss: 0.9792 - acc: 0.6979 - val_loss: 1.1388 - val_acc: 0.7143
Epoch 7/100
19/19 [==============================] - 22s 1s/step - loss: 0.9480 - acc: 0.6963 - val_loss: 0.9233 - val_acc: 0.7468
Epoch 8/100
 4/19 [=====>........................] - ETA: 17s - loss: 0.6971 - acc: 0.7500

...

[INFO] serializing network...
[INFO] serializing label binarizer...

На MacBook Pro прохождение обучения занимает около получаса, и, наконец, в главном каталоге генерируются три файла pokedex.model, lb.pickle и plot.png. plot.png выглядит так

image

Мы видим, что точность обучения и точность проверки составляют около 97%.

7. Напишите тестовые сценарии

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

# import the necessary packages
from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np
import argparse
import imutils
import pickle
import cv2
import os

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", required=True,
	help="path to trained model model")
ap.add_argument("-l", "--labelbin", required=True,
	help="path to label binarizer")
ap.add_argument("-i", "--image", required=True,
	help="path to input image")
args = vars(ap.parse_args())

# load the image
image = cv2.imread(args["image"])
output = image.copy()

# pre-process the image for classification
image = cv2.resize(image, (96, 96))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)

# load the trained convolutional neural network and the label
# binarizer
print("[INFO] loading network...")
model = load_model(args["model"])
lb = pickle.loads(open(args["labelbin"], "rb").read())

# classify the input image
print("[INFO] classifying image...")
proba = model.predict(image)[0]
idx = np.argmax(proba)
label = lb.classes_[idx]

# we'll mark our prediction as "correct" of the input image filename
# contains the predicted label text (obviously this makes the
# assumption that you have named your testing image files this way)
filename = args["image"][args["image"].rfind(os.path.sep) + 1:]
correct = "correct" if filename.rfind(label) != -1 else "incorrect"

# build the label and draw the label on the image
label = "{}: {:.2f}% ({})".format(label, proba[idx] * 100, correct)
output = imutils.resize(output, width=400)
cv2.putText(output, label, (10, 25),  cv2.FONT_HERSHEY_SIMPLEX,
	0.7, (0, 255, 0), 2)

# show the output image
print("[INFO] {}".format(label))
cv2.imshow("Output", output)
cv2.waitKey(0)

8. Классификация изображений с использованием нашей модели Keras CNN.

тест пикачу изображения

$ python classify.py --model pokedex.model --labelbin lb.pickle --image examples/pikachu_001.jpg 
Using TensorFlow backend.
[INFO] loading network...
[INFO] classifying image...
[INFO] pikachu: 100.00% (correct)

004.jpg

Тестовые картинки чармандера

$ python classify.py --model pokedex.model --labelbin lb.pickle --image examples/pikachu_001.jpg 
Using TensorFlow backend.
[INFO] loading network...
[INFO] classifying image...
[INFO] charmander: 99.66% (correct)

005.jpg

9. Резюме

Мы обучили модель CNN с помощью Keras, используя всего около 1000 изображений, и точность теста достигла около 97%! Чтобы лучше идентифицировать покемонов, необходимо увеличить количество категорий изображений и количество изображений в каждой категории.

Отсканируйте код, чтобы подписаться на официальную учетную запись, ответьте «код обучения», вы можете получить код для обучения этой модели Keras CNN.

0010.jpg