2023年12月11日發(作者:粗線條)

卷積神經網絡(CNN)mnist手寫字python源代碼詳解
首先介紹下卷積神經網絡
輸入層我就不講了,我主要根據代碼講下卷積層,池化層,全連接層。
(一)
卷積層
'''
-1代表著矩陣行不確定我這里用n表示,[-1,28,28,1]的意思是n行28列,
它的子元素是一個28行1列的矩陣,例如
[[[[1]], [[1]], [[1]], [[1]]],
[[[1]], [[1]], [[1]], [[1]]]]
可以表示為【2,4,1,1】它的子元素[[1]]為1行1列。在這里這個1也可以理解為通道數為1
'''
x_image = e(x, [-1, 28, 28, 1])
'''
w_conv1代表著filter【5,5】為卷積核大小,1為通道數,32為卷積核的個數,卷積核個
數的選取需要憑經驗,也許有大神知道一定的規律,這里我講一下卷積核的通道數為什么需
要和輸入的通道數一樣,其實原理很簡單,我們需要x_image和w_conv1相乘,也就需要它們兩
個的子元素相乘,上邊已經說過x_image的子元素為【28,1】,要想兩者相乘,則w_conv1
子元素必須為【1,n]
'''
w_conv1 = weight_variable([5, 5, 1, 32])
卷積的計算包括兩部分,輸入和filter
卷積的計算(注意,下面藍色矩陣周圍有一圈灰色的框,那些就是上面所說到的填充值)
藍色的矩陣(輸入圖像)對粉色的矩陣(filter)進行矩陣內積計算并將三個內積運算的結果與偏置值b相加(比如上面圖的計算:2+(-2+1-
2)+(1-2-2) + 1= 2 - 3 - 3 + 1 = -3),計算后的值就是綠框矩陣的一個元素。下面的動態圖形象地展示了卷積層的計算過程:
代碼中我們需要定義一個方法,來實現卷積
def conv2d(x, w):
b = 2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
return b
卷積運算后,輸出圖片尺寸縮小;
越是邊緣的像素點,對于輸出的影響越小,因為卷積運算在移動的時候到邊緣就結束了。中間的像素點有可能會參與多次計算,但是邊緣像
素點可能只參與一次。所以我們的結果可能會丟失邊緣信息。
那么為了解決這個問題,我們引入padding, 什么是padding呢,就是我們認為的擴充圖片, 在圖片外圍補充一些像素點,把這些像
素點初始化為0.
① SAME
輸出大小等于輸入大小除以步長向上取整,s是步長大小;
我們這里的輸入大小為28
28的圖像,filter 大小為5
5, 步長strides 為1所以輸出大小也為28
28,下面給出圖解
假設我們輸入矩陣為
我們先把矩陣擴充為
然后再與filter進行卷積運算,這樣做是為了保留邊界信息,否則的話我們的邊界只進行了一次運算,而內部進行了多次
② VALUE
輸出大小等于輸入大小減去濾波器大小加上1,最后再除以步長(f為濾波器的大小,s是步長大小)。假設我們輸入大小為28
28,步長為
1,filter為5
5,那么輸出大小為24
24,圖片有所縮小。
**(二)**激勵層
把卷積層輸出結果做非線性映射。
主要是增強輸入輸出之間的擬合性,
CNN采用的激勵函數一般為ReLU(The Rectified Linear Unit/修正線性單元),它的特點是收斂快,求梯度簡單,但較脆弱。代碼如下
h_conv1 = (conv2d(x_image, W_conv1) + b_conv1)
**(三)**池化層
池化層夾在連續的卷積層中間, 用于壓縮數據和參數的量,減小過擬合。
簡而言之,如果輸入是圖像的話,那么池化層的最主要作用就是壓縮圖像。
這里再展開敘述池化層的具體作用。
1. 特征不變性,也就是我們在圖像處理中經常提到的特征的尺度不變性,池化操作就是圖像的resize,平時一張狗的圖像被縮小了一倍
我們還能認出這是一張狗的照片,這說明這張圖像中仍保留著狗最重要的特征,我們一看就能判斷圖像中畫的是一只狗,圖像壓縮時
去掉的信息只是一些無關緊要的信息,而留下的信息則是具有尺度不變性的特征,是最能表達圖像的特征。
2. 特征降維,我們知道一幅圖像含有的信息是很大的,特征也很多,但是有些信息對于我們做圖像任務時沒有太多用途或者有重復,我
們可以把這類冗余信息去除,把最重要的特征抽取出來,這也是池化操作的一大作用。
3. 在一定程度上防止過擬合,更方便優化。
池化層用的方法有Max pooling 和 average pooling,而實際用的較多的是Max pooling。
這里就說一下Max pooling,其實思想非常簡單。
對于每個2
2的窗口選出最大的數作為輸出矩陣的相應元素的值,比如輸入矩陣第一個2
2窗口中最大的數是6,那么輸出矩陣的第一個元素
就是6,如此類推。
(四)全連接層
全連接層在我看來不大好理解,下面給出我自己的理解,全連接層的目的是將網絡學習到的特征映射到樣本的標記空間中。全連接層會把卷
積輸出的二維特征圖(featureMap)轉化成一個一維的向量。本案例中我們進行了2次卷積,最后得到了64個7
7的二維特征圖
(featureMap),我們需要把它轉化為一維的,即7
7*64,代碼如下
h_pool2_flat = e(h_pool2, [-1, 7*7*64]) #reshape成向量
W_fc1 = weight_variable([7 * 7 * 64, 1024]) #1024代表卷積個數,我們可以任意取
b_fc1 = bias_variable([1024])
h_fc1 = ((h_pool2_flat, W_fc1) + b_fc1)
這里我給個例子幫助你們理解e(),請看代碼
import numpy as np
import tensorflow as tf
input = le([[[[1]], [[1]], [[1]], [[1]]],
[[[1]], [[1]], [[1]], [[1]]]], dtype=float)
b = e(input, [1, 8])
print((input))
print((b))
運行結果為, 從結果中我們可以看出,轉換規則為,2
4
1
1=1
8
同理,因為我們全連接層的輸入,就是卷積層的輸出,我們經過兩次卷積后的輸出為h_pool2= [-1, 7, 7, 64],為什么是-1,是因為我們最
初的輸入x_image = [-1, 28, 28, 1] , -1 代表著行數不確定。
h_pool2_flat = e(h_pool2, [-1, 7*7*64]) #reshape成向量
我們就把 [-1, 7, 7, 64]轉換為 [-1, 7
7
64]。
謹記,全連接層不是卷積層,所以這里是
h_fc1 = ((h_pool2_flat, W_fc1) + b_fc1)
我們用()只是把得到的特征值與權重w相乘再加上偏執b。
最后我們需要加上,
keep_prob = older("float")
h_fc1_drop = t(h_fc1, keep_prob)
t()是tensorflow里面為了防止或減輕過擬合而使用的函數,它一般用在全連接層
最后給出我們整個運算過程并附上代碼。
代碼
import tensorflow as tf
import tensorflow as tf
import _data as input_data
mnist = input__data_ts("MNIST_data/", one_hot=True)
x = older(32, [None, 784]) # 占位用,因為圖片大小為28*28,所以為784,
# 但是我們并不清楚有多少副,所以設為None,后續來添加
y_actual = older(32, shape=[None, 10]) # 同理占位用,因為我們要測的是0-9一共10個數,即一共10個類別
'''
ted_normal(shape, mean, stddev) :shape表示生成張量的維度,mean是均值,stddev是標準差。
這個函數產生正太分布,均值和標準差自己設定。就是說產生正太分布的值如果與均值的差值大于兩倍的標準差,那就重新生成。
和一般的正太分布的產生隨機數據比起來,這個函數產生的隨機數與均值的差距不會超過兩倍的標準差,但是一般的別的函數是可能的。
謹記 filter中的值是經過訓練后確定的(代表著權重w)
'''
def weight_variable(shape):
initial = ted_normal(shape, stddev=0.1)
return le(initial)
# 偏置b
def bias_variable(shape):
initial = nt(0.1, shape=shape)
return le(initial)
# 卷積
def conv2d(x, w):
return 2d(x, w, strides=[1, 1, 1, 1], padding='SAME')
# 池化層
def max_pool(x):
return _pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
x_image = e(x, [-1, 28, 28, 1])
'''
w_conv1代表著filter【5,5】為卷積核大小,1為通道數,32為卷積核的個數,卷積核個
數的選取需要憑經驗,也許有大神知道一定的規律,這里我講一下卷積核的通道數為什么需
要和輸入的通道數一樣,其實原理很簡單,我們需要x_image和w_conv1,也就表示它們兩
個的子元素相乘,上邊已經說過x_image的子元素為【28,1】,要想兩者相乘,則w_conv1
子元素必須為【1,n]
'''
w_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = (conv2d(x_image, w_conv1) + b_conv1)
h_pool1 = max_pool(h_conv1)
w_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = (conv2d(h_pool1, w_conv2) + b_conv2)
h_pool2 = max_pool(h_conv2)
'''
7*7*64表示7*7的圖片64個,也就表示一共有7*7*64個特征值(包含0),1024是實際上的特征值,使我們需要保留的
'''
w_fc1 = weight_variable([7*7*64, 1024])
w_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = e(h_pool2, [-1, 7*7*64])
h_fc1 = ((h_pool2_flat, w_fc1) + b_fc1)
'''
Dropout就是在不同的訓練過程中隨機扔掉一部分神經元。也就是讓某個神經元的激活值以一定的概率p,
讓其停止工作,這次訓練過程中不更新權值,也不參加神經網絡的計算。但是它的權重得保留下來(只是暫時不更新而已),
因為下次樣本輸入時它可能又得工作了,keep_prob表示丟棄的概率
'''
keep_prob = older("float")
h_fc1_drop = t(h_fc1, keep_prob)
w_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_predict = x((h_fc1_drop, w_fc2) + b_fc2)
cross_entropy = -_sum(y_actual * (y_predict)) # 根據公式求和
train_step = ntDescentOptimizer(1e-3).minimize(cross_entropy) # 梯度下降法尋找最優解,訓練時,不斷的調整權重w
correct_prediction = ((y_predict, 1),
(y_actual, 1)) # 返回的true或fal,返回的是最大值的下標,
# 0表示按列來,1表示按行來
accuracy = _mean(
(correct_prediction, "float")) # dtype = float可以把bool(True or Fal)類型轉化為float類型(數據),
# _mean()求平均值,同樣,0表示對列求平均,1表示對行求平均,既沒有0也沒有1的話對整個矩陣求平均
ss = ctiveSession()
(_variables_initializer())
for i in range(20000):
batch = _batch(50)
if i % 100 == 0: # 訓練100次,驗證一次
train_(feed_dict={x: batch[0], y_actual: batch[1], keep_prob: 0.5})
test_acc = (feed_dict={x: , y_actual: , keep_prob: 1.0})
print("test accuracy %g" % test_acc)
本文發布于:2023-12-11 19:01:50,感謝您對本站的認可!
本文鏈接:http://www.newhan.cn/zhishi/a/1702292510118512.html
版權聲明:本站內容均來自互聯網,僅供演示用,請勿用于商業和其他非法用途。如果侵犯了您的權益請與我們聯系,我們將在24小時內刪除。
本文word下載地址:卷積神經網絡(CNN)mnist手寫字python源代碼詳解.doc
本文 PDF 下載地址:卷積神經網絡(CNN)mnist手寫字python源代碼詳解.pdf
| 留言與評論(共有 0 條評論) |