theano 模块 MLP示例,有需要的朋友可以参考下。
theano教程
Example: MLP:
约定数组为列向量,
层级:
将多层传感器定义为一连串的层级,每个层级定义为一个类。类属性包括:权重、偏差矢量、以及计算这一层输出的函数。
如果不使用Theano,我们可能希望输出函数会接收一个向量并返回图层的激活来响应输入。然而在Theano中输出函数反而是为了创造能够接收向量并返回图层激活的函数而创建的。因此我们要创建一个在类外部计算图层的激活。
Layer类:neural network 的一层用于计算非线性误差s = Wx+b 。其中x就是输入的向量。
class Layer(object): def __init__(self,W_init,b_init,activation): ''' W_init 是需要初始化的权重矩阵的值 (n_output,n_input) b_init 是需要初始化的偏差向量的值 (n_output,) activation 是图层激活函数 ''' #基于W的初始化来获得输入和输出的维度 n_output,n_input = W_init.shape #确定b是output的大小 assert b_init.shape == (n_output,) #所有参数都应该是共享变量,在类里用于计算图层的输出。但在优化网络参数时在类外更新。 #W_init 必须设置为 theano.config.floatX 字符类型。 self.W = theano.shared(value = W._init.astype(theano.config.floatX), #name 参数是专门用来打印 purporses name = 'w', #将borrow 设置为 True 来允许 theano 为对象使用用户的内存,可以避免对结构的深拷贝来使编码的速度快一点。 borrow = True, #theano 与numpy类似,允许广播,但是要明确的标示出需要被广播的坐标轴。通过设置 boardcastable = (False,True),来表示b能够沿着它的第二维广播,以便将他添加到其他变量。 broadcastable = (False,True)) self.activation = activation #计算关于列表中参数的网络成本的梯度。 self.params = [self.W,self.b] def ouput(self,x): ''' 参数: - x : theano.tensor.var.TensorVariable 图层输入的 theano 符号变量 返回: - output : theano.tensor.var.TensorVariable 混合的,有误差的,激活的 x ''' #计算线性组合 lin_output = T.dot(self.W,x) + self.b #如果缺少激活函数,那么返回的仅仅只是线性组合 #调用激活函数 return(lin_output if self.activation is None else self.activation(lin_output))
MLP类:大多数多层传感器的功能包含在 Layer 类中,MLP 类本质上是 Layer对象列表和相关的参数的容器。输出函数递归的计算每一图层的输出。squared_error:被给定输入的网络的输出和期望之间的欧氏距离的平方。这个函数的作用是估算建立在训练数据集上的最小成本。
综上,squared_error函数 和output 并不作为最终结果,相反,他们被用来计算得出最终结果。
class MLP(object): def __init__(self,W_init,b_init,activations): ''' Multi-layer perceprton class 用来计算图层序列的组成部分。 :参数 - W_init : list of np.ndarray, len=N 参数的值初始化为每一层的权重值 图层的大小应从 W_init 的 shape 属性中推断出 - b_init : list of np.ndarray, len=N 参数的值初始化为每一层的偏差向量 - activations : list of theano.tensor.elemwise.Elemwise, len=N Activation function for layer output for each layer ''' #确保输入列表的元素都是相同的大小 assert len(W_init) == len(b_init) == len(activations) #初始化图层列表 self.layers = [] #创建图层创建图层 for W , b , activation in zip (W_init,b_init,activations): self.layers.append(Layer(W,b,activation)) #从所有的图层中合并参数 self.params = [] for layer in self.layers: self.params += layer.params def output(self,x): ''' :parameters: - x : theano.tensor.var.TensorVariable 图层输入的 theano 符号变量 :returns: - output : theano.tensor.var.TensorVariable 通过 MLP 的 x ''' #递归计算输出 for layer in self.layers: x = layer.output(x) return x def squared_error(self,x,y): ''' 计算网络的输出相对与期望的欧几里得误差的平方 :parameters: - x : theano.tensor.var.TensorVariable 网络输入的 theano 的符号变量 - y : theano.tensor.var.TensorVariable 网络输出期望的 theano 的符号变量 :returns: - error : theano.tensor.var.TensorVariable x 和 y 之间的欧式误差的平方 ''' return T.sum((self.output(x) - y) ** 2)
梯度下降法:为了训练网络, 需要对训练数据集使用梯度下降法来降低成本(网络输出相对于期望的欧式误差的平方)。做神经网络的梯度下降法时, 常用方法是 momentum (动量), 也就是对参数更新进行有漏积分 : 在更新参数时, 计算当前梯度更新和之前的梯度更新的线性组合. 这往往使得网络在一个相对好的结果上更快的收敛,同时能够帮助避免成本函数中的局部极小值. 使用传统的梯度下降法你能够保证在每次迭代过程中降低成本. 当我们使用 momentum 时没有这个保证, 但在一般情况下,momentum 通常为这种改良提供了足够小的成本。
在 theano 中,我们把之前的更新储存为一个共享变量,因此它的值能在迭代过程中被保留. 于是, 在梯度更新中, 我么不仅仅只更新参数, 也同时更新之前的参数更新得到共享变量。
def gradient_updates_momentum(cost,params,learning_rate,momentum): ''' 利用 momentum 计算梯度下降的更新 :parameters: - cost : theano.tensor.var.TensorVariable Theano cost function to minimize - params : list of theano.tensor.var.TensorVariable Parameters to compute gradient against - learning_rate : float Gradient descent learning rate - momentum : float Momentum parameter, should be at least 0 (standard gradient descent) and less than 1 :returns: updates : list List of updates, one for each parameter ''' #确保 momentum 是一个 合理的值 assert momentum >0 and momentum <1 #每个参数的更新步骤列表 updates = [] #对成本应用梯度下降 for param in params: #为每个参数创建一个共享变量 param_update #这个变量会在迭代过程中持续跟踪参数的更新步骤 #param_update 初始化为0 param_update = theano.shared(param.get_value()*0.,broadcastable = param.broadcastable) #每个参数沿梯度方向移动一步完成更新。 #但是我们也根据给定的 momentum 的值“混入”之前的步骤 #所以,在更新 param_update 时,需要的变量是:前一步的 momentum 的值和新的梯度步骤 updates.append(param,param - learning_rate*param_update) #我们不需要推导计算更新的反向传播算法,用 T.grad 即可。 updates.append((param_update , momentum*param_update+(1.-momentum)*T.grad(cost,param))) return updates