使用小批量时如何更新重量?

时间:2019-01-23 17:25:01

标签: c neural-network backpropagation mini-batch

我正在尝试对我的神经网络实施小批量训练,而不是“在线”随机更新每个训练样本的权重的方法。

我用C开发了一个新手神经网络,通过它我可以调整每层神经元的数量,激活函数等。这是为了帮助我理解神经网络。我已经在mnist数据集上训练了网络,但是花了大约200个纪元才能使训练集上的错误率降低20%,这对我来说是非常糟糕的。我目前正在使用体面的在线随机梯度训练网络。我想尝试的是使用迷你批处理。我理解这样的概念:在传播错误之前,我必须累积每个训练样本的错误并取平均值。当我想计算必须对权重进行的更改时,就会出现我的问题。为了更好地解释这一点,请考虑一个非常简单的感知器模型。一输入,一隐藏层一输出。要计算我需要对输入和隐藏单位之间的权重进行的更改,我将使用以下公式:

∂C/∂w1=∂C/∂O*∂O/∂h*∂h/∂w1

如果执行偏导数,则会得到:

∂C/∂w1=(输出预期答案)(w2)(输入)

现在,此公式表明您需要将反向传播误差乘以输入。对于在线随机训练,这很有意义,因为每个体重更新使用1个输入。对于小批量训练,您使用了许多输入,因此误差乘以哪个输入? 希望您能在此方面为我提供帮助。

void propogateBack(void){


    //calculate 6C/6G
    for (count=0;count<network.outputs;count++){
            network.g_error[count] = derive_cost((training.answer[training_current])-(network.g[count]));
    }



    //calculate 6G/6O
    for (count=0;count<network.outputs;count++){
        network.o_error[count] = derive_activation(network.g[count])*(network.g_error[count]);
    }


    //calculate 6O/6S3
    for (count=0;count<network.h3_neurons;count++){
        network.s3_error[count] = 0;
        for (count2=0;count2<network.outputs;count2++){
            network.s3_error[count] += (network.w4[count2][count])*(network.o_error[count2]);
        }
    }


    //calculate 6S3/6H3
    for (count=0;count<network.h3_neurons;count++){
        network.h3_error[count] = (derive_activation(network.s3[count]))*(network.s3_error[count]);
    }


    //calculate 6H3/6S2
    network.s2_error[count] = = 0;
    for (count=0;count<network.h2_neurons;count++){
        for (count2=0;count2<network.h3_neurons;count2++){ 
            network.s2_error[count] = += (network.w3[count2][count])*(network.h3_error[count2]);
        }
    }



    //calculate 6S2/6H2
    for (count=0;count<network.h2_neurons;count++){
        network.h2_error[count] = (derive_activation(network.s2[count]))*(network.s2_error[count]);
    }


    //calculate 6H2/6S1
    network.s1_error[count] = 0;
    for (count=0;count<network.h1_neurons;count++){
        for (count2=0;count2<network.h2_neurons;count2++){
            buffer += (network.w2[count2][count])*network.h2_error[count2];
        }
    }


    //calculate 6S1/6H1
    for (count=0;count<network.h1_neurons;count++){
        network.h1_error[count] = (derive_activation(network.s1[count]))*(network.s1_error[count]);

    }


}





void updateWeights(void){


    //////////////////w1
    for(count=0;count<network.h1_neurons;count++){
        for(count2=0;count2<network.inputs;count2++){
            network.w1[count][count2] -= learning_rate*(network.h1_error[count]*network.input[count2]);
        }

    }





    //////////////////w2
    for(count=0;count<network.h2_neurons;count++){
        for(count2=0;count2<network.h1_neurons;count2++){
            network.w2[count][count2] -= learning_rate*(network.h2_error[count]*network.s1[count2]);
        }

    }



    //////////////////w3
    for(count=0;count<network.h3_neurons;count++){
        for(count2=0;count2<network.h2_neurons;count2++){
            network.w3[count][count2] -= learning_rate*(network.h3_error[count]*network.s2[count2]);
        }

    }


    //////////////////w4
    for(count=0;count<network.outputs;count++){
        for(count2=0;count2<network.h3_neurons;count2++){
            network.w4[count][count2] -= learning_rate*(network.o_error[count]*network.s3[count2]);
        }

    }
}

我随附的代码是我进行在线随机更新的方式。如您在updateWeights()函数中所见,权重更新基于输入值(取决于输入的样本)和隐藏单位值(也取决于输入的输入样本值)。所以,当我传播的是最小批量平均梯度时,我将如何更新权重?我要使用哪些输入值?

1 个答案:

答案 0 :(得分:1)

好,所以我知道了。当使用小批量时,您不应该在网络的输出端累积误差并求平均值。像往常一样传播每个训练示例错误,除了不累积权重而是累积对每个权重所做的更改,而不是像往常那样传播。当您遍历小批量时,可以平均累积量并相应地更改权重。

我给人的印象是,使用小型批处理时,您无需遍历小型批处理就可以向后传播任何错误。我错了,您仍然需要这样做,唯一的区别是,只有当您遍历最小批次大小时才更新重量。