模型
這裡,我們將使用Theano實現最基本的分類器:邏輯迴歸,以及學習數學表示式如何對映成Theano圖。
邏輯迴歸是一個基於概率的線性分類器,W和b為引數。通過投射輸入向量到一組超平面,每個對應一個類,輸入到一個平面的距離反應它屬於對應類的概率。
那麼輸入向量x為i類的概率,數值表示如下:
預測類別為概率最大的類,及:
用Theano實現的程式碼如下:
# initialize with 0 the weights W as a matrix of shape (n_in, n_out) self.W = theano.shared( value=numpy.zeros( (n_in, n_out), dtype=theano.config.floatX ), name='W', borrow=True ) self.b = theano.shared( value=numpy.zeros( (n_out), dtype=theano.config.floatX ), name='b', borrow=True ) self.p_y_given_x = T.nnet.softmax(T.dot(input, self.W) + self.b) self.y_pred = T.argmax(self.p_y_given_x, axis=-1)
模型的引數在訓練中維持一個持久的狀態,我們將W,b設為共享變數,也是Theano符號變數。
目前定義的模型還沒有做任何有用的事情,接下來將介紹如何學習最優引數。
定義損失函式(Loss Function)
對於多類迴歸,常見的是使用negative log-likelihood作為損失。
在引數θ下,最大化資料集D的似然函式,讓我們先定義似然函式和損失:
這裡使用隨機梯度下降的方法求最小值。
建立邏輯迴歸類
程式碼請參考源網址:http://www.deeplearning.net/tutorial/logreg.html
def negative_log_likelihood(self, y):
'''
:type y: theano.tensor.TensorType
:param y: correct label
:return:
Note: 我們使用mean而不是sum是為了學習率更少地依賴於batch size
p_y_given_x是vector型別
'''
# y.shape返回y的行數和列數,則y.shape[0]返回y的行數,即樣本的總個數,因為一行是一個樣本。
# T.arange(n),則是產生一組包含[0,1,...,n-1]的向量。
# T.log(x),則是對x求對數。記為LP
# LP[T.arange(y.shape[0]),y]是一組向量,其元素是[ LP[0,y[0]], LP[1,y[1]],
# LP[2,y[2]], ...,LP[n-1,y[n-1]] ]
# T.mean(x),則是求向量x中元素的均值。
return -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y])
def errors(self, y):
if y.ndim != self.y_pred.ndim:
raise TypeError('y should have the same shape as self.y_pred',
('y',y.type, 'y_pred', self.y_pred.type))
if y.dtype.startwith('int'):
# T.neq(y1, y2)是計算y1與y2對應元素是否相同,如果相同便是0,否則是1。
# 舉例:如果y1=[1,2,3,4,5,6,7,8,9,0] y2=[1,1,3,3,5,6,7,8,9,0]
# 則,err = T.neq(y1,y2) = [0,1,0,1,0,0,0,0,0,0],其中有3個1,即3個元素不同
# T.mean()的作用就是求均值。那麼T.mean(err) = (0+1+0+1+0+0+0+0+0+0)/10 = 0.3,即誤差率為30%
return T.mean(T.neq(self.y_pred, y))
else:
raise NotImplementedError()
訓練模型
若要在大多數的程式語言中實現梯度下降演算法,需要手動的推匯出梯度表示式,這是一個非常麻煩的推導,而且最終結果也很複雜,特別是考慮到數值穩定性的問題的時候。
然而,在Theano這個工具中,這個變得異常簡單。因為它已經把求梯度這種運算給封裝好了,不需要手動推導公式,只需要按照格式傳入資料即可。
g_W = T.grad(cost=cost, wrt=classifier.W) g_b = T.grad(cost=cost, wrt=classifier.b) updates = [(classifier.W, classifier.W - learning_rate * g_W), (classifier.b, classifier.b - learning_rate * g_b)] train_model = theano.function( inputs=[index], outputs=cost, updates=updates, givens={ x: train_set_x[index * batch_size: (index + 1) * batch_size], y: train_set_y[index * batch_size: (index + 1) * batch_size] } )
每一次呼叫train_model(index),都會計算並返回輸入樣本塊的cost,然後執行一次MSGD,並更新W和b。整個學習演算法的一次迭代這樣迴圈呼叫train_model (總樣本數/樣本塊數)次。假設總樣本60000個,一個樣本塊600個,那麼一次迭代就需要呼叫100次train_model。而模型的訓練又需要進行多次迭代,直到達到迭代次數或者誤差率達到要求。
測試模型
驗證模型和測試模型的不同之處在於計算所用的資料不一樣,驗證模型用的是驗證資料集。
As you will see shortly, validate_model
is key to our early-stopping implementation .
test_model = thenao.function(
inputs = [index],
outputs = classifier.errors(y),
givens = {
x: test_set_x[index * batch_size: (index + 1) * batch_size],
y: test_set_y[index * batch_size: (index + 1) * batch_size]
}
)
validate_model = theano.function(
inputs=[index],
outputs=classifier.errors(y),
givens={
x: valid_set_x[index * batch_size: (index + 1) * batch_size],
y: valid_set_y[index * batch_size: (index + 1) * batch_size]
}
)
完整程式碼
略(請參考官方教程)
參考目錄
1.深度學習(DL)與卷積神經網路(CNN)學習筆記隨筆-03-基於Python的LeNet之LR
2.官方教程