模型
这里,我们将使用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.官方教程