2016-02-17 35 views
5

我仍在努力在我的连体神经网络上实现小批量梯度更新。以前我有一个执行问题,那就是correctly solved here火炬/ Lua,小批量训练的神经网络结构?

现在我意识到我的神经网络架构中也存在一个错误,这与我对正确实现的不完全理解有关。

到目前为止,我一直使用非小批次梯度下降方法,其中我将训练元素逐个传递给梯度更新。现在,我想通过小批量实现梯度更新,比如用N = 2个元素构成的小型贴片开始。

我的问题是:我应该如何改变我的连体神经网络的架构,使其能够处理N = 2个元素的小批量而不是单个元素?

这是我的连体神经网络的(简化的)体系结构:

nn.Sequential { 
    [input -> (1) -> (2) -> output] 
    (1): nn.ParallelTable { 
    input 
     |`-> (1): nn.Sequential { 
     |  [input -> (1) -> (2) -> output] 
     |  (1): nn.Linear(6 -> 3) 
     |  (2): nn.Linear(3 -> 2) 
     | } 
     |`-> (2): nn.Sequential { 
     |  [input -> (1) -> (2) -> output] 
     |  (1): nn.Linear(6 -> 3) 
     |  (2): nn.Linear(3 -> 2) 
     | } 
     ... -> output 
    } 
    (2): nn.CosineDistance 
} 

我有:

  • 2相同连体神经网络(上部和下部)
  • 6输入单元
  • 3个隐藏单位
  • 2个输出单位
  • 两个平行神经网络

这里的输出与

  • 余弦距离函数是我的代码:

    perceptronUpper= nn.Sequential() 
    perceptronUpper:add(nn.Linear(input_number, hiddenUnits)) 
    perceptronUpper:add(nn.Linear(hiddenUnits,output_number)) 
    perceptronLower= perceptronUpper:clone('weight', 'gradWeights', 'gradBias', 
    'bias') 
    
    parallel_table = nn.ParallelTable() 
    parallel_table:add(perceptronUpper) 
    parallel_table:add(perceptronLower) 
    
    perceptron = nn.Sequential() 
    perceptron:add(parallel_table) 
    perceptron:add(nn.CosineDistance()) 
    

    这种架构工作得非常好,如果我有一个梯度更新函数,采用1个元素;如何修改它以让它管理一个小批次

    编辑:

    perceptron:add(nn.Sequencer(parallel_table)) 
    perceptron:add(nn.Sequencer(nn.CosineDistance())). 
    

    你们有什么想:我也许应该通过修改我的代码的最后两行使用nn.Sequencer() class,?

  • 回答

    2

    每个nn模块都可以使用minibatches工作。一些仅与小型配件一起工作,例如(Spatial)BatchNormalization。一个模块知道它的输入必须包含多少维数(比如说D),如果模块接收到D + 1维张量,则它假定第一维是批量维。例如,看看nn.Linear module documentation

    在正向(输入)中给出的输入张量必须是一个矢量(1D 张量)或矩阵(2D张量)。如果输入是矩阵,则假定每行 都是给定批次的输入样本。

    function table_of_tensors_to_batch(tbl) 
        local batch = torch.Tensor(#tbl, unpack(tbl[1]:size():totable())) 
        for i = 1, #tbl do 
         batch[i] = tbl[i] 
        end 
        return batch 
    end 
    
    inputs = { 
        torch.Tensor(5):fill(1), 
        torch.Tensor(5):fill(2), 
        torch.Tensor(5):fill(3), 
    } 
    input_batch = table_of_tensors_to_batch(inputs) 
    linear = nn.Linear(5, 2) 
    output_batch = linear:forward(input_batch) 
    
    print(input_batch) 
    1 1 1 1 1 
    2 2 2 2 2 
    3 3 3 3 3 
    [torch.DoubleTensor of size 3x5] 
    
    print(output_batch) 
    0,3128 -1,1384 
    0,7382 -2,1815 
    1,1637 -3,2247 
    [torch.DoubleTensor of size 3x2] 
    

    好了,但怎么样容器(nn.Sequentialnn.Paralelnn.ParallelTable等)?容器本身不处理输入,只是将输入(或其相应的部分)发送到它所包含的相应模块。例如,ParallelTable只是将第i个成员模块应用于第i个输入表格元素。因此,如果您希望它处理一个批次,则每个输入[i](输入是一个表格)必须是具有上述批量维度的张量。

    input_number = 5 
    output_number = 2 
    
    inputs1 = { 
        torch.Tensor(5):fill(1), 
        torch.Tensor(5):fill(2), 
        torch.Tensor(5):fill(3), 
    } 
    inputs2 = { 
        torch.Tensor(5):fill(4), 
        torch.Tensor(5):fill(5), 
        torch.Tensor(5):fill(6), 
    } 
    input1_batch = table_of_tensors_to_batch(inputs1) 
    input2_batch = table_of_tensors_to_batch(inputs2) 
    
    input_batch = {input1_batch, input2_batch} 
    output_batch = perceptron:forward(input_batch) 
    
    print(input_batch) 
    { 
        1 : DoubleTensor - size: 3x5 
        2 : DoubleTensor - size: 3x5 
    } 
    print(output_batch) 
    0,6490 
    0,9757 
    0,9947 
    [torch.DoubleTensor of size 3] 
    
    
    target_batch = torch.Tensor({1, 0, 1}) 
    criterion = nn.MSECriterion() 
    err = criterion:forward(output_batch, target_batch) 
    gradCriterion = criterion:backward(output_batch, target_batch) 
    perceptron:zeroGradParameters() 
    perceptron:backward(input_batch, gradCriterion) 
    

    为什么nn.Sequencer呢?有人可以使用它吗?是的,但它是非常不推荐。 Sequencer获取一个序列表并将该模块独立应用于表中的每个元素,而不会加速。此外,它必须复制该模块,因此这种“批处理模式”比在线(非批处理)培训的效率低得多。 Sequencer被设计成是经常性网络的一部分,在你的情况下没有意义。

    +0

    嗨@Alexander,谢谢你的回复。我试图实现你的解决方案,但我陷入了梯度更新'perceptron:backward(input_batch,targets)'指令。 '目标'应该包含我训练的目标,例如'0,1'。如果'input_batch'是大小为3x5的2个DoubleTensors列表,那么'target'的正确尺寸应该是多少?谢谢 –

    +0

    @ DavideChicco.it,目标是最小化输入对之间的距离,对吗?那么你的目标是什么?我会认为它是零。 '0,1'从哪里来? –

    +0

    我正在比较向量对。每个矢量由6个实数值组成。每对可以是true(target = 1)或false(target = 0)。在训练过程中,我称之为'感知器:前向(input_batch)',然后'感知器:zeroGradParameters()'和'感知器:反向(input_batch,目标)'。我在“目标”的尺寸方面遇到麻烦,我不得不适应新的设置。大小为1的#input_batch DoubleTensors矢量不起作用,应该使用什么?谢谢 –