【Keras篇】---Keras初始,兩種模型構造方法,利用keras實現手寫數字體識別

LHBlog發表於2018-03-30

一、前述

Keras 適合快速體驗 ,keras的設計是把大量內部運算都隱藏了使用者始終可以用theano或tensorflow的語句來寫擴充套件功能並和keras結合使用。

二、安裝

Pip install --upgrade keras

三、Keras模型之序列模型

序列模型屬於通用模型的一種,因為很常見,所以這裡單獨列出來進行介紹,這種模型各層之間是依次順序的線性關係,在第k層和第k+1層之間可以加上各種元素來構造神經網路
這些元素可以通過一個列表來制定,然後作為引數傳遞給序列模型來生成相應的模型。

 第一種方式

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Activation

# Dense相當於構建一個全連線層,32指的是全連線層上面神經元的個數
layers = [Dense(32, input_shape=(784,)),
          Activation('relu'),
          Dense(10),
          Activation('softmax')]
model = Sequential(layers)
model.summary()

第二種方式:

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Activation


model = Sequential()
model.add(Dense(32, input_shape=(784,)))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('softmax'))

 

 結果:

四、Keras模型之通用模型

 通用模型可以用來設計非常複雜、任意拓撲結構的神經網路,例如有向無環圖網路類似於序列模型,通用模型通過函式化的應用介面來定義模型使用函式化的應用介面有好多好處,比如:決定函式執行結果的唯一要素是其返回值,而決定返回值的唯一要素則是其引數,這大大減輕了程式碼測試的工作量

在通用模型中,定義的時候,從輸入的多維矩陣開始,然後定義各層及其要素,最後定義輸出層將輸入層和輸出層作為引數納入通用模型中就可以定義一個模型物件

 程式碼:

# 通用模型
# 通用模型可以用來設計非常複雜、任意拓撲結構的神經網路,例如有向無環圖網路
# 類似於序列模型,通用模型通過函式化的應用介面來定義模型
# 使用函式化的應用介面有好多好處,比如:決定函式執行結果的唯一要素是其返回值,而決定
# 返回值的唯一要素則是其引數,這大大減輕了程式碼測試的工作量

# 在通用模型中,定義的時候,從輸入的多維矩陣開始,然後定義各層及其要素,最後定義輸出層
# 將輸入層和輸出層作為引數納入通用模型中就可以定義一個模型物件

from keras.layers import Input
from keras.layers import Dense
from keras.models import Model

# 定義輸入層
input = Input(shape=(784,))
# 定義各個連線層,假設從輸入層開始,定義兩個隱含層,都有64個神經元,都使用relu啟用函式
x = Dense(64, activation='relu')(input)#把上一層輸出結果給下一層的輸入
x = Dense(64, activation='relu')(x)
# 定義輸出層,使用最近的隱含層作為引數
y = Dense(10, activation='softmax')(x)#整個邏輯從輸入到輸出全都在y裡面了

# 所有要素都齊備以後,就可以定義模型物件了,引數很簡單,分別是輸入和輸出,其中包含了
# 中間的各種資訊
model = Model(inputs=input, outputs=y)

# 當模型物件定義完成之後,就可以進行編譯(定義損失函式,通過什麼方式優化(優化器),等等)了,並對資料進行擬合,擬合的時候也有兩個引數
# 分別對應於輸入和輸出
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(data, labels)#data是輸入資料的X labels是Y

五、Keras實現手寫識別體案例

 

import numpy as np
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
#Conv2D  圖片是3通道 Conv1D  單聲道或者雙聲道


# 先讀入資料
(X_train, y_train), (X_test, y_test) = mnist.load_data("../test_data_home")
# 看一下資料集的樣子
print(X_train[0].shape)#X_train是很多張圖片[0]是第一張
print(y_train[0])

# 下面把訓練集中的手寫黑白字型變成標準的四維張量形式,即(樣本數量,長,寬,1)
# 1是channel通道
# 並把畫素值變成浮點格式
# X_train.shape[0]取得是行的數量
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32')

# 由於每個畫素值都介於0到255,所以這裡統一除以255,把畫素值控制在0-1範圍
X_train /= 255 #X_train是一個矩陣 這裡相當於裡面每個數都除以255
X_test /= 255


# 由於輸入層需要10個節點,所以最好把目標數字0-9做成One Hot編碼的形式
def tran_y(y):#自己定義的One_hot編碼格式 先定義10個零 然後在對應個數上填1
    y_ohe = np.zeros(10)
    y_ohe[y] = 1
    return y_ohe


# 把標籤用One Hot編碼重新表示一下
y_train_ohe = np.array([tran_y(y_train[i]) for i in range(len(y_train))])#列表生成器
y_test_ohe = np.array([tran_y(y_test[i]) for i in range(len(y_test))])

# 搭建卷積神經網路
model = Sequential()
# 新增一層卷積層,構造64個過濾器(卷積核),每個過濾器(卷積核)覆蓋範圍是3*3*1
# 過濾器步長為1,影像四周補一圈0,並用relu進行非線性變化
model.add(Conv2D(filters=64, kernel_size=(3, 3), strides=(1, 1), padding='same',
                 input_shape=(28, 28, 1), activation='relu'))#activation如果不設定,就是線性的
# 新增一層最大池化層
model.add(MaxPooling2D(pool_size=(2, 2)))#預設Strides是和池化維度一樣 這裡是2*2 池化預設一般不做padding
# 設立Dropout層,Dropout的概率為0.5
model.add(Dropout(0.5))

# 重複構造,搭建深度網路
model.add(Conv2D(128, kernel_size=(3, 3), strides=(1, 1), padding='same',
                 activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(256, kernel_size=(3, 3), strides=(1, 1), padding='same',
                 activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))

# 把當前層節點展平
model.add(Flatten())

# 構造全連線層神經網路層
model.add(Dense(128, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(10, activation='softmax'))

# 定義損失函式,一般來說分類問題的損失函式都選擇採用交叉熵
# adagrad自適應的調整學習率的隨機梯度下降演算法 因為自適應所以會比較耗時間
model.compile(loss='categorical_crossentropy', optimizer='adagrad', metrics=['accuracy'])

# 放入批量樣本,進行訓練
model.fit(X_train, y_train_ohe, validation_data=(X_test, y_test_ohe)#驗證集作用邊訓練邊測試 在每一個step中都會驗證
          , epochs=20, batch_size=128)
#epochs是迭代多少輪次 學完一輪是整個資料集/128 這裡面有20輪

# 在測試集上評價模型的準確率
# verbose : 進度表示方式。0表示不顯示資料,1表示顯示進度條
scores = model.evaluate(X_test, y_test_ohe, verbose=0)#evaluate就是評估準確率

 

 

 

延伸結論:

最後一個卷積層到第一個全連線層的引數是最多的

結果:

 

相關文章