zoukankan      html  css  js  c++  java
  • [DL] 基于theano.tensor.dot的逻辑回归代码中的SGD部分的疑问探幽

    在Hinton的教程中, 使用Python的theano库搭建的CNN是其中重要一环, 而其中的所谓的SGD - stochastic gradient descend算法又是如何实现的呢? 看下面源码

    (篇幅考虑只取测试模型函数, 训练函数只是多了一个updates参数, 并且部分参数有改动):

     3     classifier = LogisticRegression(input=x, n_in=24 * 48, n_out=32)
    
     7     cost = classifier.negative_log_likelihood(y)
    
    11     test_model = theano.function(inputs=[index],
    12             outputs=classifier.errors(y),
    13             givens={
    14                 x: test_set_x[index * batch_size: (index + 1) * batch_size],
    15                 y: test_set_y[index * batch_size: (index + 1) * batch_size]})

    行3声明了一个对象classifer, 它的输入是符号x, 大小为24*48, 输出长度为32.

    行11定义了一个theano的函数对象, 接收的是下标index, 使用输入数据的第index*batch_size~第(index+1)*batch_size个数据作为函数的输入, 输出为误差.

    我们再来看看行12中的errors函数的定义:

        def errors(self, y):
            # check if y has same dimension of y_pred
            if y.ndim != self.y_pred.ndim:
                raise TypeError('y should have the same shape as self.y_pred',
                    ('y', target.type, 'y_pred', self.y_pred.type))
            # check if y is of the correct datatype
            if y.dtype.startswith('int'):
                # the T.neq operator returns a vector of 0s and 1s, where 1
                # represents a mistake in prediction
                return T.mean(T.neq(self.y_pred, y))
            else:
                raise NotImplementedError()

     self.y_pred 是一个大小为batch_size的向量, 每个元素代表batch_size中对应输入的网络判断结果, errors函数接受1个同等大小的期望输出y, 将两者进行比较求差后作均值返回, 这正是误差的定义.

    那么问题来了, 这个 self.y_pred 是如何计算的? 这里我们看LogisticRegression的构造函数:

     1     def __init__(self, input, n_in, n_out):
     2 
     3         # initialize with 0 the weights W as a matrix of shape (n_in, n_out)
     4         self.W = theano.shared(value=numpy.zeros((n_in, n_out),
     5                                                  dtype=theano.config.floatX),
     6                                 name='W', borrow=True)
     7         # initialize the baises b as a vector of n_out 0s
     8         self.b = theano.shared(value=numpy.zeros((n_out,),
     9                                                  dtype=theano.config.floatX),
    10                                name='b', borrow=True)
    11 
    12         # compute vector of class-membership probabilities in symbolic form
    13         self.p_y_given_x = T.nnet.softmax(T.dot(input, self.W) + self.b)
    14 
    15         # compute prediction as class whose probability is maximal in
    16         # symbolic form
    17         self.y_pred = T.argmax(self.p_y_given_x, axis=1)
    18 
    19         # parameters of the model
    20         self.params = [self.W, self.b]

     在行13可以看到, 使用input和self.W, self.b进行了一个softmax的映射. softmax本身是一个一一映射所以此处不再细说, 详情可以搜索引擎. 这里我们来说一说T.dot(input, self.W).

    这里的dot是theano的tensor变量的点乘操作, T.dot接受两个矩阵(向量)输入, 计算它们的点积并返回一个保存了点乘信息的节点对象, 使用返回的对象调用eval()方法即可获得实际数值结果, 如下:

    1 >>> a = numpy.asarray([1,2,3])
    2 >>> b = numpy.asarray([[3],[2],[1]])
    3 >>> T.dot(a,b).eval()
    4 array([10])

    上述代码是在ab大小匹配的情况, 即a的第2维等于b的第1维. 所以本例中正常情况(非SGD)下, input是1行1152列的, W是1152行32列的, b的长度为1行32列.

    这里的T.dot计算的结果是(input*W), 见如下代码:

    1 >>> a = numpy.ones((1, 1152))
    2 >>> W.shape
    3 (1152, 32)
    4 >>> dotaW = T.dot(a, W)
    5 >>> dotaW = dotaW.eval()
    1 >>> dotaW.shape
    2 (1, 32)

    注意, 如果颠倒了a和W的位置, 会报尺寸不匹配的错误.

    那么在SGD算法中, 行13代码中的input的大小实际上是batch_size行1152(24*48)列的, 所以我不禁疑惑, 如果a和b大小不匹配呢? 一个合理的推断就是, T.dot会自动截断input. 看如下代码:

    1 >>> a = numpy.ones((10, 1152))
    2 >>> dotaW = T.dot(a, W)
    3 >>> dotaW = dotaW.eval()
    4 >>> dotaW.shape
    5 (10, 32)

    果然, T.dot会自动截断input, 将其按照匹配W的尺寸(1行1152列)依次和W进行点乘后返回, 所以大小为(10, 32), 又偏置b的大小为(1, 32), 所以b会按列进行相加.


    解决了T.dot的问题, 一开篇的疑问就比较容易解答了, SGD基于T.dot的这种特性, 一次性输入batch_size行1152列样本, T.dot配合softmax生成batch_size行32列输出, 再基于 T.argmax(self.p_y_given_x, axis=1) , 计算每行(样本)的最大值作为期望输出y_pred(尺寸为batch_size行1列).

    本人预测, 卷积神经网络中的conv2d也是同样的机理, 对于一定数量的输入, 如20个48行24列大小的图像, 它会针对每一个输入样本产生对应的N张特征图->降采样->第二层卷积层->MLP, 到了MLP中, 配合上述的T.dot的特性, 就完成了SGD中的批训练的目的.

  • 相关阅读:
    LeetCode 275. H-Index II
    LeetCode 274. H-Index
    LeetCode Gray Code
    LeetCode 260. Single Number III
    LeetCode Word Pattern
    LeetCode Nim Game
    LeetCode 128. Longest Consecutive Sequence
    LeetCode 208. Implement Trie (Prefix Tree)
    LeetCode 130. Surrounded Regions
    LeetCode 200. Number of Islands
  • 原文地址:https://www.cnblogs.com/lancelod/p/4134276.html
Copyright © 2011-2022 走看看