深度學習框架之一:Theano | Lasagne簡單教程
參考Lasagne官網(http://lasagne.readthedocs.io/en/latest/)tutorial進行總結而來。
01
簡介
Lasagne is a lightweight library to build and train neural networks in Theano.
Lasagen是一個基於Theano的輕量級的神經網路庫。其實就是對Theano庫的上層封裝,使其用起來更簡單,但是相應的靈活性下降。
Lasagne設計的六個原則是簡潔、透明、模組化、實用、聚焦和專注。
官網地址:http://lasagne.readthedocs.io/en/latest/index.html GitHub: https://github.com/Lasagne/Lasagne
02
安裝
本質上來說Lasagne還是個python庫,所以它的安裝還是很簡單的,通過pip就可以安裝了。整個安裝就兩步:安裝依賴包和安裝Lasagen.
官網有很詳細的安裝教程(http://lasagne.readthedocs.io/en/latest/user/installation.html)。
穩定版安裝
執行下面兩條命令即可:
pip install -r https://raw.githubusercontent.com/Lasagne/Lasagne/v0.1/requirements.txt pip install Lasagne==0.1
Bleeding-edge version
執行下面兩條命令:
pip install --upgrade https://github.com/Theano/Theano/archive/master.zip pip install --upgrade https://github.com/Lasagne/Lasagne/archive/master.zip
開發版安裝
執行下面命令
git clone https://github.com/Lasagne/Lasagne.git cd Lasagne pip install -r requirements.txt pip install --editable
這裡建議安裝Bleeding-edge version,功能相對比較新,而版本也相對穩定。
03
Tutorial
教程還是以經典的mnist資料集的字元識別為例。
整個過程分為以下幾個部分:
- Loading data/載入資料(http://lasagne.readthedocs.io/en/latest/user/tutorial.html#loading-data)
- Building the model/建立模型(http://lasagne.readthedocs.io/en/latest/user/tutorial.html#building-the-model)
- Training the model/訓練模型(http://lasagne.readthedocs.io/en/latest/user/tutorial.html#training-the-model)
下面分別介紹這幾個部分。
1、載入資料
這個和其它庫的資料載入方法差不多,都是採用python語法處理資料,沒有太多特殊之處,這裡就不詳細介紹了,具體的可以查閱原始碼mnist.py(https://github.com/Lasagne/Lasagne/blob/master/examples/mnist.py)
2、建立模型
和所有的框架一樣,非常重要的一個環節就是進行網路模型的定義。Lasagne的網路模型建立方法和torch比較相似,都是對各種常用網路層(layer)進行了封裝,我們只需要呼叫相應的網路層函式並把它們搭接在一起就可以了,就像蓋房子一樣。
下面以建立多層感知機、卷積神經網路等模型為例進行介紹。
多層感知機
多層感知機(Multi-Layer Perceptron, MLP)(http://lasagne.readthedocs.io/en/latest/user/tutorial.html#multi-layer-perceptron-mlp)
這裡以構建一個兩個隱藏層的多層感知機為例,並對輸入增加20%的dropout、隱藏層增加50%的dropout。
實際上,我們網路模型就由輸入層+兩個隱藏層+輸出層組成,只需要對其分別進行定義即可。
** 輸入層 **
輸入層採用InputLayer進行定義,InputLayer只用於接收資料,不對資料做任何處理,類似於tensorfolw裡的placeholder功能。定義方法如下:
l_in = lasagne.layers.InputLayer(shape=(None, 1, 28, 28), input_var=input_var)
shape裡對應的四個引數分別表示:(batchsize, channels, rows, columns),input_var表示需要連線到網路輸入層的theano變數,預設為none。
然後對輸入資料加以20%的dropout,採用DropoutLayer進行定義:
l_in_drop = lasagne.layers.DropoutLayer(l_in, p=0.2)
p=0.2表示dropout的比例。DropoutLayer也屬於layers裡的一個元件,也可以簡寫為dropout。
** 隱藏層 ** 這裡的隱藏層由全連線層、啟用層、dropout層組成。Lasagne將全連線層和啟用層封裝到一個函式裡了,即DenseLayer,定義如下:
l_hid1 = lasagne.layers.DenseLayer( l_in_drop, num_units=800, nonlinearity=lasagne.nonlinearities.rectify, W=lasagne.init.GlorotUniform
())
num_units表示全連線層的單元數目,nonlinearity用以定義啟用層函式,啟用層函式封裝在lasagne.nonlinearities中,這裡選擇的是ReLU函式,而網路引數的初始化封裝在lasagne.init裡,只需要分別進行呼叫就可以了。
之後新增50%的dropou:
l_hid1_drop = lasagne.layers.DropoutLayer(l_hid1, p=0.5)
第二個隱藏層的定義與此類似,這裡就不贅述了。
** 輸出層 ** 輸出層依然是一個全連線網路,只是不同的是這裡是做分類任務,所以需要將非線性函式/啟用函式修改為softmax,如下:
l_out = lasagne.layers.DenseLayer( l_hid2_drop, num_units=10, nonlinearity=lasagne.nonlinearities.softmax)
這樣就得到了一個含兩個隱藏層的多層感知機了。當然,我們也可以像官網一樣將一些網路設定引數作為函式變數輸入,建立可自定義的多層感知機。
卷積神經網路
這裡以建立一個含兩個卷積層的神經網路為例。網路模型的具體組成包括輸入層、兩個卷積層、全連線層、輸出層。
** 輸入層 ** 輸入層的定義和前面一樣,不再贅述。
** 卷積層 ** 卷積層採用Conv2DLayer進行定義,定義如下:
network = lasagne.layers.Conv2DLayer( network, num_filters=32, filter_size=(5, 5), nonlinearity=lasagne.nonlinearities.rectify, W=lasagne.init.GlorotUniform())
num_filters表示卷積核的數目,filter_size表示卷積核的大小,啟用函式和引數初始化和DenseLayer類似。當然,我們還可以定義padding、stride等引數,具體方法可以檢視Conv2DLayer的幫助。
值得注意的是lasagne預設採用的是theano的卷積實現方法,如果配置了gpu就會呼叫Nvidia提供的cuDNN實現。lasagne也提供了一些其它的實現方法:
lasagne.layers.dnn.Conv2DDNNLayer to enforce cuDNN, lasagne.layers.corrmm.Conv2DMMLayer to enforce the gemm-based one, lasagne.layers.cuda_convnet.Conv2DCCLayer for Krizhevsky’s cuda-convnet.
一般情況,我們會在卷積層後加上pooling層,其中maxpool採用函式MaxPool2DLayer進行定義:
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))
pool_size表示pooling的大小。當然我們也可以採用Pool2DLayer定義meanPool等。
之後的第二個卷積層、全連線層、輸出層的定義與前面類似,此處不再贅述。
通過前面mlp和cnn的定義可以發現,在lasagne裡定義網路,只需要在lasagne.layers裡呼叫對應的網路層函式然後按照一定的結構組裝起來即可。
關於lasagne.layers的詳細使用可以查閱官方文件lasagne.layers(http://lasagne.readthedocs.io/en/latest/modules/layers.html)
3、訓練模型
和一般的深度學習框架類似,我們還需要定義訓練模型,包括:損失函式、更新/優化函式等。在Lasagne裡,或者更準確的說是在Theano裡,一般是將網路模型、訓練模型整合在一塊兒定義一個function,然後再將訓練資料/測試資料作為函式的自變數輸入到函式中,而輸入資料通過tensor來進行定義,網路引數通過shared來更新並儲存。tensorflow和這個其實是有點類似,tensorflow是將網路模型、訓練模型等等整合成一個計算圖,定義一個placeholder接收資料,而網路引數通過Variable來保持。
下面,通過程式碼來進行說明。
資料準備
通過Theano裡的tensor進行定義:
# Prepare Theano variables for inputs and targets input_var = T.tensor4('inputs') target_var = T.ivector('targets')
這兩個變數作為訓練函式的自變數,在實際訓練時只需要將真實的訓練資料帶入了函式中即可。
損失和更新函式定義
損失和更新函式定義(http://lasagne.readthedocs.io/en/latest/user/tutorial.html#loss-and-update-expressions)
通過呼叫lasagne.objectives裡的損失函式來定義不同的損失函式:
prediction = lasagne.layers.get_output(network) loss = lasagne.objectives.categorical_crossentropy(prediction, target_var) loss = loss.mean()
這裡的network是前面定義的網路模型,prediction表示網路模型的輸出表達式。這裡的的損失函式採用的是categorical_crossentropy。
驗證集和測試集上的定義與此類似,只是我們需要更改deterministic為deterministic=True,這樣會遮蔽掉所有的dropout層:
test_prediction = lasagne.layers.get_output(network, deterministic=True) test_loss = lasagne.objectives.categorical_crossentropy(test_prediction, target_var) test_loss = test_loss.mean()
有了網路模型和損失函式的定義後,還需要定義網路訓練與引數更新方法的表示式,一般採用梯度下降方法。更新方法通過呼叫lasagne.updates裡的更新函式來進行定義,這裡採用的是Stochastic Gradient Descent (SGD) with Nesterov momentum,即nesterov_momentum:
params = lasagne.layers.get_all_params(network, trainable=True) updates = lasagne.updates.nesterov_momentum( loss, params, learning_rate=0.01, momentum=0.9
)
這裡我們第一步需要先獲取所有的網路引數,然後產生更新引數的更新表示式。
compliation
最後,就是基於前面的表示式定義一步訓練函式:
train_fn = theano.function([input_var, target_var], loss, updates=updates)
這個函式是告訴Theano生成一個訓練函式,接收兩個輸入input_var, target_var,然後計算trainning loss並返回,之後利用updates表示式更新引數。
如果是用於驗證和測試,我們就不需要進行網路引數的更新,這時這樣定義:
val_fn = theano.function([input_var, target_var], [test_loss, test_acc])
對於測試精度,採用下面定義:
test_acc = T.mean(T.eq(T.argmax(test_prediction, axis=1), target_var), dtype=theano.config.floatX
)
前面的這麼多定義,其實並沒有進行正式的計算,就像是tensorflow裡的計算圖定義。其實就像是我們在高中的時候解一道數學題,往往都是先把最終的符號表達式推匯出來,最後再把輸入x代入表示式計算結果y。
Theano的當初的誕生其實也是基於這個需求的,當時python的Numpy、Scipy等庫主要用於數值計算,但是需要一種能夠呼叫庫就得到導數的符號表達式的庫,所以就有了後來的Theano,所以本質上來說早期的Theano的定位是一個融合符號運算與數值計算的數學計算庫。
迴圈訓練
有了一步訓練表示式後就可以將真實的資料輸入到函式中進行迴圈訓練了:
for epoch in range(num_epochs):
# In each epoch, we do a full pass over the training data:
train_err = 0
train_batches = 0
start_time = time.time()
for batch in iterate_minibatches(X_train, y_train, 500, shuffle=True):
inputs, targets = batch
train_err += train_fn(inputs, targets)
train_batches += 1
# And a full pass over the validation data:
val_err = 0
val_acc = 0
val_batches = 0
for batch in iterate_minibatches(X_val, y_val, 500, shuffle=False):
inputs, targets = batch
err, acc = val_fn(inputs, targets)
val_err += err
val_acc += acc
val_batches += 1
# Then we print the results for this epoch:
print("Epoch {} of {} took {:.3f}s".format(
epoch + 1, num_epochs, time.time() - start_time))
print(" training loss:tt{:.6f}".format(train_err / train_batches))
print(" validation loss:tt{:.6f}".format(val_err / val_batches))
print(" validation accuracy:tt{:.2f} %".format(
val_acc / val_batches * 100))
以上就是Lasagne的簡單使用方法的,還是挺簡單的,跟著教程走,基本上一個小時就搞定了。如果要學習Theano庫的其它一些用法以及各種函式的具體使用方法,建議查詢官方文件裡的API,主要包括:
- all layers(lasagne.layers)
- weight initializers (lasagne.init)
- nonlinearities (lasagne.nonlinearities)
- loss expressions (lasagne.objectives)
- training methods (lasagne.updates)
- regularizers (lasagne.regularization)
- lasagne.random
- lasagne.utils