4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

一字千金 發表於 2021-06-22
神經網路

自己開發了一個股票智慧分析軟體,功能很強大,需要的點選下面的連結獲取:

https://www.cnblogs.com/bclshuai/p/11380657.html

1.1  CNN卷積神經網路

1.1.1          什麼是CNN卷積神經網路

CNN(convolutional neural network)卷積神經網路是一種具有區域性連線和權重共享等特性的深層前饋神經網路。簡單來說神經網路都是為了提取特徵。卷積提取特徵的方式如下圖所示,加入圖片是5*5個畫素的圖片,用一個3*3的卷積核在圖片矩陣上移動,用卷積核中行列中的值乘以圖片資料中3*3的資料值,得到一個值,作為圖片區域的特徵值,然後卷積核向右移動一位,繼續計算。移動到最右邊,在向下移動一格,從左往右繼續計算,最後將5*5的圖片資料,轉化為3*3的圖片特徵資料,轉化後的圖片特徵資料仍然保留著原始圖片資料的特徵。

 4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

1.1.2          卷積神經網路解決什麼問題

(1)    全連線引數過多的問題

全連線層如果圖片是100*100*3(高,寬,RGB三色值),則第一個隱藏層的引數有30000個。引數多會導致訓練效率低,也容易出現過擬合。

(2)    區域性不變性特徵提取

影像縮放,平移,旋轉都不影響其特徵資訊,而全連線層很難提取區域性不變性特徵。

1.1.3          卷積神經網路原理

(1)    卷積層初步提取特徵

通過卷積核去乘之後得出值,初步提取特徵。卷積層的作用其實就是通過不斷的改變卷積核,來確定能初步表徵圖片特徵的有用的卷積核是哪些,再得到與相應的卷積核相乘後的輸出矩陣。

 4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

(2)    池化層提取主要特徵

通過池化層減少訓練引數的數量,降低卷積層輸出的特徵向量的維度。減小過擬合現象,只保留最有用的圖片資訊,減少噪聲的傳遞。例如卷積層輸出是8*8的二維矩陣。把它分成4個2*2的區域性矩陣,對區域性矩陣進行最大值或者平均值計算,得出一個2*2的矩陣,作為原始圖片的特徵矩陣。如果池化層的輸入單元大小不是二的整數倍,一般採取邊緣補零(zero-padding)的方式補成2的倍數,然後再池化。

 4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

(3)    全連線層將各部分特徵彙總

卷積層和池化層的工作就是提取特徵,並減少原始影像帶來的引數。全連線層先將二維矩陣轉化為1維陣列,然後用全連線層進行訓練學習,通過前饋誤差計算、啟用函式、梯度下降法修改引數來提高分類器的準確率。來生成一個等於我們需要的類的數量的分類器。

4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

 

(4)    產生分類器,進行預測識別

通過訓練準確率達到要求之後,就可以用模型去預測分類。

1.1.4          卷積知識點

(1)感受野:後一層中某個區域的值是前面某一層固定區域的輸入計算出來的,那這個前一層的固定區域就是後一層該位置的感受野。其實就是卷積核移動經過的地方。

 4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

(2)步幅(stride):卷積核計算時每次向右移動和向下移動的長度。

(3)深度(depth) : 顧名思義,它控制輸出單元的深度,也就是filter的個數,連線同一塊區域的神經元個數。

(4)補零(zero-padding) : 我們可以通過在輸入單元周圍補零來改變輸入單元整體大小,從而控制輸出單元的空間大小。例如5*5的輸入矩陣,通過3*3的卷積之後,輸出是3*3,如果希望通過卷積之後,輸出仍然是5*5,則需要輸入矩陣周圍補0,變成7*7的矩陣。

1.1.5          CNN實現手寫數字識別

程式碼例項

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plot
#(1)定義手寫數字資料獲取類,用於下載資料和隨機獲取小批量訓練資料
class MNISTLoader():
    def __init__(self):
        minist = tf.keras.datasets.mnist
        #訓練資料x_train, 正確值y_train,測試資料x_test,測試資料正確值self.y_test
        (self.x_train, self.y_train), (self.x_test, self.y_test) = minist.load_data()
        #[60000,28,28,1],60000個28*28畫素的圖片資料,每個畫素點時0-255的整數,除以255.0是將每個畫素值歸一化為0-1間
        #的浮點數,並通過np.expand_dims增加一維,作為顏色通道.預設值為1。
        self.x_train = np.expand_dims(self.x_train.astype(np.float) / 255.0, axis=-1)
        print(self.x_train.shape)
        #[10000,28,28]->[10000,28,28,1]
        self.x_test = np.expand_dims(self.x_test.astype(np.float) / 255.0, axis=-1)
        #訓練用的標籤值
        self.y_train = self.y_train.astype(np.int)
        #測試用的標籤值
        self.y_test = self.y_test.astype(np.int)
        self.num_train_data = self.x_train.shape[0]
        self.num_test_data = self.x_test.shape[0]
    #隨機從資料集中獲取大小為batch_size手寫圖片資料
    def get_batch(self, batch_size):
        #shape[0]獲取資料總數量,在0-總數量之間隨機獲取資料的索引值,相當於抽樣。
        index = np.random.randint(0, self.x_train.shape[0], batch_size)
        #通過索引值去資料集中獲取訓練資料集。
        return self.x_train[index, :], self.y_train[index]
#(2)定義CNN卷積神經網路模型,繼承繼承keras.Model,init函式定義層,call函式中組織資料處理流程
class CNN(tf.keras.Model):
    def __init__(self):
        super(CNN, self).__init__()
        #卷積層1
        self.conv1 = tf.keras.layers.Conv2D(filters=32,#卷積核數目
                                            kernel_size=[5,5],#感受野大小
                                            padding='same',#矩陣補0使得輸入輸出大小一致,valid則不補0
                                            activation=tf.nn.relu)#啟用函式
        #池化層1
        self.pool1=tf.keras.layers.MaxPool2D(pool_size=[2,2],strides=2)
        #卷積層2
        self.conv2 = tf.keras.layers.Conv2D(filters=64,  # 卷積核數目
                                            kernel_size=[5, 5],  # 感受野大小
                                            padding='same',  # 矩陣補0使得輸入輸出大小一致,valid則不補0
                                            activation=tf.nn.relu)  # 啟用函式
        # 池化層2
        self.pool2= tf.keras.layers.MaxPool2D(pool_size=[2, 2], #2*2的感受野
                                              strides=2)#步長為2
        # 維度轉換,三維7*7*64,轉為1維3136
        self.flatten = tf.keras.layers.Reshape(target_shape=[7*7*64,])
        #全連線層,將3136個畫素點轉化為1024個
        self.dence1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)
        #全連線層,將1024個單元轉化為10個點
        self.dence2 = tf.keras.layers.Dense(units=10)

    def call(self, inputs, training=None, mask=None):
        #編寫資料流的處理過程,
        x=self.conv1(inputs)#[batch_size,28,28,32]
        x=self.pool1(x)#[batch_size,14,14,32]圖片大小變為14*14
        x=self.conv2(x)#[batch_size,14,14,,64],
        x=self.pool2(x)#[batch_size,7,7,64],
        x = self.flatten(x)#三維7*7*64陣列轉化為3136一維陣列
        x = self.dence1(x)#3136個對映到1024個
        x = self.dence2(x)#1024個對映到10個,分別表示對應0,1..9數字的概率
        output = tf.nn.softmax(x)#輸出0,1..9概率最大的值。
        return output

#(3)定義訓練引數和模型物件,資料集物件
num_epochs = 5
batch_size = 500#一批資料的數量
learning_rate = 0.001#學習率
model = CNN()#建立模型
data_loader = MNISTLoader()#建立資料來源物件
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)#建立優化器,用於引數學習優化
#開始訓練引數
num_batches=int(data_loader.num_train_data//batch_size*num_epochs)#計算訓練資料的總組數
arryindex=np.arange(num_batches)
arryloss=np.zeros(num_batches)
#(4)通過梯度下降法對模型引數進行訓練,優化模型
for batch_index in range(num_batches):
    X,ylabel=data_loader.get_batch(batch_size)#隨機獲取訓練資料
    with tf.GradientTape() as tape:
        ypred=model(X)#模型計算預測值
        #計算損失函式
        loss=tf.keras.losses.sparse_categorical_crossentropy(y_true=ylabel,y_pred=ypred)
        #計算損失函式的均方根值,表示誤差大小
        loss=tf.reduce_mean(loss)
        print("第%d次訓練後:誤差%f" % (batch_index,loss.numpy()))
        #儲存誤差值,用於畫圖
        arryloss[batch_index]=loss
        #根據誤差計算梯度值
    grads=tape.gradient(loss,model.variables)
    #將梯度值調整模型引數
    optimizer.apply_gradients(grads_and_vars=zip(grads,model.variables))

#畫出訓練誤差隨訓練次數的圖片圖
plot.plot(arryindex,arryloss,c='r')
plot.show()
#(5)評估模型的準確性
#建立評估器物件
sparse_categorical_accuracy=tf.keras.metrics.SparseCategoricalAccuracy()
#用測試資料集計算預測值
ytestpred=model.predict(data_loader.x_test)
#向評估器輸入預測值和真實值,計算準確率
sparse_categorical_accuracy.update_state(y_true=data_loader.y_test,y_pred=ytestpred)
print("test accuracy is %f" % sparse_categorical_accuracy.result())

 

 

訓練600次,每次誤差隨訓練次數的變化曲線如下圖所示,訓練比全連線層要耗時,600次大概需要600秒時間,而多層感知器大概只需要15秒。

 4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

最後幾次分析誤差已經達到了0.01,以及用測試集上的準確率達到0.99.

4.3CNN卷積神經網路最詳細最容易理解--tensorflow原始碼MLP對比

 

 

1.1.6          MLP和CNN對比

屬性

MLP

CNN

600次訓練時長

15秒

600秒

測試集上的準確率

0.95

0.99

訓練收斂次數

350次

150次

測試集最終誤差

0.08

0.01

通過對比可知,CNN比MLP,訓練收斂更快,誤差更小,準確率更好,但是訓練時間會更長。

MLP介紹和原始碼https://www.cnblogs.com/bclshuai/p/14902942.html

相關文章