python神經(jīng)網(wǎng)絡AlexNet分類模型訓練貓狗數(shù)據(jù)集
最近在做實驗室的工作,要用到分類模型,老板一星期催20次,我也是無語了,上有對策下有政策,在下先找個貓貓狗狗的數(shù)據(jù)集練練手,快樂極了
什么是AlexNet模型
AlexNet是2012年ImageNet競賽冠軍獲得者Hinton和他的學生Alex Krizhevsky設計的。也是在那年之后,更多的更深的神經(jīng)網(wǎng)絡被提出,比如優(yōu)秀的vgg,GoogLeNet。 這對于傳統(tǒng)的機器學習分類算法而言,已經(jīng)相當?shù)某錾?。如下是其網(wǎng)絡的結(jié)構(gòu),現(xiàn)在看來還是比較簡單的。


這是一個AlexNet的網(wǎng)絡結(jié)構(gòu)圖,其實并不復雜,很好的反應了AlexNet的結(jié)構(gòu):
1、一張原始圖片被resize到(224,224,3);
2、使用步長為4x4,大小為11的卷積核對圖像進行卷積,輸出的特征層為96層,輸出的shape為(55,55,96);
3、使用步長為2的最大池化層進行池化,此時輸出的shape為(27,27,96)
4、使用步長為1x1,大小為5的卷積核對圖像進行卷積,輸出的特征層為256層,輸出的shape為(27,27,256);
5、使用步長為2的最大池化層進行池化,此時輸出的shape為(13,13,256);
6、使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為384層,輸出的shape為(13,13,384);
7、使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為384層,輸出的shape為(13,13,384);
8、使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為256層,輸出的shape為(13,13,256);
9、使用步長為2的最大池化層進行池化,此時輸出的shape為(6,6,256);
10、兩個全連接層,最后輸出為1000類
最后輸出的就是每個類的預測。
從上面的圖也可以看出,其實最大的內(nèi)存與計算消耗在于第一個全連接層的實現(xiàn),它的參數(shù)有37M之多(這一點與VGG很類似,第一個全連接層參數(shù)巨多。),
訓練前準備
1、數(shù)據(jù)集處理
在數(shù)據(jù)集處理之前,首先要下載貓狗數(shù)據(jù)集,地址如下。
鏈接:https://pan.baidu.com/s/1IfN8Cvt60n64bbC2gF4Ung
提取碼:he9i
順便直接下載我的源代碼吧。
這里的源代碼包括了所有的代碼部分,訓練集需要自己下載,大概訓練2個小時就可以進行預測了。
本次教程準備使用model.fit_generator來訓練模型,在訓練模型之前,需要將數(shù)據(jù)集的內(nèi)容保存到一個TXT文件中,便于讀取。
txt文件的保存格式如下:
文件名;種類

具體操作步驟如下:
1、將訓練文件存到"./data/image/train/"目錄下。

2、調(diào)用如下代碼:
import os
photos = os.listdir("./data/image/train/")
# 該部分用于將
with open("data/dataset.txt","w") as f:
for photo in photos:
name = photo.split(".")[0]
if name=="cat":
f.write(photo + ";0\n")
elif name=="dog":
f.write(photo + ";1\n")
f.close()
就可以得到訓練數(shù)據(jù)集的文本文件。

2、創(chuàng)建Keras的AlexNet模型
該步就是按照AlexNet的結(jié)構(gòu)創(chuàng)建AlexNet的模型。我試了原大小的模型,發(fā)現(xiàn)根本呢不收斂,可能是模型太復雜而且貓狗的特征太少了(也許是我打開方式不對)……于是我就縮減了模型,每個卷積層的filter減半,全連接層減為1024.
from keras.models import Sequential
from keras.layers import Dense,Activation,Conv2D,MaxPooling2D,Flatten,Dropout,BatchNormalization
from keras.datasets import mnist
from keras.utils import np_utils
from keras.optimizers import Adam
def AlexNet(input_shape=(224,224,3),output_shape=2):
# AlexNet
model = Sequential()
# 使用步長為4x4,大小為11的卷積核對圖像進行卷積,輸出的特征層為96層,輸出的shape為(55,55,96);
# 所建模型后輸出為48特征層
model.add(
Conv2D(
filters=48,
kernel_size=(11,11),
strides=(4,4),
padding='valid',
input_shape=input_shape,
activation='relu'
)
)
model.add(BatchNormalization())
# 使用步長為2的最大池化層進行池化,此時輸出的shape為(27,27,96)
model.add(
MaxPooling2D(
pool_size=(3,3),
strides=(2,2),
padding='valid'
)
)
# 使用步長為1x1,大小為5的卷積核對圖像進行卷積,輸出的特征層為256層,輸出的shape為(27,27,256);
# 所建模型后輸出為128特征層
model.add(
Conv2D(
filters=128,
kernel_size=(5,5),
strides=(1,1),
padding='same',
activation='relu'
)
)
model.add(BatchNormalization())
# 使用步長為2的最大池化層進行池化,此時輸出的shape為(13,13,256);
model.add(
MaxPooling2D(
pool_size=(3,3),
strides=(2,2),
padding='valid'
)
)
# 使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為384層,輸出的shape為(13,13,384);
# 所建模型后輸出為192特征層
model.add(
Conv2D(
filters=192,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'
)
)
# 使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為384層,輸出的shape為(13,13,384);
# 所建模型后輸出為192特征層
model.add(
Conv2D(
filters=192,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'
)
)
# 使用步長為1x1,大小為3的卷積核對圖像進行卷積,輸出的特征層為256層,輸出的shape為(13,13,256);
# 所建模型后輸出為128特征層
model.add(
Conv2D(
filters=128,
kernel_size=(3,3),
strides=(1,1),
padding='same',
activation='relu'
)
)
# 使用步長為2的最大池化層進行池化,此時輸出的shape為(6,6,256);
model.add(
MaxPooling2D(
pool_size=(3,3),
strides=(2,2),
padding='valid'
)
)
# 兩個全連接層,最后輸出為1000類,這里改為2類
# 縮減為1024
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(output_shape, activation='softmax'))
return model
開始訓練
1、訓練的主函數(shù)
訓練的主函數(shù)主要包括如下部分:
1、讀取訓練用txt,并打亂,利用該txt進行訓練集和測試集的劃分。
2、建立AlexNet模型
3、設定模型保存的方式、學習率下降的方式、是否需要早停。
4、利用model.fit_generator訓練模型。
具體代碼如下:
if __name__ == "__main__":
# 模型保存的位置
log_dir = "./logs/"
# 打開數(shù)據(jù)集的txt
with open(r".\data\dataset.txt","r") as f:
lines = f.readlines()
# 打亂行,這個txt主要用于幫助讀取數(shù)據(jù)來訓練
# 打亂的數(shù)據(jù)更有利于訓練
np.random.seed(10101)
np.random.shuffle(lines)
np.random.seed(None)
# 90%用于訓練,10%用于估計。
num_val = int(len(lines)*0.1)
num_train = len(lines) - num_val
# 建立AlexNet模型
model = AlexNet()
# 保存的方式,3世代保存一次
checkpoint_period1 = ModelCheckpoint(
log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='acc',
save_weights_only=False,
save_best_only=True,
period=3
)
# 學習率下降的方式,acc三次不下降就下降學習率繼續(xù)訓練
reduce_lr = ReduceLROnPlateau(
monitor='acc',
factor=0.5,
patience=3,
verbose=1
)
# 是否需要早停,當val_loss一直不下降的時候意味著模型基本訓練完畢,可以停止
early_stopping = EarlyStopping(
monitor='val_loss',
min_delta=0,
patience=10,
verbose=1
)
# 交叉熵
model.compile(loss = 'categorical_crossentropy',
optimizer = Adam(lr=1e-3),
metrics = ['accuracy'])
# 一次的訓練集大小
batch_size = 64
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
# 開始訓練
model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=generate_arrays_from_file(lines[num_train:], batch_size),
validation_steps=max(1, num_val//batch_size),
epochs=150,
initial_epoch=0,
callbacks=[checkpoint_period1, reduce_lr])
model.save_weights(log_dir+'last1.h5')
model.fit_generator需要用到python的生成器來滾動讀取數(shù)據(jù),具體方法看第二步。
2、Keras數(shù)據(jù)生成器
Keras的數(shù)據(jù)生成器就是在一個while 1的無限循環(huán)中不斷生成batch大小的數(shù)據(jù)集。
def generate_arrays_from_file(lines,batch_size):
# 獲取總長度
n = len(lines)
i = 0
while 1:
X_train = []
Y_train = []
# 獲取一個batch_size大小的數(shù)據(jù)
for b in range(batch_size):
if i==0:
np.random.shuffle(lines)
name = lines[i].split(';')[0]
# 從文件中讀取圖像
img = cv2.imread(r".\data\image\train" + '/' + name)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img = img/255
X_train.append(img)
Y_train.append(lines[i].split(';')[1])
# 讀完一個周期后重新開始
i = (i+1) % n
# 處理圖像
X_train = utils.resize_image(X_train,(224,224))
X_train = X_train.reshape(-1,224,224,3)
Y_train = np_utils.to_categorical(np.array(Y_train),num_classes= 2)
yield (X_train, Y_train)
在其中用到了一些處理函數(shù),我存在了utils.py工具人文件中。
import matplotlib.image as mpimg
import numpy as np
import cv2
import tensorflow as tf
from tensorflow.python.ops import array_ops
def load_image(path):
# 讀取圖片,rgb
img = mpimg.imread(path)
# 將圖片修剪成中心的正方形
short_edge = min(img.shape[:2])
yy = int((img.shape[0] - short_edge) / 2)
xx = int((img.shape[1] - short_edge) / 2)
crop_img = img[yy: yy + short_edge, xx: xx + short_edge]
return crop_img
def resize_image(image, size):
with tf.name_scope('resize_image'):
images = []
for i in image:
i = cv2.resize(i, size)
images.append(i)
images = np.array(images)
return images
def print_answer(argmax):
with open("./data/model/index_word.txt","r",encoding='utf-8') as f:
synset = [l.split(";")[1][:-1] for l in f.readlines()]
print(synset[argmax])
return synset[argmax]
3、主訓練函數(shù)全部代碼
大家可以整體看看哈:
from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStopping
from keras.utils import np_utils
from keras.optimizers import Adam
from model.AlexNet import AlexNet
import numpy as np
import utils
import cv2
from keras import backend as K
K.set_image_dim_ordering('tf')
def generate_arrays_from_file(lines,batch_size):
# 獲取總長度
n = len(lines)
i = 0
while 1:
X_train = []
Y_train = []
# 獲取一個batch_size大小的數(shù)據(jù)
for b in range(batch_size):
if i==0:
np.random.shuffle(lines)
name = lines[i].split(';')[0]
# 從文件中讀取圖像
img = cv2.imread(r".\data\image\train" + '/' + name)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img = img/255
X_train.append(img)
Y_train.append(lines[i].split(';')[1])
# 讀完一個周期后重新開始
i = (i+1) % n
# 處理圖像
X_train = utils.resize_image(X_train,(224,224))
X_train = X_train.reshape(-1,224,224,3)
Y_train = np_utils.to_categorical(np.array(Y_train),num_classes= 2)
yield (X_train, Y_train)
if __name__ == "__main__":
# 模型保存的位置
log_dir = "./logs/"
# 打開數(shù)據(jù)集的txt
with open(r".\data\dataset.txt","r") as f:
lines = f.readlines()
# 打亂行,這個txt主要用于幫助讀取數(shù)據(jù)來訓練
# 打亂的數(shù)據(jù)更有利于訓練
np.random.seed(10101)
np.random.shuffle(lines)
np.random.seed(None)
# 90%用于訓練,10%用于估計。
num_val = int(len(lines)*0.1)
num_train = len(lines) - num_val
# 建立AlexNet模型
model = AlexNet()
# 保存的方式,3世代保存一次
checkpoint_period1 = ModelCheckpoint(
log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',
monitor='acc',
save_weights_only=False,
save_best_only=True,
period=3
)
# 學習率下降的方式,acc三次不下降就下降學習率繼續(xù)訓練
reduce_lr = ReduceLROnPlateau(
monitor='acc',
factor=0.5,
patience=3,
verbose=1
)
# 是否需要早停,當val_loss一直不下降的時候意味著模型基本訓練完畢,可以停止
early_stopping = EarlyStopping(
monitor='val_loss',
min_delta=0,
patience=10,
verbose=1
)
# 交叉熵
model.compile(loss = 'categorical_crossentropy',
optimizer = Adam(lr=1e-3),
metrics = ['accuracy'])
# 一次的訓練集大小
batch_size = 64
print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))
# 開始訓練
model.fit_generator(generate_arrays_from_file(lines[:num_train], batch_size),
steps_per_epoch=max(1, num_train//batch_size),
validation_data=generate_arrays_from_file(lines[num_train:], batch_size),
validation_steps=max(1, num_val//batch_size),
epochs=150,
initial_epoch=0,
callbacks=[checkpoint_period1, reduce_lr, early_stopping ])
model.save_weights(log_dir+'last1.h5')
訓練結(jié)果
在完成上述的一大堆內(nèi)容的配置后就可以開始訓練了,所有文件的構(gòu)架如下:

……訓練是真的慢
…… Epoch 36/50 175/175 [==============================] - 219s 1s/step - loss: 0.0124 - acc: 0.9962 - val_loss: 0.5256 - val_acc: 0.9034 Epoch 37/50 175/175 [==============================] - 178s 1s/step - loss: 0.0028 - acc: 0.9991 - val_loss: 0.7911 - val_acc: 0.9034 Epoch 38/50 175/175 [==============================] - 174s 992ms/step - loss: 0.0047 - acc: 0.9987 - val_loss: 0.6690 - val_acc: 0.8910 Epoch 39/50 175/175 [==============================] - 241s 1s/step - loss: 0.0044 - acc: 0.9986 - val_loss: 0.6518 - val_acc: 0.9001 Epoch 40/50 142/175 [=======================>......] - ETA: 1:07 - loss: 0.0074 - acc: 0.9976
差不多是這樣,在測試集上有90的準確度呢!我們拿一個模型預測一下看看。
import numpy as np
import utils
import cv2
from keras import backend as K
from model.AlexNet import AlexNet
K.set_image_dim_ordering('tf')
if __name__ == "__main__":
model = AlexNet()
# 載入模型
model.load_weights("./logs/ep039-loss0.004-val_loss0.652.h5")
# 載入圖片,并處理
img = cv2.imread("./Test.jpg")
img_RGB = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img_nor = img_RGB/255
img_nor = np.expand_dims(img_nor,axis = 0)
img_resize = utils.resize_image(img_nor,(224,224))
# 預測~!
#utils.print_answer(np.argmax(model.predict(img)))
print(utils.print_answer(np.argmax(model.predict(img_resize))))
cv2.imshow("ooo",img)
cv2.waitKey(0)
預測結(jié)果為:
貓貓

大功告成。
以上就是python神經(jīng)網(wǎng)絡AlexNet分類模型訓練貓狗數(shù)據(jù)集的詳細內(nèi)容,更多關(guān)于AlexNet分類模型訓練貓狗數(shù)據(jù)集的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python scikit-learn 做線性回歸的示例代碼
本篇文章主要介紹了Python scikit-learn 做線性回歸的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
Python高級排序sort()函數(shù)使用技巧實例探索
本文詳細介紹sort()函數(shù)的使用,包括基本排序、自定義排序、逆序排序等多種情況,并提供大量示例代碼,以幫助你充分理解和掌握這一函數(shù)的用法,探索更多sort()排序函數(shù)的作用2024-01-01
OpenCV2.3.1+Python2.7.3+Numpy等的配置解析
這篇文章主要介紹了OpenCV2.3.1+Python2.7.3+Numpy等的配置解析,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
Python如何查看并打印matplotlib中所有的colormap(cmap)類型
這篇文章主要介紹了Python如何查看并打印matplotlib中所有的colormap(cmap)類型,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11

