c++读取图片_手工计算神经网络第三期:数据读取与完成训练
大數(shù)據(jù)文摘出品
作者:蔣寶尚
小伙伴們大家好呀~~用Numpy搭建神經(jīng)網(wǎng)絡(luò),我們已經(jīng)來(lái)到第三期了。第一期文摘菌教大家如何用Numpy搭建一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò),完成了前饋部分。第二期為大家?guī)?lái)了梯度下降相關(guān)的知識(shí)點(diǎn)。
這一期,教大家如何讀取數(shù)據(jù)集,以及將數(shù)據(jù)集用于神經(jīng)網(wǎng)絡(luò)的訓(xùn)練,和上兩期一樣,這次依然用Numpy實(shí)現(xiàn)。在開始代碼之前,文摘菌先帶大家看看今天我們使用的數(shù)據(jù)集。
數(shù)據(jù)集介紹
數(shù)據(jù)集采用著名的MNIST的手寫數(shù)據(jù)集。根據(jù)官網(wǎng)介紹,這個(gè)數(shù)據(jù)集有70000個(gè)樣本,包括60000個(gè)訓(xùn)練樣本,10000個(gè)測(cè)試樣本。
數(shù)據(jù)集下載下來(lái)之后,文件分為4個(gè)部分,分別是:訓(xùn)練集圖片、訓(xùn)練集標(biāo)簽、測(cè)試集圖片、測(cè)試集標(biāo)簽。這些數(shù)據(jù)以二進(jìn)制的格式儲(chǔ)存。
? ? ?
其中,訓(xùn)練集圖片文件的前16個(gè)字節(jié)是儲(chǔ)存了圖片的個(gè)數(shù),行數(shù)以及列數(shù)等。訓(xùn)練集標(biāo)簽文件前8個(gè)字節(jié)儲(chǔ)存了圖片標(biāo)簽的個(gè)數(shù)等。測(cè)試集的兩個(gè)文件同理。
文摘菌下載好的文件存儲(chǔ)地址
讀取數(shù)據(jù)
train_img_path=r'C:\Users\Dell\MNIST\train-images.idx3-ubyte'train_lab_path=r'C:\Users\Dell\MNIST\train-labels.idx1-ubyte'test_img_path=r'C:\Users\Dell\MNIST\t10k-images.idx3-ubyte'test_lab_path=r'C:\Users\Dell\MNIST\t10k-labels.idx1-ubyte'根據(jù)文件在本地解壓后的儲(chǔ)存地址,生成四個(gè)地址,上面代碼中‘r’是轉(zhuǎn)義字符,因?yàn)閈在Python中有特殊的用法,所以需用轉(zhuǎn)義字符明確文件地址。
為了讓后面的模型表現(xiàn)更好,我們將訓(xùn)練集拆分,拆成50000個(gè)訓(xùn)練集和10000個(gè)驗(yàn)證集。
注:驗(yàn)證集是模型訓(xùn)練過(guò)程中單獨(dú)留出的樣本集,它可以用于調(diào)整模型的超參數(shù)和用于對(duì)模型的能力進(jìn)行初步評(píng)估。
import?structtrain_num=50000valid_num=10000test_num=10000with open(train_img_path,'rb') as f: struct.unpack('>4i',f.read(16)) tmp_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28) train_img=tmp_img[:train_num] #前五萬(wàn)個(gè)數(shù)據(jù)是訓(xùn)練集 valid_img=tmp_img[train_num:] #第五萬(wàn)到第六萬(wàn)個(gè)數(shù)據(jù)是測(cè)試集 with open(test_img_path,'rb') as f: struct.unpack('>4i',f.read(16)) test_img=np.fromfile(f,dtype=np.uint8).reshape(-1,28*28)with open(train_lab_path,'rb') as f: struct.unpack('>2i',f.read(8)) tmp_lab=np.fromfile(f,dtype=np.uint8) train_lab=tmp_lab[:train_num] valid_lab=tmp_lab[train_num:]with open(test_lab_path,'rb') as f: struct.unpack('>2i',f.read(8))????test_lab=np.fromfile(f,dtype=np.uint8)因?yàn)?#xff0c;文件是以二進(jìn)制的格式儲(chǔ)存,所以數(shù)據(jù)讀取方式是‘rb’。又因?yàn)槲覀冃枰獢?shù)據(jù)以阿拉伯?dāng)?shù)字的方式顯示。所以這里用到了Python的struct包。struct.unpack('>4i',f.read(16))中的>號(hào)代表字節(jié)存儲(chǔ)的方向,i是整數(shù),4代表需要前4個(gè)整數(shù)。f.read(16)是指讀取16個(gè)字節(jié),即4個(gè)整數(shù),因?yàn)橐粋€(gè)整數(shù)等于4個(gè)字節(jié)。
reshape(-1,28*28):如果參數(shù)中存在-1,表示該參數(shù)由其他參數(shù)來(lái)決定.-1是將一維數(shù)組轉(zhuǎn)換為二維的矩陣,并且第二個(gè)參數(shù)是表示每一行數(shù)的個(gè)數(shù)。
注:fromfile的用法np.fromfile (frame,?dtype=np.float,?count=‐1,?sep=''),其中:frame : 文件、字符串。dtype :讀取的數(shù)據(jù)類型。count : 讀入元素個(gè)數(shù),‐1表示讀入整個(gè)文件。sep : 數(shù)據(jù)分割字符串。
文件讀取完成,接下來(lái)按照用圖片的方式顯示數(shù)據(jù)。
import matplotlib.pyplot as pltdef show_train(index): plt.imshow(train_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(train_lab[index]))def show_test(index): plt.imshow(train_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(test_lab[index]))def valid_train(index): plt.imshow(valid_img[index].reshape(28,28),cmap='gray') print('label:{}'.format(valid_lab[index]))注意,如果不定義cmap='gray',圖片的底色會(huì)非常奇怪。
? ? ? ?? ? ? ?
測(cè)試一下,定義完函數(shù)之后,顯示的是這樣的~
數(shù)據(jù)顯示和讀取完成,接下來(lái)開始訓(xùn)練參數(shù)。
訓(xùn)練數(shù)據(jù)
在開始之前,為了能夠上下銜接,我們把第一次課程的代碼貼上來(lái)~
def?tanh(x): return np.tanh(x)def softmax(x): exp = np.exp(x-x.max()) return exp/exp.sum()dimensions = [28*28,10]activation = [tanh,softmax]distribution=[{ 'b':[0,0]},{ 'b':[0,0], 'w':[-math.sqrt(6/(dimensions[0]+dimensions[1])),math.sqrt(6/(dimensions[0]+dimensions[1]))]}]# 初始化參數(shù)bdef init_parameters_b(layer): dist = distribution[layer]['b'] return np.random.rand(dimensions[layer])*(dist[1]-dist[0])+dist[0]# 初始化參數(shù)wdef init_parameters_w(layer): dist = distribution[layer]['w'] return np.random.rand(dimensions[layer-1],dimensions[layer])*(dist[1]-dist[0])+dist[0]#初始化參數(shù)方法def init_parameters(): parameter=[] for i in range(len(distribution)): layer_parameter={} for j in distribution[i].keys(): if j=='b': layer_parameter['b'] = init_parameters_b(i) continue; if j=='w': layer_parameter['w'] = init_parameters_w(i) continue parameter.append(layer_parameter) return parameter# 預(yù)測(cè)函數(shù)def predict(img,init_parameters): l0_in = img+parameters[0]['b'] l0_out = activation[0](l0_in) l1_in = np.dot(l0_out,parameters[1]['w'])+parameters[1]['b'] l1_out = activation[1](l1_in)??return?l1_out先定義兩個(gè)激活函數(shù)的導(dǎo)數(shù),導(dǎo)數(shù)的具體推到過(guò)程在這里不呈現(xiàn),感興趣的同學(xué)可以自行搜索。
def?d_softmax(data): sm = softmax(data) return np.diag(sm)-np.outer(sm,sm)def d_tanh(data): return 1/(np.cosh(data))**2differential = {softmax:d_softmax,tanh:d_tanh}其中tanh的導(dǎo)數(shù) 是np.diag(1/(np.cosh(data))**2),進(jìn)行優(yōu)化后的結(jié)果是1/(np.cosh(data))**2
注:diag生成對(duì)角矩陣?,outer函數(shù)的作用是第一個(gè)參數(shù)挨個(gè)乘以第二個(gè)參數(shù)得到矩陣
然后定義一個(gè)字典,并將數(shù)解析為某一位置為1的一維矩陣
differential?=?{softmax:d_softmax,tanh:d_tanh}onehot = np.identity(dimensions[-1])求平方差函數(shù),其中parameters是我們?cè)诘谝淮握n程定義的那個(gè)初始化的參數(shù),在訓(xùn)練的過(guò)程中,會(huì)自動(dòng)更新。
def?sqr_loss(img,lab,parameters): y_pred = predict(img,parameters) y = onehot[lab] diff = y-y_pred return np.dot(diff,diff)計(jì)算梯度
def?grad_parameters(img,lab,init_parameters): l0_in = img+parameters[0]['b'] l0_out = activation[0](l0_in) l1_in = np.dot(l0_out,parameters[1]['w'])+parameters[1]['b'] l1_out = activation[1](l1_in) diff = onehot[lab]-l1_out act1 = np.dot(differential[activation[1]](l1_in),diff) grad_b1 = -2*act1 grad_w1 = -2*np.outer(l0_out,act1) # 與上文優(yōu)化d_tanh有關(guān),將矩陣乘法化為數(shù)組乘以矩陣??grad_b0?=?-2*differential[activation[0]](l0_in)*np.dot(parameters[1]['w'],act1) return {'b1':grad_b1,'w1':grad_w1,'b0':grad_b0}這次的梯度計(jì)算公式用到了公式:(y_predict-y)^2,根據(jù)復(fù)合函數(shù)求導(dǎo),所以有-2(y_prdict-y)乘以相關(guān)的導(dǎo)數(shù),這也是grad_b1后面-2的來(lái)歷。
按理說(shuō)應(yīng)該更加導(dǎo)數(shù)的定義[f(x+h)-f(x)]/h驗(yàn)證下我們的梯度求的對(duì)不對(duì),為了照顧新手同學(xué)對(duì)神經(jīng)網(wǎng)絡(luò)的理解過(guò)程,這一步在這兒省略了哈。
下面進(jìn)入訓(xùn)練環(huán)節(jié),我們將數(shù)據(jù)以batch的方式輸入,每個(gè)batch定位包含100個(gè)圖片。batch_size=100。梯度的獲取是用平均求得的,代碼體現(xiàn)在:grad_accu[key]/=batch_size。
def?train_batch(current_batch,parameters): grad_accu = grad_parameters(train_img[current_batch*batch_size+0],train_lab[current_batch*batch_size+0],parameters) for img_i in range(1,batch_size): grad_tmp = grad_parameters(train_img[current_batch*batch_size+img_i],train_lab[current_batch*batch_size+img_i],parameters) for key in grad_accu.keys(): grad_accu[key] += grad_tmp[key] for key in grad_accu.keys(): grad_accu[key]/=batch_size return grad_accuimport copydef combine_parameters(parameters,grad,learn_rate): parameter_tmp = copy.deepcopy(parameters) parameter_tmp[0]['b'] -= learn_rate*grad['b0'] parameter_tmp[1]['b'] -= learn_rate*grad['b1'] parameter_tmp[1]['w'] -= learn_rate*grad['w1'] return parameter_tmp采用copy機(jī)制,是避免parameters變化影響全局的訓(xùn)練,copy.deepcopy可以重新拷貝不影響原來(lái)的數(shù)據(jù)。
并且這里用到了公式:
? ? ? ? ? ? ?
然后定義學(xué)習(xí)率:
def?learn_self(learn_rate): for i in range(train_num//batch_size): if i%100 == 99: print("running batch {}/{}".format(i+1,train_num//batch_size)) grad_tmp = train_batch(i,parameters) global parameters parameters = combine_parameters(parameters,grad_tmp,learn_rate)里面的if語(yǔ)句可以讓我們看到神經(jīng)網(wǎng)絡(luò)訓(xùn)練的進(jìn)度。
? ? ? ? ? ? ?
到這里,我們就完成了神經(jīng)網(wǎng)絡(luò)的一次訓(xùn)練,為了驗(yàn)證準(zhǔn)確度如何,我們可以用驗(yàn)證集看看準(zhǔn)確度如何。
定義驗(yàn)證集的損失:
def?valid_loss(parameters): loss_accu = 0 for img_i in range(valid_num): loss_accu+=sqr_loss(valid_img[img_i],valid_lab[img_i],parameters)??return?loss_accu計(jì)算準(zhǔn)確度:
def?valid_accuracy(parameters): correct = [predict(valid_img[img_i],parameters).argmax()==valid_lab[img_i] for img_i in range(valid_num) ]??print("validation?accuracy:{}".format(correct.count(True)/len(correct)))最后得到結(jié)果:
? ? ? ? ? ? ?
有90%的準(zhǔn)確度哎~結(jié)果還好,還好,畢竟沒(méi)有怎么調(diào)學(xué)習(xí)率以及解決過(guò)擬合。
好了,這一期的內(nèi)容就到這了,內(nèi)容有些多大家多多消化,下一期我們講講怎么調(diào)節(jié)學(xué)習(xí)率以及看看更復(fù)雜的神經(jīng)網(wǎng)絡(luò)。
*注:此篇文章受B站up主大野喵渣的啟發(fā),并參考了其代碼,感興趣的同學(xué)可以去B站觀看他關(guān)于神經(jīng)網(wǎng)絡(luò)的教學(xué)視頻,以及到他的Github地址逛逛。
視頻地址與Github:
https://www.bilibili.com/video/av51197008
https://github.com/YQGong
實(shí)習(xí)/全職編輯記者招聘ing
加入我們,親身體驗(yàn)一家專業(yè)科技媒體采寫的每個(gè)細(xì)節(jié),在最有前景的行業(yè),和一群遍布全球最優(yōu)秀的人一起成長(zhǎng)。坐標(biāo)北京·清華東門,在大數(shù)據(jù)文摘主頁(yè)對(duì)話頁(yè)回復(fù)“招聘”了解詳情。簡(jiǎn)歷請(qǐng)直接發(fā)送至zz@bigdatadigest.cn
點(diǎn)「在看」的人都變好看了哦
總結(jié)
以上是生活随笔為你收集整理的c++读取图片_手工计算神经网络第三期:数据读取与完成训练的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 版是什么版本的教材_acca教材有哪些版
- 下一篇: tictoc正方形网络模型_反卷积:可视