神经网络无法学习 – MNIST数据 – 手写识别

我编写了一个神经网络程序。它适用于逻辑门,但当我尝试用它来识别手写数字时,它根本无法学习。

请查看下面的代码:

// 这是一个单神经元;理解剩余代码可能需要这个

typedef struct SingleNeuron{    double                  outputValue;    std::vector<double>     weight;    std::vector<double>     deltaWeight;    double                  gradient;    double                  sum;}SingleNeuron;

然后我初始化网络。我将权重设置为-0.5到+0.5之间的随机值,将sum设置为0,deltaWeight设置为0

接下来是前馈过程:

for (unsigned i = 0; i < inputValues.size(); ++i){    neuralNet[0][i].outputValue = inputValues[i];    neuralNet[0][i].sum = 0.0;    //  std::cout << "o/p Val = " << neuralNet[0][i].outputValue << std::endl;}for (unsigned i = 1; i < neuralNet.size(); ++i){    std::vector<SingleNeuron> prevLayerNeurons = neuralNet[i - 1];    unsigned j = 0;    double thisNeuronOPVal = 0;    //  std::cout << std::endl;    for (j = 0; j < neuralNet[i].size() - 1; ++j)    {        double sum = 0;        for (unsigned k = 0; k < prevLayerNeurons.size(); ++k)        {            sum += prevLayerNeurons[k].outputValue * prevLayerNeurons[k].weight[j];        }        neuralNet[i][j].sum = sum;        neuralNet[i][j].outputValue = TransferFunction(sum);        //      std::cout << neuralNet[i][j].outputValue << "\t";    }    //      std::cout << std::endl;}

我的传递函数及其导数在最后提到。

之后我尝试使用以下方法进行反向传播:

// 计算输出层的梯度for (unsigned i = 0; i < outputLayer.size() - 1; ++i){    double delta = actualOutput[i] - outputLayer[i].outputValue;    outputLayer[i].gradient = delta * TransferFunctionDerivative(outputLayer[i].sum);}//  std::cout << "Found Output gradients "<< std::endl;// 计算隐藏层的梯度for (unsigned i = neuralNet.size() - 2; i > 0; --i){    std::vector<SingleNeuron>& hiddenLayer = neuralNet[i];    std::vector<SingleNeuron>& nextLayer = neuralNet[i + 1];    for (unsigned j = 0; j < hiddenLayer.size(); ++j)    {        double dow = 0.0;        for (unsigned k = 0; k < nextLayer.size() - 1; ++k)        {            dow += nextLayer[k].gradient * hiddenLayer[j].weight[k];        }        hiddenLayer[j].gradient = dow * TransferFunctionDerivative(hiddenLayer[j].sum);    }}//  std::cout << "Found hidden layer gradients "<< std::endl;// 从输出层到第一隐藏层,更新所有权重for (unsigned i = neuralNet.size() - 1; i > 0; --i){    std::vector <SingleNeuron>& currentLayer = neuralNet[i];    std::vector <SingleNeuron>& prevLayer = neuralNet[i - 1];    for (unsigned j = 0; j < currentLayer.size() - 1; ++j)    {        for (unsigned k = 0; k < prevLayer.size(); ++k)        {            SingleNeuron& thisNeueon = prevLayer[k];            double oldDeltaWeight = thisNeueon.deltaWeight[j];            double newDeltaWeight = ETA * thisNeueon.outputValue * currentLayer[j].gradient + (ALPHA * oldDeltaWeight);            thisNeueon.deltaWeight[j] = newDeltaWeight;            thisNeueon.weight[j] += newDeltaWeight;        }    }}

这些是传递函数及其导数:

double TransferFunction(double x){    double val;    //val = tanh(x);    val = 1 / (1 + exp(x * -1));    return val;}double TransferFunctionDerivative(double x){    //return 1 - x * x;    double val = exp(x * -1) / pow((exp(x * -1) + 1), 2);    return val;}

我观察到一件事情,如果我使用标准的Sigmoid函数作为我的传递函数,并且将神经元的输出传递给传递函数,结果是无穷大。但是tanh(x)在这个值上工作得很好

所以如果我使用1/1+e^(-x)作为传递函数,我必须传递网络输入的总和,而如果tanh是我的传递函数,我必须传递当前神经元的输出

我不完全理解为什么会这样,这可能需要一个不同的问题来回答。

但这个问题实际上是关于其他事情的:网络对逻辑门有效,但对字符识别无效

我已经尝试了许多学习率加速度以及隐藏层数它们的尺寸的组合变化。请查看下面的结果:

AvgErr: 0.299399          #Pass799AvgErr : 0.305071         #Pass809AvgErr : 0.303046         #Pass819AvgErr : 0.299569         #Pass829AvgErr : 0.30413          #Pass839AvgErr : 0.304165         #Pass849AvgErr : 0.300529         #Pass859AvgErr : 0.302973         #Pass869AvgErr : 0.299238         #Pass879AvgErr : 0.304708         #Pass889AvgErr : 0.30068          #Pass899AvgErr : 0.302582         #Pass909AvgErr : 0.301767         #Pass919AvgErr : 0.303167         #Pass929AvgErr : 0.299551         #Pass939AvgErr : 0.301295         #Pass949AvgErr : 0.300651         #Pass959AvgErr : 0.297867         #Pass969AvgErr : 0.304221         #Pass979AvgErr : 0.303702         #Pass989

看了这些结果后,您可能会觉得这个家伙只是陷入了局部最小值,但请稍等并继续阅读:

Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]          Output = 0.0910903, 0.105674, 0.064575, 0.0864824, 0.128682, 0.0878434, 0.0946296, 0.154405, 0.0678767, 0.0666924Input = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]Output = 0.0916106, 0.105958, 0.0655508, 0.086579, 0.126461, 0.0884082, 0.110953, 0.163343, 0.0689315, 0.0675822Input = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]          Output = 0.105344, 0.105021, 0.0659517, 0.0858077, 0.123104, 0.0884107, 0.116917, 0.161911, 0.0693426, 0.0675156Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]          Output = 0.107113, 0.101838, 0.0641632, 0.0967766, 0.117149, 0.085271, 0.11469, 0.153649, 0.0672772, 0.0652416

以上是第996、997、998和999次迭代的输出

所以网络根本没有学习。对于这个例子,我使用了ALPHA = 0.4,ETA = 0.7,10个隐藏层,每层100个神经元,平均值为10个迭代。如果您担心学习率为0.4或如此多的隐藏层,我已经尝试了它们的不同组合。例如,学习率为0.1和4个隐藏层,每层16个神经元


回答:

这个回答是从问题发布者的评论中复制过来的。

我解开了谜团。我犯了最糟糕的错误。我给出了错误的输入。我使用opencv扫描图像,而不是使用reshape,我使用了resize,所以输入是图像的线性插值。因此,我的输入是错误的。代码没有任何问题。我的网络是784 - 65 - 10,准确率为96.43%。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注