深蓝学院第二章:基于全连接神经网络(FCNN)的手写数字识别
如何用全連接神經網絡去做手寫識別???
使用的是jupyter notebook這個插件進行代碼演示。(首先先裝一個Anaconda的虛擬環境,然后自己構建一個自己的虛擬環境,然后在虛擬環境中安裝jupyter、安裝我們將要使用的一些包)
安裝參考步驟:https://blog.csdn.net/m0_37957160/article/details/114153355
手寫數字識別輸入是圖片,建立一種全連接神經網絡的模型來將手寫數字進行識別。手寫數字識別是一個的圖片,實際上我們神經網絡的輸入層只能處理這種一維的數據,這里的我們按照行或者按照列給他展開,相當于把它展成一個784這樣的一個向量,然后再輸入到這個全連接神經網絡當中。這里讓全連接神經網絡的輸入層有784個神經元,再加上一個偏置b,中間層可以按照自己的實驗去設置一個數值,比如說中間層有30或者20個神經元,這個輸出層有10個,分別代表的是0到9。
+1就表示加入的偏置。
全連接神經網絡:
在計算每一層誤差的時候就代表我整個的從層到層誤差反傳的時候他有一個權重矩陣的轉置在這里面。
使用的是Minist batch的一個梯度下降算法,并不是一次把所有的數據都放進去進行學習,而是每一次我選擇里邊一部分數據集進行學習,他的輸出就是我整個的模型,包括權重和偏置。
代碼中使用到的python知識:
1、python中cPickle用法:
有些training set 數據是用.pkl 文件存儲的。用module cPickle讀取非常方便。
cPickle模塊:
在python中,一般可以使用pickle類來進行python對象序列化,而cPickle提供了一個更快速簡單的接口,如python文檔所說:“cPickle - A faster pickle”。
cPickle可以對任意一種類型的python對象進行序列化操作,比如:list, dict,甚至是一個類的對象等。而所謂的序列化,是為了能完整地保存并能夠完全可逆的恢復。在cPickle中,主要有4個函數:
1.1 dump:將python對象序列化保存到本地的文件
import _pickle as cPickledata = range(1000)#range() 函數可創建一個整數列表,0到999是沒有1000。
cPickle.dump(data, open("test\\data.pkl", "wb"))
dump函數需要指定兩個參數,第一個是需要序列化的python對象名稱,第二個是本地的文件,需要注意的是,在這里需要使用open函數打開一個文件,并指定“寫”操作。
1.2. load:載入本地文件,恢復python對象
data = cPickle.load(open("test\\data.pkl", "rb"))
使用open函數打開本地的一個文件,并指定“讀”操作。
1.3. dumps:將python對象序列化保存到一個字符串變量中
data_string = cPickle.dumps(data)
1.4. loads:載入字符串,恢復python對象
data = cPickle.loads(data_string)
pickle與cpickle比較:https://www.cnblogs.com/keye/p/8779626.html
pickle完全用python來實現的,cpickle用C來實現的,cpickle的速度要比pickle快好多倍。
2、numpy.reshape(a, newshape, order='C')[source],參數`newshape`是啥意思?
根據Numpy文檔:https://numpy.org/doc/stable/reference/generated/numpy.reshape.html#numpy-reshape
newshape : int or tuple of ints
The new shape should be compatible with the original shape. If an integer, then the result will be a 1-D array of that length. One shape dimension can be -1. In this case, **the value is inferred from the length of the array and remaining dimensions**.
大意是說,數組新的shape屬性應該要與原來的配套,如果等于-1的話,那么Numpy會根據剩下的維度計算出數組的另外一個shape屬性值。
舉幾個例子或許就清楚了,有一個數組z,它的shape屬性是(4, 4)
z = np.array([[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12],[13, 14, 15, 16]])
print(z.shape)#輸出(4, 4)變量名.reshape(m,n),返回一個m行n列的數組
變量名.reshape(-1),返回一個一維數組
變量名.reshape(-1,n),返回一個n列的數組,行數自動給定
3、python 自定義向量化(vectorized)操作函數
4、np.zeros函數的作用
返回來一個給定形狀和類型的用0填充的數組;
numpy.zeros(shape,dtype=float,order = 'C')
shape:形狀
dtype:數據類型,可選參數,默認numpy.float64
order:可選參數,c代表與c語言類似,行優先;F代表列優先
np.zeros(5)
Out[1]: array([ 0., 0., 0., 0., 0.])
import numpy as np
print(np.zeros((2,5)))
結果為一個2行5列的矩陣
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
print(np.zeros((2,5),dtype= np.int))
結果為
[[0 0 0 0 0]
[0 0 0 0 0]]
5、plt.subplot()使用方法以及參數介紹
首先一幅Matplotlib的圖像組成部分介紹。:https://blog.csdn.net/asher117/article/details/85128463
在matplotlib中,整個圖像為一個Figure對象。在Figure對象中可以包含一個或者多個Axes對象。每個Axes(ax)對象都是一個擁有自己坐標系統的繪圖區域。所屬關系如下:
def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True,subplot_kw=None, gridspec_kw=None, **fig_kw):
參數
nrows,ncols:
子圖的行列數。
sharex, sharey:
設置為 True 或者 ‘all’ 時,所有子圖共享 x 軸或者 y 軸,
設置為 False or ‘none’ 時,所有子圖的 x,y 軸均為獨立,
設置為 ‘row’ 時,每一行的子圖會共享 x 或者 y 軸,
設置為 ‘col’ 時,每一列的子圖會共享 x 或者 y 軸。
squeeze:
默認為 True,是設置返回的子圖對象的數組格式。
當為 False 時,不論返回的子圖是只有一個還是只有一行,都會用二維數組格式返回他的對象。
當為 True 時,如果設置的子圖是(nrows=ncols=1),即子圖只有一個,則返回的子圖對象是一個標量的形式,如果子圖有(N×1)或者(1×N)個,則返回的子圖對象是一個一維數組的格式,如果是(N×M)則是返回二位格式。
subplot_kw:
字典格式,傳遞給 add_subplot() ,用于創建子圖。
gridspec_kw:
字典格式,傳遞給 GridSpec 的構造函數,用于創建子圖所擺放的網格。
class matplotlib.gridspec.GridSpec(nrows, ncols, figure=None, left=None, bottom=None, right=None, top=None, wspace=None, hspace=None, width_ratios=None, height_ratios=None)
如,設置 gridspec_kw={'height_ratios': [3, 1]} 則子圖在列上的分布比例是3比1。
**fig_kw :
所有其他關鍵字參數都傳遞給 figure()調用。
如,設置 figsize=(21, 12) ,則設置了圖像大小。
返回值
fig:?matplotlib.figure.Figure?對象
ax:子圖對象(?matplotlib.axes.Axes)或者是他的數組
在用plt.subplots畫多個子圖中,ax = ax.flatten()將ax由n*m的Axes組展平成1*nm的Axes組。ax是在畫布上添加的子圖
以下面的例子說明ax = ax.flatten()的作用:
fig, ax = plt.subplots(nrows=2,ncols=2,sharex='all',sharey='all')
ax = ax.flatten() for i in range(4):img = image[i].reshape(28, 28)ax[i].imshow(img, cmap='Greys', interpolation='nearest') # 區別:可以直接用ax[i]
不使用ax = ax.flatten()
fig, ax = plt.subplots(nrows=2,ncols=2,sharex='all',sharey='all') for i in range(4):img = image[i].reshape(28, 28)axs[0, 0].imshow(img, cmap='Greys', interpolation='nearest') # 區別:不能直接使用ax[i]axs[0, 1].imshow(img, cmap='Greys', interpolation='nearest')axs[1, 0].imshow(img, cmap='Greys', interpolation='nearest')axs[1, 1].imshow(img, cmap='Greys', interpolation='nearest')
官方文檔:https://matplotlib.org/stable/api/axes_api.html
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplot.html
6、format 格式化函數
Python2.6 開始,新增了一種格式化字符串的函數?str.format(),它增強了字符串格式化的功能。
基本語法是通過?{}?和?:?來代替以前的?%?。
format 函數可以接受不限個參數,位置可以不按順序。
>>>"{} {}".format("hello", "world") # 不設置指定位置,按默認順序
結果輸出:'hello world'>>> "{0} {1}".format("hello", "world") # 設置指定位置
結果輸出:'hello world'>>> "{1} {0} {1}".format("hello", "world") # 設置指定位置
結果輸出:'world hello world'
也可以設置參數:
#!/usr/bin/python
# -*- coding: UTF-8 -*-print("網站名:{name}, 地址 {url}".format(name="菜鳥教程", url="www.runoob.com"))# 通過字典設置參數
site = {"name": "菜鳥教程", "url": "www.runoob.com"}
print("網站名:{name}, 地址 {url}".format(**site))# 通過列表索引設置參數
my_list = ['菜鳥教程', 'www.runoob.com']
print("網站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必須的
輸出結果為:
網站名:菜鳥教程, 地址 www.runoob.com 網站名:菜鳥教程, 地址 www.runoob.com 網站名:菜鳥教程, 地址 www.runoob.com
參考:https://www.runoob.com/python/att-string-format.html
7、?numpy.random.rand()
numpy.random.rand(d0,d1,…,dn)
- rand函數根據給定維度生成[0,1)之間的數據,包含0,不包含1
- dn表格每個維度
- 返回值為指定維度的array
np.random.rand(4,2)
結果:
array([[ 0.02173903, 0.44376568],[ 0.25309942, 0.85259262],[ 0.56465709, 0.95135013],[ 0.14145746, 0.55389458]])
np.random.rand(4,3,2) # shape: 4*3*2
結果為:array([[[ 1.27820764, 0.92479163],[-0.15151257, 1.3428253 ],[-1.30948998, 0.15493686]],[[-1.49645411, -0.27724089],[ 0.71590275, 0.81377671],[-0.71833341, 1.61637676]],[[ 0.52486563, -1.7345101 ],[ 1.24456943, -0.10902915],[ 1.27292735, -0.00926068]],[[ 0.88303 , 0.46116413],[ 0.13305507, 2.44968809],[-0.73132153, -0.88586716]]])
參考:https://blog.csdn.net/u012149181/article/details/78913167
8、python列表的截取
負數索引表示從右邊往左數,從-1開始。最右邊的元素的索引為-1,倒數第二個元素為-2。[ a:b ]包含a不包括b。
正索引從左向右,從0開始。
9、zip() 函數
zip()?函數用于將可迭代的對象作為參數,將對象中對應的元素打包成一個個元組,然后返回由這些元組組成的列表。
如果各個迭代器的元素個數不一致,則返回列表長度與最短的對象相同,利用 * 號操作符,可以將元組解壓為列表。
10、random.shuffle()
用來亂序序列,它是在序列的本身打亂,而不是新生成一個序列
不會生成新的列表,只是將原列表的次序打亂。
PS:有關random.shuffle函數的局限性。重點: random.shuffle千萬不要用于二維numpy.array(也就是矩陣)!!!
如下代碼:
得到一個錯誤的打亂輸出!
查看random.shuffle源碼:
def shuffle(self, x, random=None):"""Shuffle list x in place, and return None.原位打亂列表,不生成新的列表。Optional argument random is a 0-argument function returning arandom float in [0.0, 1.0); if it is the default None, thestandard random.random will be used.可選參數random是一個從0到參數的函數,返回[0.0,1.0)中的隨機浮點;如果random是缺省值None,則將使用標準的random.random()。"""if random is None:randbelow = self._randbelowfor i in reversed(range(1, len(x))):# pick an element in x[:i+1] with which to exchange x[i]j = randbelow(i+1)x[i], x[j] = x[j], x[i]else:_int = intfor i in reversed(range(1, len(x))):# pick an element in x[:i+1] with which to exchange x[i]j = _int(random() * (i+1))x[i], x[j] = x[j], x[i]
只需要關注其中交換元素操作為?x[i], x[j] = x[j], x[i]?
測試一下這種交換方式對于二維numpy.array會發生什么事情:
import numpy as np
a = np.array([[1,2,3,4],[5,6,7,8]])
a[0], a[1] = a[1], a[0]
print(a)
輸出:
[[5 6 7 8][5 6 7 8]]
顯然這種方式不適合numpy.array的行交換(但是二維list就可以使用這種交換方式。可以自行證明,至于原因暫時不知道,求解答)。
打亂numpy.array正確的姿勢當然是使用numpy自帶的numpy.random.shuffle()
def shuffle(x): # real signature unknown; restored from __doc__
"""
shuffle(x)Modify a sequence in-place by shuffling its contents.This function only shuffles the array along the first axis of amulti-dimensional array. The order of sub-arrays is changed buttheir contents remains the same.Parameters----------x : array_likeThe array or list to be shuffled.Returns-------NoneExamples-------->>> arr = np.arange(10)>>> np.random.shuffle(arr)>>> arr[1 7 5 2 9 4 3 6 0 8]Multi-dimensional arrays are only shuffled along the first axis:>>> arr = np.arange(9).reshape((3, 3))>>> np.random.shuffle(arr)>>> arrarray([[3, 4, 5],[6, 7, 8],[0, 1, 2]])
"""
pass
注釋中Multi-dimensional arrays are only shuffled along the first axis: 多維向量只是沿著第一個坐標軸進行重新排序。
參考:https://blog.csdn.net/qq_21063873/article/details/80860218
11、range()
https://www.runoob.com/python/python-func-range.html
以下是完整的代碼,包含解讀,經測試是完全可以跑通的。
?
?
?
?
完整的代碼下載鏈接:https://download.csdn.net/download/m0_37957160/15713687
---------------------------------------done----------------------
下面是一些代碼解讀:
??
?
總結
以上是生活随笔為你收集整理的深蓝学院第二章:基于全连接神经网络(FCNN)的手写数字识别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 回归分析中的“回归”
- 下一篇: Windows下超详细安装Anacond