2018年9月19日筆記
Keras官方github鏈接:https://github.com/keras-team/keras
官方的口號是Keras: Deep Learning for humans渴频,中文叫做Keras是給人使用的深度學習開發(fā)框架扳剿,其意義是Keras是一個高度集成的開發(fā)框架期吓,其中的API調用很簡單。
Keras用python語言編寫,在tensorflow、cntk专控、theano這3種框架的基礎上運行。
本文是學習github源碼的筆記遏餐,源碼鏈接:https://github.com/keras-team/keras/blob/master/examples/cifar10_cnn.py
0.編程環(huán)境
操作系統(tǒng):Win10
python版本:3.6
tensorflow-gpu版本:1.6
keras版本:2.1.5
1.配置環(huán)境
先安裝tenforflow的GPU版本伦腐,再安裝keras。
使用卷積神經網(wǎng)絡模型要求有較高的機器配置失都,如果使用CPU版tensorflow會花費大量時間柏蘑。
讀者在有nvidia顯卡的情況下,安裝GPU版tensorflow會提高計算速度50倍粹庞。
安裝教程鏈接:https://blog.csdn.net/qq_36556893/article/details/79433298
如果沒有nvidia顯卡咳焚,但有visa信用卡,請閱讀我的另一篇文章《在谷歌云服務器上搭建深度學習平臺》庞溜,鏈接:http://www.reibang.com/p/893d622d1b5a
2.完整代碼
此章給讀者能夠直接運行的完整代碼革半,使讀者有編程結果的感性認識。
如果下面一段代碼運行成功强缘,則說明安裝tensorflow環(huán)境成功督惰。
想要了解代碼的具體實現(xiàn)細節(jié),請閱讀后面的章節(jié)旅掂。
from keras.datasets import mnist
from keras.utils import to_categorical
train_X, train_y = mnist.load_data()[0]
train_X = train_X.reshape(-1, 28, 28, 1)
train_X = train_X.astype('float32')
train_X /= 255
train_y = to_categorical(train_y, 10)
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dropout, Dense
from keras.losses import categorical_crossentropy
from keras.optimizers import Adadelta
model = Sequential()
model.add(Conv2D(32, (5,5), activation='relu', input_shape=[28, 28, 1]))
model.add(Conv2D(64, (5,5), activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss=categorical_crossentropy,
optimizer=Adadelta(),
metrics=['accuracy'])
batch_size = 100
epochs = 8
model.fit(train_X, train_y,
batch_size=batch_size,
epochs=epochs)
test_X, test_y = mnist.load_data()[1]
test_X = test_X.reshape(-1, 28, 28, 1)
test_X = test_X.astype('float32')
test_X /= 255
test_y = to_categorical(test_y, 10)
loss, accuracy = model.evaluate(test_X, test_y, verbose=1)
print('loss:%.4f accuracy:%.4f' %(loss, accuracy))
上面一段代碼的運行結果如下:
Epoch 1/8
60000/60000 [==============================] - 11s 190us/step - loss: 0.2232 - acc: 0.9306
Epoch 2/8
60000/60000 [==============================] - 9s 147us/step - loss: 0.0818 - acc: 0.9756
Epoch 3/8
60000/60000 [==============================] - 9s 148us/step - loss: 0.0633 - acc: 0.9817
Epoch 4/8
60000/60000 [==============================] - 9s 147us/step - loss: 0.0538 - acc: 0.9843
Epoch 5/8
60000/60000 [==============================] - 9s 147us/step - loss: 0.0468 - acc: 0.9861
Epoch 6/8
60000/60000 [==============================] - 9s 148us/step - loss: 0.0428 - acc: 0.9875
Epoch 7/8
60000/60000 [==============================] - 9s 147us/step - loss: 0.0405 - acc: 0.9880
Epoch 8/8
60000/60000 [==============================] - 9s 148us/step - loss: 0.0376 - acc: 0.9888
10000/10000 [==============================] - 1s 111us/step
loss:0.0223 accuracy:0.9930
epoch中文叫做新紀元赏胚,每經過1次epoch,即模型訓練遍歷所有樣本1次;
上文中epoch設置為8,即模型訓練遍歷所有樣本8次皿渗;
batch_size設置為100,即每次模型訓練使用的樣本數(shù)量為100典勇;
每經過1次epoch,模型遍歷訓練集的60000個樣本叮趴,每次訓練使用100個樣本割笙,即模型訓練600次,即損失函數(shù)經過600次批量梯度下降。
從上面的運行結果可以看出伤溉,經過8次epoch般码,模型在測試集的準確率到達0.9930。
3.數(shù)據(jù)觀察
3.1 使用keras庫中的方法加載數(shù)據(jù)
本文使用keras.datasets庫的mnist.py文件中的load_data方法加載數(shù)據(jù)乱顾。
本文作者使用anaconda集成開發(fā)環(huán)境板祝,keras.datasets庫的mnist.py文件路徑:C:\ProgramData\Anaconda3\Lib\site-packages\keras\datasets
,如下圖所示:
mnist.py文件中代碼如下:
from ..utils.data_utils import get_file
import numpy as np
def load_data(path='mnist.npz'):
path = get_file(path,
origin='https://s3.amazonaws.com/img-datasets/mnist.npz',
file_hash='8a61469f7ea1b51cbae51d4f78837e45')
f = np.load(path)
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
f.close()
return (x_train, y_train), (x_test, y_test)
第1行代碼導入此文件上一級目錄utils.data_tuils路徑下的get_file方法走净;
第2行代碼導入numpy庫券时,起別名np;
第4-12行代碼定義load_data方法伏伯;
第5-7行代碼會檢查keras的緩存文件夾中是否有mnist.npz文件橘洞,如果沒有則下載第6行代碼的url鏈接指向的資源;
keras緩存文件夾是用戶路徑的.keras
文件夾舵鳞,舉例本文作者的keras緩存文件夾路徑:C:\Users\Administrator\.keras\datasets
在第一次運行l(wèi)oad_data方法時震檩,會從網(wǎng)絡上下載mnist.npz文件琢蛤,之后運行則不需要下載蜓堕。
mnist.npz文件在keras緩存文件夾的情況如下圖所示:
3.2 查看數(shù)據(jù)情況
從3.1節(jié)mnist.py文件的代碼可以看出,load_data方法返回值是一個元組博其,其中有2個元素套才。
第1個元素是訓練集的數(shù)據(jù),第2個元素是測試集的數(shù)據(jù)慕淡;
訓練集的數(shù)據(jù)是1個元組背伴,里面包括2個元素,第1個元素是特征矩陣峰髓,第2個元素是預測目標值傻寂;
測試集的數(shù)據(jù)是1個元組,里面包括2個元素携兵,第1個元素是特征矩陣疾掰,第2個元素是預測目標值。
第1種寫法:
from keras.datasets import mnist
train_data = mnist.load_data()[0]
test_data = mnist.load_data()[1]
train_X , train_y = train_data
test_X, test_y = test_data
print(train_X.shape, train_y.shape)
print(test_X.shape, test_y.shape)
第2種寫法:
from keras.datasets import mnist
(train_X, train_y), (test_X, test_y) = mnist.load_data()
print(train_X.shape, train_y.shape)
print(test_X.shape, test_y.shape)
上面兩種代碼寫法的運行結果相同徐紧,讀者可以通過對比體會如何使用python中的元組静檬。
(60000, 28, 28) (60000,)
(10000, 28, 28) (10000,)
從上面的運行結果可以看出,訓練集總共有60000個樣本并级,測試集總共有10000個樣本拂檩,每個圖片樣本的像素大小是28*28
。
3.3 查看手寫數(shù)字圖
運行下面代碼成功的前提是讀者保持前文代碼中的變量名嘲碧。
本文作者按照中國人的思維習慣稻励,喜歡將變量內容的主體放在變量命名的后邊。
例如訓練集的特征矩陣愈涩,主體是特征矩陣望抽,本文作者將其變量命名為train_X至非。
外國人的思維習慣,習慣將變量內容的主體放在變量命名的前面糠聪。
例如訓練集的特征矩陣荒椭,主體是特征矩陣,外國人將其變量命名為X_train舰蟆。
從訓練集train_X中選取一部分樣本查看圖片內容趣惠,即調用random的sample方法隨機獲得一部分樣本,代碼如下:
import matplotlib.pyplot as plt
import math
import random
def drawDigit(position, image, title):
plt.subplot(*position)
plt.imshow(image.reshape(-1, 28), cmap='gray_r')
plt.axis('off')
plt.title(title)
def batchDraw(batch_size):
selected_index = random.sample(range(len(train_y)), k=batch_size)
images,labels = train_X[selected_index], train_y[selected_index]
image_number = images.shape[0]
row_number = math.ceil(image_number ** 0.5)
column_number = row_number
plt.figure(figsize=(row_number, column_number))
for i in range(row_number):
for j in range(column_number):
index = i * column_number + j
if index < image_number:
position = (row_number, column_number, index+1)
image = images[index]
title = 'actual:%d' %(labels[index])
drawDigit(position, image, title)
batchDraw(100)
plt.show()
上面一段代碼的運行結果如下圖所示身害,本文作者對難以辨認的數(shù)字做了紅色方框標注:
4.數(shù)據(jù)準備
from keras.datasets import mnist
from keras.utils import to_categorical
train_X, train_y = mnist.load_data()[0]
train_X = train_X.reshape(-1, 28, 28, 1)
train_X = train_X.astype('float32')
train_X /= 255
train_y = to_categorical(train_y, 10)
第1行代碼從keras.datasets庫中導入mnist.py文件味悄;
第2行代碼從keras.utils庫中導入to_categorical方法;
第4行代碼獲取訓練集的特征矩陣賦值給變量train_X塌鸯,獲取訓練集的預測目標值賦值給變量train_y侍瑟;
第5-7行代碼將原始的特征矩陣做數(shù)據(jù)處理形成模型需要的數(shù)據(jù);
第8行代碼使用keras中的方法對數(shù)字的標簽分類做One-Hot編碼丙猬。
5.搭建神經網(wǎng)絡
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dropout, Dense
from keras.losses import categorical_crossentropy
from keras.optimizers import Adadelta
model = Sequential()
model.add(Conv2D(32, (5,5), activation='relu', input_shape=[28, 28, 1]))
model.add(Conv2D(64, (5,5), activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss=categorical_crossentropy,
optimizer=Adadelta(),
metrics=['accuracy'])
第1-4行代碼導入keras中的模型涨颜、層、損失函數(shù)茧球、優(yōu)化器庭瑰。
第6行代碼使用keras.model庫的Sequential方法實例化模型對象;
第7抢埋、8行代碼是模型中添加卷積層弹灭;
第9行代碼是模型中添加最大池化層;
第10行代碼是模型中的數(shù)據(jù)矩陣展平揪垄;
第11行代碼是模型中添加dropout操作穷吮;
第12行代碼是模型中添加全連接層;
第13行代碼是模型中添加dropout操作饥努;
第14行代碼是模型中添加全連接層捡鱼,且使用relu作為激活函數(shù),即最終分類結果肪凛;
第16-18行代碼為模型指定損失函數(shù)堰汉,優(yōu)化器,評判指標伟墙。
6.模型訓練
batch_size = 100
epochs = 8
model.fit(train_X, train_y,
batch_size=batch_size,
epochs=epochs)
第1行代碼設置批量梯度下降時的batch_size為100翘鸭;
第2行代碼設置遍歷所有樣本的次數(shù)epoch為8,讀者可以自行嘗試不同的值戳葵,本文作者在設置為8時取得較好的收斂效果就乓;
第3-5行代碼調用模型對象的fit方法開始模型訓練,fit方法需要4個參數(shù),第1個參數(shù)是特征矩陣生蚁,第2個參數(shù)是預測目標值噩翠,第3個關鍵字參數(shù)batch_size,第4個關鍵字參數(shù)epochs邦投。
上面一段代碼的運行結果如下圖所示:
Epoch 1/8
60000/60000 [==============================] - 12s 192us/step - loss: 0.2178 - acc: 0.9330
Epoch 2/8
60000/60000 [==============================] - 9s 150us/step - loss: 0.0810 - acc: 0.9760
Epoch 3/8
60000/60000 [==============================] - 9s 150us/step - loss: 0.0628 - acc: 0.9813
Epoch 4/8
60000/60000 [==============================] - 9s 151us/step - loss: 0.0531 - acc: 0.9838
Epoch 5/8
60000/60000 [==============================] - 9s 150us/step - loss: 0.0475 - acc: 0.9858
Epoch 6/8
60000/60000 [==============================] - 9s 151us/step - loss: 0.0435 - acc: 0.9873
Epoch 7/8
60000/60000 [==============================] - 9s 151us/step - loss: 0.0386 - acc: 0.9887
Epoch 8/8
60000/60000 [==============================] - 9s 151us/step - loss: 0.0366 - acc: 0.9895
7.模型評估
test_X, test_y = mnist.load_data()[1]
test_X = test_X.reshape(-1, 28, 28, 1)
test_X = test_X.astype('float32')
test_X /= 255
test_y = to_categorical(test_y, 10)
loss, accuracy = model.evaluate(test_X, test_y, verbose=1)
print('train data loss:%.4f accuracy:%.4f' %(loss, accuracy))
loss, accuracy = model.evaluate(train_X, train_y, verbose=1)
print('test data loss:%.4f accuracy:%.4f' %(loss, accuracy))
第1行代碼獲取測試集的數(shù)據(jù)伤锚;
第2-4行代碼將原始的特征矩陣做數(shù)據(jù)處理形成模型需要的數(shù)據(jù);
第5行代碼使用keras中的方法對數(shù)字的標簽分類做One-Hot編碼志衣。
上面一段代碼的運行結果如下:
第7-8行代碼使用測試集的數(shù)據(jù)做模型評估屯援,打印損失函數(shù)值和準確率;
第9-10行代碼使用訓練集的數(shù)據(jù)做模型評估念脯,打印損失函數(shù)值和準確率狞洋。
10000/10000 [==============================] - 1s 110us/step
train data loss:0.0215 accuracy:0.9931
60000/60000 [==============================] - 6s 107us/step
test data loss:0.0153 accuracy:0.9957
8.模型測試
import math
import matplotlib.pyplot as plt
import numpy as np
import random
def drawDigit3(position, image, title, isTrue):
plt.subplot(*position)
plt.imshow(image.reshape(-1, 28), cmap='gray_r')
plt.axis('off')
if not isTrue:
plt.title(title, color='red')
else:
plt.title(title)
def batchDraw3(batch_size, test_X, test_y):
selected_index = random.sample(range(len(test_y)), k=batch_size)
images = test_X[selected_index]
labels = test_y[selected_index]
predict_labels = model.predict(images)
image_number = images.shape[0]
row_number = math.ceil(image_number ** 0.5)
column_number = row_number
plt.figure(figsize=(row_number+8, column_number+8))
for i in range(row_number):
for j in range(column_number):
index = i * column_number + j
if index < image_number:
position = (row_number, column_number, index+1)
image = images[index]
actual = np.argmax(labels[index])
predict = np.argmax(predict_labels[index])
isTrue = actual==predict
title = 'actual:%d\npredict:%d' %(actual,predict)
drawDigit3(position, image, title, isTrue)
batchDraw3(100, test_X, test_y)
plt.show()
第6-13行定義drawDigit3函數(shù)畫出單個數(shù)字;
第7行代碼調用matplotlib.pyplot庫的subplot方法指定子圖位置绿店;
第8行代碼調用matplotlib.pyplot庫的imshow方法把數(shù)字矩陣繪制成圖吉懊;
第9行代碼設置不顯示坐標軸;
第10-13行代碼如果函數(shù)的參數(shù)isTrue為真假勿,則標題為黑色借嗽,否則為紅色。
第15-34行代碼定義batchDraw函數(shù)废登,根據(jù)參數(shù)batch_size選出此數(shù)量的樣本并畫圖淹魄。
第21行代碼調用math庫的ceil函數(shù)對小數(shù)向上取整郁惜,例如math.ceil(2.01)=3
上面一段代碼的運行結果如下圖所示:
從上面的運行結果可以看出堡距,只有最后1行中的1個數(shù)被判斷錯誤,符合前一章模型評估中99.3%的結果兆蕉。
9.總結
1.keras基于tensorflow封裝羽戒,代碼更直觀,容易理解虎韵;
2.根據(jù)本文作者的經驗易稠,在MNIST數(shù)據(jù)集上,基于tensorflow編寫代碼需要53行代碼包蓝,基于keras編寫代碼需要38行驶社,38/53=0.7170
,即可以減少30%的代碼量测萎。
3.keras在訓練過程中會動態(tài)顯示訓練進度亡电,是友好的用戶界面設計。