【theano-windows】学习笔记八——预备知识
前言
按照上一個(gè)博客所說的,直接按照深度學(xué)習(xí)0.1文檔進(jìn)行學(xué)習(xí),當(dāng)然在此之前我們需要了解這一系列教程所需要的數(shù)據(jù)集,以及一些概念性的東西
國(guó)際慣例,參考博客網(wǎng)址:
深度學(xué)習(xí)0.1文檔
深度學(xué)習(xí)0.1文檔-中文翻譯
基于梯度的學(xué)習(xí)
數(shù)據(jù)集網(wǎng)址
網(wǎng)盤下載鏈接: https://pan.baidu.com/s/1bpvqwDT 密碼: 7c2w
在進(jìn)行操作前先導(dǎo)入基本的模塊
#-*- coding:utf-8 -*- import cPickle,gzip import numpy as np import theano import theano.tensor as T數(shù)據(jù)集簡(jiǎn)介
就是把Lecun大佬的手寫數(shù)字?jǐn)?shù)據(jù)集MNIST做了個(gè)序列化,并且分成了機(jī)器學(xué)習(xí)所需要的三種基本數(shù)據(jù)集:
- 訓(xùn)練集: 學(xué)習(xí)模型參數(shù)
- 驗(yàn)證集: 執(zhí)行模型選擇和超參數(shù)的選擇
- 測(cè)試集: 測(cè)試訓(xùn)練好的模型的分辨能力即泛化能力
下載完數(shù)據(jù)集以后, 就可以進(jìn)行讀取操作
#導(dǎo)入數(shù)據(jù)集 f=gzip.open('mnist.pkl.gz','rb') train_set,valid_set,test_set=cPickle.load(f) f.close() #train_set中存儲(chǔ)了數(shù)據(jù)和標(biāo)簽 a,b=train_set print a.shape#輸出數(shù)據(jù)大小(50000L, 784L) print b.shape#輸出標(biāo)簽大小(50000L,)為了訓(xùn)練性能著想, 教程建議將數(shù)據(jù)集存儲(chǔ)在共享變量中, 并且通過小批索引的方式獲取數(shù)據(jù)集. 存儲(chǔ)到共享變量中的原因與使用GPU有關(guān). 將數(shù)據(jù)拷貝到GPU內(nèi)存中需要很大功耗.如果按需拷貝(每次使用到的小批數(shù)據(jù)), 由于上述所說的功耗問題, GPU的代碼運(yùn)行效率并不會(huì)比CPU快, 很可能更慢. 一旦存儲(chǔ)在共享變量中, theano就可以在構(gòu)建共享變量的時(shí)候一次性拷貝GPU上所有的數(shù)據(jù)集. 隨后GPU可以通過從共享變量中利用切片來獲取小批數(shù)據(jù), 無需從CPU內(nèi)存中拷貝任何信息,因而避免了功耗.
注意由于數(shù)據(jù)點(diǎn)和它們的標(biāo)簽往往具有不同的本質(zhì)(標(biāo)簽常是整型的,但是數(shù)據(jù)嘗嘗是實(shí)值), 因而我們建議對(duì)數(shù)據(jù)和標(biāo)簽采用不同的變量存儲(chǔ), 現(xiàn)將所有的數(shù)據(jù)存儲(chǔ)為float, 然后再將標(biāo)簽用theano.tensor.cast轉(zhuǎn)換為int類型
#最好將數(shù)據(jù)集放入到共享變量中 def shared_dataset(data_xy):data_x,data_y=data_xyshared_x=theano.shared(np.asarray(data_x,dtype=theano.config.floatX))shared_y=theano.shared(np.asarray(data_y,dtype=theano.config.floatX))return shared_x,T.cast(shared_y,'int32') train_set_x,train_set_y=shared_dataset(train_set) test_set_x,test_set_y=shared_dataset(test_set) valid_set_x,valid_set_y=shared_dataset(valid_set) batch_size=500 #假裝獲取第三批數(shù)據(jù)(批索引是0,1,2,3.....) data=train_set_x[2*batch_size:3*batch_size] label=train_set_y[2*batch_size:3*batch_size]深度學(xué)習(xí)的監(jiān)督優(yōu)化基礎(chǔ)
分類器
0-1損失
l0,1=∑i=1|D|If(x(i))≠y(i)
目的是最小化沒有見過的樣本的最小錯(cuò)誤量. 如果用f:RD→0,?,L代表預(yù)測(cè)函數(shù), 那么損失可以被寫為
其中I稱為示性函數(shù)
Ix={1if x is True0otherwise
在本實(shí)例中, 預(yù)測(cè)函數(shù)的定義為
f(x)=argmaxkP(Y=k|x,θ)
上式的含義就是樣本x在模型參數(shù)θ中, 屬于每個(gè)標(biāo)簽中概率最大的是第k個(gè)標(biāo)簽. 在theano中, 損失函數(shù)的實(shí)現(xiàn)可以寫成: #0-1損失zero_one_loss=T.sum(T.neq(T.argmax(p_y_given_x),y))負(fù)對(duì)數(shù)似然
#最小化負(fù)對(duì)數(shù)似然NLL=- T.sum(T.log(p_y_given_x)[T.arange(y.shape[0]),y])
可以發(fā)現(xiàn)0-1損失是不可微的(它僅僅是是與不是)的加和. 所以我們看預(yù)測(cè)函數(shù), 只要使得模型預(yù)測(cè)出真實(shí)標(biāo)簽的概率P(Y=真實(shí)標(biāo)簽|x(i);θ)最大即可,然后我們通常使用極大對(duì)數(shù)似然來解決這個(gè)最大化問題:
L(θ,D)=∑i=0|D|logP(Y=y(i)|x(i);θ)
可以發(fā)現(xiàn)這個(gè)損失函數(shù)的值并非0-1損失那樣帶包正確預(yù)測(cè)的數(shù)量, 但是從隨機(jī)初始化的分類器來看, 它們是非常相似的. 為了跟我們經(jīng)常說的最小化損失函數(shù)保持一致, 可以定義最小化負(fù)對(duì)數(shù)似然(NLL)函數(shù):
$$ NLL(\theta,D)=-\sum_{i=0}^{|D|}\log P(Y=y^{(i)}|x^{(i)};\theta) $$
在theano`中實(shí)現(xiàn)它:代碼標(biāo)注: 看大括號(hào)里面的[T.arange(y.shape[0]),y], 第一項(xiàng)T.arange(y.shape[0])代表的就是樣本索引從0-n, 第二項(xiàng)就是每個(gè)樣本的標(biāo)簽值.這句話說白了就是從概率矩陣p_y_given_x中取出第i個(gè)樣本對(duì)應(yīng)的標(biāo)簽為y(i)的概率
隨機(jī)梯度下降
普通的梯度下降法: 是沿著一些參數(shù)所定義的損失函數(shù)的誤差表面下降一小步, 如此反復(fù)不斷下降. 訓(xùn)練集是大批量進(jìn)入損失函數(shù)的, 偽代碼如下:
while True:loss = f(params)d_loss_wrt_params = ... # compute gradientparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params隨機(jī)梯度下降(SGD): 與普通的梯度下降原則上相同, 但是處理速度更快, 因?yàn)閮H僅從部分樣本中估算梯度, 極端情況下就是從一個(gè)時(shí)間僅僅從一個(gè)單一樣本中估算梯度
# STOCHASTIC GRADIENT DESCENTfor (x_i,y_i) in training_set:# imagine an infinite generator# that may repeat examples (if there is only a finite training set)loss = f(params, x_i, y_i)d_loss_wrt_params = ... # compute gradientparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params而在深度學(xué)習(xí)中, 我們比較建議采用小批量隨機(jī)梯度下降(Minibatch SGD)方法, 一次采用多于一個(gè)的訓(xùn)練樣本去計(jì)算梯度
for (x_batch,y_batch) in train_batches:# imagine an infinite generator# that may repeat examplesloss = f(params, x_batch, y_batch)d_loss_wrt_params = ... # compute gradient using theanoparams -= learning_rate * d_loss_wrt_paramsif <stopping condition is met>:return params特別注意: 如果你訓(xùn)練固定次數(shù), 批大小的設(shè)置對(duì)于參數(shù)的更新控制是非常重要的. 對(duì)批大小為1的數(shù)據(jù)訓(xùn)練十次與對(duì)批大小為20的數(shù)據(jù)訓(xùn)練十次, 達(dá)到的效果完全不同, 記住當(dāng)改變批大小的時(shí)候, 要據(jù)此調(diào)整其他的參數(shù).
批量隨機(jī)梯度下降在theano中實(shí)現(xiàn)如下:
d_loss_wrt_params=T.grad(loss,params) updates=[(params,params-learning_rate*d_loss_wrt_params)] MSGD=theano.function([x_batch,y_batch],loss,updates=updates) for (x_batch,y_batch) in train_batches:print ('Current loss is ',MSGD(x_batch,y_batch))if stopping_condition_is_met:return param
正則項(xiàng)
概念就不說了, 機(jī)器學(xué)習(xí)里面常用的減少過擬合方法, 一般采用L1或者L2正則項(xiàng). 這里還說到了提前停止(early-stopping)也是正則化的一種方法. 詳細(xì)請(qǐng)看周志華老師《機(jī)器學(xué)習(xí)》P105頁緩解過擬合方法
L1和L2正則項(xiàng)
NLL(θ,D)=?∑i=0|D|logP(Y=y(i)|x(i);θ)
就是在損失函數(shù)后面添加一個(gè)額外項(xiàng), 用于乘法某些參數(shù)
正常情況下, 我們的損失函數(shù)是這樣
加了正則項(xiàng)以后可能是這樣
E(θ,D)=NLL(θ,D)+λR(θ)orE(θ,D)=NLL(θ,D)+λ||θ||pp
其中||θ||p=(∑|θ|j=0|θj|p)1p, 這就是傳說中的p范數(shù), 當(dāng)p=2的時(shí)候就代表二范數(shù), 而且也就是傳說中的權(quán)重衰減原則上來說, 在損失上增加正則項(xiàng)能夠增強(qiáng)神經(jīng)網(wǎng)絡(luò)的平滑映射(通過乘法參數(shù)中較大的值, 減少了網(wǎng)絡(luò)的非線性程度). 最小化損失函數(shù)與正則項(xiàng)的和能夠在訓(xùn)練集的擬合與一般解之間找到權(quán)衡. 為了遵循奧卡姆剃須刀準(zhǔn)則(‘如無必要, 勿增實(shí)體’), 它們兩個(gè)的最小化能夠幫助我們找到最簡(jiǎn)單的解.
L1 = T.sum(abs(param))#L1范數(shù) L2 = T.sum(param ** 2)#L2范數(shù) loss = NLL + lambda_1 * L1 + lambda_2 * L2#損失+L1正則+L2正則提前停止: 通過觀察模型在驗(yàn)證集上的性能來減少過擬合. 如果模型在驗(yàn)證集上停止了提升或者出現(xiàn)退化, 就需要我們停止優(yōu)化了. 關(guān)于何時(shí)停止, 這是一個(gè)判斷, 并且很多啟發(fā)式算法存在, 這里提供了一個(gè)幾何增加耐心量的算法:
# 提前停止方法patience = 5000 # 迭代結(jié)束條件就看這個(gè)值與迭代多少次batch的iter大小 patience_increase = 2 # 結(jié)束時(shí)間延長(zhǎng) improvement_threshold = 0.995 # 小于這個(gè)值就認(rèn)為性能沒有被再提升 validation_frequency = min(n_train_batches, patience/2)#驗(yàn)證頻率best_params = None best_validation_loss = numpy.inf test_score = 0. start_time = time.clock()done_looping = False#是否結(jié)束循環(huán) epoch = 0 while (epoch < n_epochs) and (not done_looping):epoch = epoch + 1#當(dāng)前迭代次數(shù)for minibatch_index in range(n_train_batches):#當(dāng)前迭代的批索引d_loss_wrt_params = ... # 計(jì)算梯度params -= learning_rate * d_loss_wrt_params # 參數(shù)更新# 從第0次開始迭代,計(jì)算得到當(dāng)前迭代的累計(jì)批索引iter = (epoch - 1) * n_train_batches + minibatch_indexif (iter + 1) % validation_frequency == 0:#使用0-1損失驗(yàn)證性能提升this_validation_loss = ... if this_validation_loss < best_validation_loss:#如果性能還在提升if this_validation_loss < best_validation_loss * improvement_threshold:#如果性能提升超過閾值,那么繼續(xù)迭代patience = max(patience, iter * patience_increase)best_params = copy.deepcopy(params)best_validation_loss = this_validation_loss#看看是否已經(jīng)到達(dá)迭代終止時(shí)間if patience <= iter:done_looping = Truebreak這個(gè)代碼的意思就是迭代結(jié)束的條件一是達(dá)到了最大的迭代次數(shù)n_epoch,另一個(gè)就是利用patience控制是否提前結(jié)束迭代. 如果迭代過程中性能提升超過閾值, 就考慮將patience提升一下max(patience,iter*patience_increase), 反之性能并未提升或者達(dá)到穩(wěn)定情況(閾值范圍之內(nèi)), 那么就對(duì)比當(dāng)前patience與總共使用批樣本訓(xùn)練的次數(shù)(每次使用一批樣本就將iter+1), 一旦iter超過了patience就停止訓(xùn)練了
注意: 這個(gè)驗(yàn)證頻率validation_frequency要比patience小, 至少要在一次patience迭代期間驗(yàn)證過兩次.所以使用了 validation_frequency = min( value, patience/2.)
測(cè)試
當(dāng)循環(huán)完畢, 得到的參數(shù)是驗(yàn)證集上效果最好的參數(shù). 這樣我們使用同一個(gè)訓(xùn)練集、測(cè)試集、驗(yàn)證集去訓(xùn)練多個(gè)模型, 我們比較每個(gè)模型最好的驗(yàn)證集損失, 就認(rèn)為我們選擇了最好的模型.
簡(jiǎn)單總結(jié)
三個(gè)數(shù)據(jù)集: 訓(xùn)練集、驗(yàn)證集、測(cè)試集
優(yōu)化方法: 訓(xùn)練集被用于目標(biāo)函數(shù)的可微近似的批量隨機(jī)梯度下降中
選擇模型: 看模型在驗(yàn)證集上的性能能表現(xiàn)
存儲(chǔ)和讀取模型參數(shù)
存儲(chǔ)模型參數(shù)
save_file = open('path', 'wb') cPickle.dump(w.get_value(borrow=True), save_file, -1) cPickle.dump(v.get_value(borrow=True), save_file, -1) cPickle.dump(u.get_value(borrow=True), save_file, -1) save_file.close()讀取模型參數(shù)
save_file = open('path') w.set_value(cPickle.load(save_file), borrow=True) v.set_value(cPickle.load(save_file), borrow=True) u.set_value(cPickle.load(save_file), borrow=True)關(guān)于borrow看這里, 大概就是如果borrow=True, 那么對(duì)原始變量的更改會(huì)對(duì)當(dāng)前的共享變量產(chǎn)生影響, 還是把例子貼出來吧
import numpy, theano np_array = numpy.ones(2, dtype='float32')s_default = theano.shared(np_array) s_false = theano.shared(np_array, borrow=False) s_true = theano.shared(np_array, borrow=True) np_array += 1 # now it is an array of 2.0 sprint(s_default.get_value()) print(s_false.get_value()) print(s_true.get_value()) ''' [ 1. 1.] [ 1. 1.] [ 2. 2.] '''【注】我可能用了假theano, 這個(gè)例子在我的環(huán)境中執(zhí)行竟然結(jié)果都是[1,1]
后續(xù)
數(shù)據(jù)集和一些基本的訓(xùn)練方法都搞定了, 下一步就得實(shí)戰(zhàn)一波了
- logistic回歸分類手寫數(shù)字
- 多層感知器
- 卷積
- 去噪自編碼dAE
- 堆疊去噪自編碼SdAE
- 受限玻爾茲曼機(jī)RBM
- 深度信念網(wǎng)
- 混合蒙特卡洛采樣
- LSTM
- RNN-RBM
總結(jié)
以上是生活随笔為你收集整理的【theano-windows】学习笔记八——预备知识的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 六大国有银行手机银行跨行转账要手续费吗?
- 下一篇: 【theano-windows】学习笔记