中國(guó)制造網(wǎng) 做網(wǎng)站費(fèi)用網(wǎng)站測(cè)試的內(nèi)容有哪些
文章目錄
- 整體流程
- 數(shù)據(jù)加載與預(yù)處理
- 搭建網(wǎng)絡(luò)模型
- 優(yōu)化網(wǎng)絡(luò)模型
- 學(xué)習(xí)率
- Drop-out操作
- 權(quán)重初始化方法對(duì)比
- 正則化
- 加載模型進(jìn)行測(cè)試
實(shí)戰(zhàn):利用Keras框架搭建神經(jīng)網(wǎng)絡(luò)模型實(shí)現(xiàn)基本圖像分類識(shí)別,使用自己的數(shù)據(jù)集進(jìn)行訓(xùn)練測(cè)試。
問(wèn):為什么選擇Keras?
答:使用Keras便捷快速。用起來(lái)簡(jiǎn)單,入門容易,上手快。沒(méi)有tensorflow那么復(fù)雜的規(guī)范。
整體流程
- 讀取數(shù)據(jù)
- 數(shù)據(jù)預(yù)處理
- 切分?jǐn)?shù)據(jù)集(分為訓(xùn)練集和測(cè)試集)
- 搭建網(wǎng)絡(luò)模型(初始化參數(shù))
- 訓(xùn)練網(wǎng)絡(luò)模型
- 評(píng)估測(cè)試模型(通過(guò)對(duì)比不同參數(shù)下?lián)p失函數(shù)不斷優(yōu)化模型)
- 保存模型到本地
(1)手動(dòng)配置參數(shù),設(shè)置數(shù)據(jù)存儲(chǔ)路徑、模型保存路徑、圖片保存路徑
# 輸入?yún)?shù),手動(dòng)設(shè)置數(shù)據(jù)存儲(chǔ)路徑、模型保存路徑、圖片保存路徑等
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,help="path to output trained model")
ap.add_argument("-l", "--label-bin", required=True,help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,help="path to output accuracy/loss plot")
args = vars(ap.parse_args())
數(shù)據(jù)加載與預(yù)處理
# 拿到圖像數(shù)據(jù)路徑,方便后續(xù)讀取
imagePaths = sorted(list(utils_paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)
# 數(shù)據(jù)洗牌前設(shè)置隨機(jī)種子確保后面調(diào)參過(guò)程中訓(xùn)練數(shù)據(jù)集一樣# 遍歷讀取數(shù)據(jù)
for imagePath in imagePaths:# 讀取圖像數(shù)據(jù),由于使用神經(jīng)網(wǎng)絡(luò),需要輸入數(shù)據(jù)給定成一維image = cv2.imread(imagePath)# 而最初獲取的圖像數(shù)據(jù)是三維的,則需要將三維數(shù)據(jù)進(jìn)行拉長(zhǎng)image = cv2.resize(image, (32, 32)).flatten()data.append(image)# 讀取標(biāo)簽,通過(guò)讀取數(shù)據(jù)存儲(chǔ)位置文件夾來(lái)判斷圖片標(biāo)簽label = imagePath.split(os.path.sep)[-2]labels.append(label)# scale圖像數(shù)據(jù),歸一化
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)# 轉(zhuǎn)換標(biāo)簽,one-hot格式
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
數(shù)據(jù)預(yù)處理:①通過(guò)數(shù)據(jù)除以255進(jìn)行數(shù)據(jù)歸一化;②對(duì)數(shù)據(jù)標(biāo)簽進(jìn)行格式轉(zhuǎn)換。
搭建網(wǎng)絡(luò)模型
- 創(chuàng)建序列結(jié)構(gòu)
model = Sequential()
- 添加全連接層
- 第一層全連接層Dense設(shè)計(jì)512個(gè)神經(jīng)元,當(dāng)前輸入特征個(gè)數(shù)(輸入神經(jīng)元個(gè)數(shù))為3072,設(shè)置激活函數(shù)為"relu";
- 第二層設(shè)計(jì)256個(gè)神經(jīng)元;
- 第三層設(shè)計(jì)類別數(shù)個(gè)神經(jīng)元(即3個(gè)),并作softmax操作得到最終分類類別。
# 第一層
model.add(Dense(512, input_shape=(3072,),activation="relu"))
# 第二層
model.add(Dense(256, activation="relu",))
# 第三層
model.add(Dense(len(lb.classes_), activation="softmax",))
- 初始化參數(shù)
# 學(xué)習(xí)率
INIT_LR = 0.01
# 迭代次數(shù)
EPOCHS = 200
- 訓(xùn)練網(wǎng)絡(luò)模型
# 給定損失函數(shù)和評(píng)估方法
opt = SGD(lr=INIT_LR) # 指定優(yōu)化器為梯度下降的優(yōu)化器
model.compile(loss="categorical_crossentropy", optimizer=opt,metrics=["accuracy"])# 訓(xùn)練網(wǎng)絡(luò)模型
H = model.fit(trainX, trainY, validation_data=(testX, testY),epochs=EPOCHS, batch_size=32)
- 測(cè)試網(wǎng)絡(luò)模型
使用上面訓(xùn)練所得網(wǎng)絡(luò)模型對(duì)測(cè)試集進(jìn)行預(yù)測(cè),并對(duì)比預(yù)測(cè)解國(guó)和數(shù)據(jù)集真實(shí)結(jié)果打印結(jié)果報(bào)告(包括準(zhǔn)確率、recall、f1-score),并將損失函數(shù)以折線圖的效果直觀展示出來(lái)
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),predictions.argmax(axis=1), target_names=lb.classes_))
- 評(píng)估結(jié)果
從損失函數(shù)圖像中可看出,模型出現(xiàn)明顯過(guò)擬合現(xiàn)象,故而該初始參數(shù)所構(gòu)建的模型效果較差,需要通過(guò)調(diào)參優(yōu)化模型。
優(yōu)化網(wǎng)絡(luò)模型
學(xué)習(xí)率
對(duì)比學(xué)習(xí)率為0.01和0.001的損失函數(shù)圖像。
train_loss與val_loss之間差異仍然存在,但是可看出學(xué)習(xí)率越大,過(guò)擬合現(xiàn)象越明顯。
Drop-out操作
Dropout操作:在搭建網(wǎng)絡(luò)模型中,通過(guò)設(shè)置一0到1范圍內(nèi)的參數(shù)從而防止過(guò)擬合。
權(quán)重初始化方法對(duì)比
(1)RandomNormal隨機(jī)高斯初始化
kernel_initializer =initializers.random_normal(mean=0.0,stddev=0.05)
model.add(Dense(512, input_shape=(3072,),activation="relu",kernel_initializer =initializers.random_normal(mean=0.0,stddev=0.05)))
model.add(Dense(256, activation="relu",kernel_initializer =initializers.random_normal(mean=0.0,stddev=0.05)))
model.add(Dense(len(lb.classes_), activation="softmax",kernel_initializer =initializers.random_normal(mean=0.0,stddev=0.05)))
圖中可看出,添加RandomNormal初始化后,過(guò)擬合現(xiàn)象減弱了一丟丟。
(2)TruncatedNormal截?cái)?/p>
kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)
相比于正常高斯分布截?cái)嗔藘蛇?#xff0c;只取小于2倍stddev的值
model.add(Dense(512, input_shape=(3072,), activation="relu" ,kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05)))
model.add(Dense(256, activation="relu",kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05)))
model.add(Dense(len(lb.classes_), activation="softmax",kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05)))
對(duì)比stddev取不同值時(shí)的loss函數(shù)圖可得,TruncatedNormal中stddev值越小,過(guò)擬合風(fēng)險(xiǎn)越低,模型效果越好。TruncatedNormal消除過(guò)擬合的效果RandomNormal好。
正則化
kernel_regularizer=regularizers.l2(0.01)
正則化后,損失函數(shù)loss = 初始loss + aR(W)。正則化懲罰W,讓穩(wěn)定的W減少過(guò)擬合。
model.add(Dense(512, 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(Dense(256, activation="relu",kernel_initializer = initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None),kernel_regularizer=regularizers.l2(0.01)))
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)))
對(duì)比正則化前后取迭代150到200的loss波動(dòng)圖,可發(fā)現(xiàn)正則化后雖然開(kāi)始時(shí)loss值較大,但后期過(guò)擬合現(xiàn)象有明顯減弱
再對(duì)比正則化參數(shù)l2 = 0.01和0.05的結(jié)果可得,l2越大,W的懲罰力度越大,過(guò)擬合風(fēng)險(xiǎn)越小
加載模型進(jìn)行測(cè)試
# 導(dǎo)入所需工具包
from keras.models import load_model
import argparse
import pickle
import cv2# 設(shè)置輸入?yún)?shù)
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to input image we are going to classify")
ap.add_argument("-m", "--model", required=True,help="path to trained Keras model")
ap.add_argument("-l", "--label-bin", required=True,help="path to label binarizer")
ap.add_argument("-w", "--width", type=int, default=28,help="target spatial dimension width")
ap.add_argument("-e", "--height", type=int, default=28,help="target spatial dimension height")
ap.add_argument("-f", "--flatten", type=int, default=-1,help="whether or not we should flatten the image")
args = vars(ap.parse_args())# 加載測(cè)試數(shù)據(jù)并進(jìn)行相同預(yù)處理操作
image = cv2.imread(args["image"])
output = image.copy()
image = cv2.resize(image, (args["width"], args["height"]))# scale the pixel values to [0, 1]
image = image.astype("float") / 255.0# 對(duì)圖像進(jìn)行拉平操作
image = image.flatten()
image = image.reshape((1, image.shape[0]))# 讀取模型和標(biāo)簽
print("[INFO] loading network and label binarizer...")
model = load_model(args["model"])
lb = pickle.loads(open(args["label_bin"], "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é)果畫(huà)出來(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)
分類結(jié)果:
通過(guò)預(yù)測(cè)結(jié)果可得:該模型在預(yù)測(cè)貓上存在較大誤差,在預(yù)測(cè)熊貓上較為準(zhǔn)確。或許改進(jìn)增加迭代次數(shù)可進(jìn)一步優(yōu)化模型。