1.準(zhǔn)備數(shù)據(jù)集:
本次以圖像三分類為例捺弦,準(zhǔn)備貓沐绒、狗剖毯、熊貓三種動(dòng)物的圖片數(shù)據(jù)(每種各1000張圖片),依次存放在'./dataset/cats'堂淡、'./dataset/dogs'馋缅、'./dataset/pandas'文件夾中。
2.訓(xùn)練模型:
# 導(dǎo)入所需工具包
import matplotlib
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from keras.models import Sequential
from keras.layers import Dropout
from keras.layers.core import Dense
from keras.optimizers import SGD
from keras import initializers
from keras import regularizers
import utils_paths # 主要用于圖像路徑處理操作绢淀,具體代碼參考最后的附錄
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os
print("------開始讀取數(shù)據(jù)------")
data = []
labels = []
# 拿到圖像數(shù)據(jù)路徑萤悴,方便后續(xù)讀取
imagePaths = sorted(list(utils_paths.list_images('./dataset')))
random.seed(42)
random.shuffle(imagePaths)
# 遍歷讀取數(shù)據(jù)
for imagePath in imagePaths:
# 讀取圖像數(shù)據(jù),由于使用神經(jīng)網(wǎng)絡(luò)皆的,需要給拉平成一維
image = cv2.imread(imagePath)
image = cv2.resize(image, (32, 32)).flatten()
data.append(image)
# 讀取標(biāo)簽
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# 對(duì)圖像數(shù)據(jù)做scale操作
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
# 切分?jǐn)?shù)據(jù)集
(trainX, testX, trainY, testY) = train_test_split(data,
labels, test_size=0.25, random_state=42)
# 轉(zhuǎn)換標(biāo)簽為one-hot encoding格式
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
# 構(gòu)造網(wǎng)絡(luò)模型結(jié)構(gòu):本次為3072-128-64-3
model = Sequential()
# kernel_regularizer=regularizers.l2(0.01) L2正則化項(xiàng)
# initializers.TruncatedNormal 初始化參數(shù)方法覆履,截?cái)喔咚狗植?model.add(Dense(128, input_shape=(3072,), activation="relu" ,kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None),kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(0.5))
model.add(Dense(64, activation="relu",kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None),kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(0.5))
model.add(Dense(len(lb.classes_), activation="softmax",kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None),kernel_regularizer=regularizers.l2(0.01)))
# 初始化參數(shù)
INIT_LR = 0.001
EPOCHS = 2000
# 模型編譯
print("------準(zhǔn)備訓(xùn)練網(wǎng)絡(luò)------")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
metrics=["accuracy"])
# 擬合模型
H = model.fit(trainX, trainY, validation_data=(testX, testY),
epochs=EPOCHS, batch_size=32)
# 測(cè)試網(wǎng)絡(luò)模型
print("------正在評(píng)估模型------")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
predictions.argmax(axis=1), target_names=lb.classes_))
# 繪制結(jié)果曲線
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N[1500:], H.history["accuracy"][1500:], label="train_acc")
plt.plot(N[1500:], H.history["val_accuracy"][1500:], label="val_acc")
plt.title("Training and Validation Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Accuracy")
plt.legend()
plt.savefig('./output/simple_nn_plot_acc.png')
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.title("Training and Validation Loss (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss")
plt.legend()
plt.savefig('./output/simple_nn_plot_loss.png')
# 保存模型到本地
print("------正在保存模型------")
model.save('././output/simple_nn.model')
f = open('./output/simple_nn_lb.pickle', "wb") # 保存標(biāo)簽數(shù)據(jù)
f.write(pickle.dumps(lb))
f.close()
運(yùn)行得到如下文件數(shù)據(jù):
3.加載模型進(jìn)行預(yù)測(cè):
# 導(dǎo)入所需工具包
from keras.models import load_model
import argparse
import pickle
import cv2
# 加載測(cè)試數(shù)據(jù)并進(jìn)行相同預(yù)處理操作
image = cv2.imread('./cs_image/panda.jpg')
output = image.copy()
image = cv2.resize(image, (32, 32))
# scale圖像數(shù)據(jù)
image = image.astype("float") / 255.0
# 對(duì)圖像進(jìn)行拉平操作
image = image.flatten()
image = image.reshape((1, image.shape[0]))
# 讀取模型和標(biāo)簽
print("------讀取模型和標(biāo)簽------")
model = load_model('./output/simple_nn.model')
lb = pickle.loads(open('./output/simple_nn_lb.pickle', "rb").read())
# 預(yù)測(cè)
preds = model.predict(image)
# 得到預(yù)測(cè)結(jié)果以及其對(duì)應(yīng)的標(biāo)簽
i = preds.argmax(axis=1)[0]
label = lb.classes_[i]
# 在圖像中把結(jié)果畫出來(lái)
text = "{}: {:.2f}%".format(label, preds[0][i] * 100)
cv2.putText(output, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,(0, 0, 255), 2)
# 繪圖
cv2.imshow("Image", output)
cv2.waitKey(0)
最終得到預(yù)測(cè)結(jié)果:
4.附錄:
utils_paths.py
代碼如下:
import os
image_types = (".jpg", ".jpeg", ".png", ".bmp", ".tif", ".tiff")
def list_images(basePath, contains=None):
# 返回有效的圖片路徑數(shù)據(jù)集
return list_files(basePath, validExts=image_types, contains=contains)
def list_files(basePath, validExts=None, contains=None):
# 遍歷圖片數(shù)據(jù)目錄,生成每張圖片的路徑
for (rootDir, dirNames, filenames) in os.walk(basePath):
# 循環(huán)遍歷當(dāng)前目錄中的文件名
for filename in filenames:
# if the contains string is not none and the filename does not contain
# the supplied string, then ignore the file
if contains is not None and filename.find(contains) == -1:
continue
# 通過(guò)確定.的位置费薄,從而確定當(dāng)前文件的文件擴(kuò)展名
ext = filename[filename.rfind("."):].lower()
# 檢查文件是否為圖像硝全,是否應(yīng)進(jìn)行處理
if validExts is None or ext.endswith(validExts):
# 構(gòu)造圖像路徑
imagePath = os.path.join(rootDir, filename)
yield imagePath
卷積神經(jīng)網(wǎng)絡(luò)可以參看使用Keras訓(xùn)練自己的數(shù)據(jù)集——以圖像多分類為例(基于卷積神經(jīng)網(wǎng)絡(luò))