c++ - Neural Network not learning-Datos de MNIST-Reconocimiento de escritura a mano
neural network c++ (1)
Esta respuesta se copia del comentario de OP sobre la pregunta.
Resolví el acertijo. Había cometido el peor error posible. Estaba dando una entrada equivocada. He usado opencv para escanear las imágenes, en lugar de usar reshape
, estaba usando el resize
y la entrada fue de interpolación lineal de imágenes. Entonces mi entrada fue incorrecta. No había nada de malo con el código. Mi red es 784 - 65 - 10
con un 96.43% de precisión.
He escrito un programa de red neuronal. Funciona para Logic Gates, pero cuando intento usarlo para reconocer dígitos escritos a mano, simplemente no aprende.
Por favor encuentre el código a continuación:
// Esta es una sola neurona; esto podría ser necesario para entender el código restante
typedef struct SingleNeuron
{
double outputValue;
std::vector<double> weight;
std::vector<double> deltaWeight;
double gradient;
double sum;
}SingleNeuron;
Entonces inicializo la red. Establecí los pesos para que sean valores aleatorios entre -0.5 a +0.5, suma a 0, deltaWeight a 0
Luego viene FeedForward:
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;
}
Mi función de transferencia y su derivada se menciona al final.
Después de esto, intento retroceder usando:
// calculate output layer gradients
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;
// calculate hidden layer gradients
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;
// from output to 1st hidden layer, update all weights
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;
}
}
}
Estos son TransferFuntion y su derivado;
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;
}
Una cosa que observé Si uso la función sigmoidea estándar para ser mi función de transferencia Y si paso la salida de la neurona a la función de transferencia - El resultado es INFINITO. Pero tanh (x) funciona bien con este valor
Entonces, si estoy usando 1/1 + e ^ (- x) como función de transferencia, tengo que pasar la Sum of Net Inputs
y siendo tanh
mi función de transferencia, tengo que pasar la output
de la neurona actual.
No entiendo completamente por qué es así, puede ser que esto requiera una pregunta diferente.
Pero esta pregunta es realmente sobre otra cosa: LA RED ESTÁ TRABAJANDO PARA LAS PUERTAS LÓGICAS PERO NO PARA EL RECONOCIMIENTO DEL CARÁCTER
He intentado muchas variaciones / combinaciones de Learning Rate
de Learning Rate
y Acceleration
y # hidden layers
y their sizes
. Encuentre los resultados a continuación:
AvgErr: 0.299399 #Pass799
AvgErr : 0.305071 #Pass809
AvgErr : 0.303046 #Pass819
AvgErr : 0.299569 #Pass829
AvgErr : 0.30413 #Pass839
AvgErr : 0.304165 #Pass849
AvgErr : 0.300529 #Pass859
AvgErr : 0.302973 #Pass869
AvgErr : 0.299238 #Pass879
AvgErr : 0.304708 #Pass889
AvgErr : 0.30068 #Pass899
AvgErr : 0.302582 #Pass909
AvgErr : 0.301767 #Pass919
AvgErr : 0.303167 #Pass929
AvgErr : 0.299551 #Pass939
AvgErr : 0.301295 #Pass949
AvgErr : 0.300651 #Pass959
AvgErr : 0.297867 #Pass969
AvgErr : 0.304221 #Pass979
AvgErr : 0.303702 #Pass989
Después de ver los resultados, es posible que sienta que este tipo simplemente está atrapado en los mínimos locales, pero espere y lea lo siguiente:
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.0666924
Input = [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.0675822
Input = [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.0675156
Input = [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
Arriba está la salida de la época # 996, # 997, # 998 y # 999
Entonces, simplemente, la red no está aprendiendo. Para esto, por ejemplo, he usado ALPHA = 0.4, ETA = 0.7, 10 capas ocultas, cada una de 100 neuronas y el promedio es de más de 10 épocas. Si le preocupa que Learning Rate sea de 0,4 o más capas ocultas, ya he probado sus variaciones. Por ejemplo, para una tasa de aprendizaje de 0,1 y 4 capas ocultas, cada una de 16
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = 0.0883238, 0.0983253, 0.0613749, 0.0809751, 0.124972, 0.0897194, 0.0911235, 0.179984, 0.0681346, 0.0660039
Input = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Output = 0.0868767, 0.0966924, 0.0612488, 0.0798343, 0.120353, 0.0882381, 0.111925, 0.169309, 0.0676711, 0.0656819
Input = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
Output = 0.105252, 0.0943837, 0.0604416, 0.0781779, 0.116231, 0.0858496, 0.108437, 0.1588, 0.0663156, 0.0645477
Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Output = 0.102023, 0.0914957, 0.059178, 0.09339, 0.111851, 0.0842454, 0.104834, 0.149892, 0.0651799, 0.063558
Estoy tan seguro de que me he perdido algo. No soy capaz de resolverlo. He leído el algoritmo de Tom Mitchel muchas veces, pero no sé lo que está mal. Cualquiera que sea el ejemplo que resuelvo a mano, ¡funciona! (Por favor, no me pidas que resuelva imágenes de datos MNIST a mano;)) No sé dónde cambiar el código, qué hacer ... por favor ayuda ...
EDITAR - Carga de más datos según sugerencias en comentarios
1 capa oculta de 32 - todavía no hay aprendizaje.
Salida esperada - La entrada es imágenes entre 0-9, entonces un vector simple que describe cuál es la imagen actual, ese bit es 1 todos los demás son 0. Entonces quisiera que la salida sea tan cercana a 1 para ese bit en particular y que otros estén cerca a 0 Por ejemplo, si la entrada es Input = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
Me gustaría que la salida fuera algo así como Output = 0.002023, 0.0914957, 0.059178, 0.09339, 0.011851, 0.0842454, 0.924834, 0.049892, 0.0651799, 0.063558
(Esto es vago, generado a mano)
Aquí están los enlaces del trabajo de otros investigadores.
SourceForge - Esto es más bien una biblioteca
No solo estos 2, hay tantos sitios que muestran las demostraciones.
Las cosas están funcionando bastante bien para ellos. Si configuro mis parámetros de red (Alpha, ETA) como ellos, no obtengo resultados como estos, así que esto es una garantía de que algo anda mal con mi código.
EDIT 2
Agregar más casos de falla
Accelaration - 0.7, Tasa de aprendizaje 0.1
Accelaration - 0.7, Tasa de aprendizaje 0.6
En los dos casos anteriores, las capas ocultas fueron 3, cada una de 32 neuronas.