una tipos redes practicos paso neuronales neuronal hacer fuente ejemplos como codigo c++ neural-network

c++ - tipos - redes neuronales python



Conseguir una red neuronal simple para trabajar desde cero en C++ (4)

He estado tratando de hacer funcionar una simple red neuronal doble XOR y estoy teniendo problemas para volver a propagar y entrenar una red neuronal de alimentación hacia adelante realmente simple.
He estado tratando principalmente de seguir this guía para obtener una red neuronal, pero en el mejor de los casos he creado programas que aprenden a una velocidad extremadamente lenta.

Como entiendo las redes neuronales:

  1. Los valores se calculan tomando el resultado de una función sigmoidea de la suma de todas las entradas a esa neurona. Luego se alimenta a la siguiente capa utilizando el peso para cada neurona.
  2. Al final de la ejecución, el error se calcula para las neuronas de salida, luego, al usar las ponderaciones, el error se vuelve a propagar simplemente multiplicando los valores y luego sumando cada neurona.
  3. Cuando se calculan todos los errores, los pesos se ajustan por el delta = peso de la conexión * derivado del sigmoide (el valor del peso de la neurona va a) * el valor de la neurona a la que la conexión es a * error de la neurona * cantidad de error de salida de La neurona va a * beta (algunas constantes para tasa de aprendizaje)

This es mi código de código actual con el que estoy tratando de trabajar. Tengo muchos otros intentos un tanto mezclados, pero la función principal de propagación hacia atrás que estoy tratando de hacer funcionar está en la línea 293 en Net.cpp


¿Qué tal este código de código abierto? Define una red de 1 capa oculta simple (2 entradas, 2 ocultas, 1 salida) y resuelve el problema de XOR:

http://www.sylbarth.com/mlp.php



Escribí un sencillo "Tutorial" que puedes consultar a continuación.

Es una implementación simple del modelo perceptron. Puedes imaginar un perceptrón como una red neuronal con una sola neurona. Hay un código de maldición que puedes probar que escribí en C ++. Repaso el código paso a paso para que no tengas ningún problema.

Aunque el perceptrón no es realmente una "red neuronal", es realmente útil si desea comenzar y podría ayudarlo a comprender mejor cómo funciona una red neuronal completa.

¡Espero que ayude! ¡Aclamaciones! ^ _ ^

En este ejemplo, pasaré por la implementación del modelo perceptron en C ++ para que pueda tener una mejor idea de cómo funciona.

Primero lo primero es una buena práctica escribir un algoritmo simple de lo que queremos hacer.

Algoritmo:

  1. Haga un vector para los pesos e inicialícelo a 0 (No olvide agregar el término de sesgo)
  2. Siga ajustando los pesos hasta que obtengamos 0 errores o un recuento bajo de errores.
  3. Hacer predicciones sobre datos invisibles.

Habiendo escrito un algoritmo súper simple, ahora escribamos algunas de las funciones que necesitaremos.

  • Necesitaremos una función para calcular la entrada de la red (ei * x * wT * multiplicando las entradas por el tiempo de los pesos)
  • Una función escalonada para que podamos obtener una predicción de 1 o -1
  • Y una función que encuentra los valores ideales para los pesos.

Así que sin más preámbulos, entremos en esto.

Comencemos simple creando una clase de perceptron:

class perceptron { public: private: };

Ahora agreguemos las funciones que necesitaremos.

class perceptron { public: perceptron(float eta,int epochs); float netInput(vector<float> X); int predict(vector<float> X); void fit(vector< vector<float> > X, vector<float> y); private: };

Observe cómo el ajuste de la función toma como argumento un vector del vector <float>. Esto se debe a que nuestro conjunto de datos de capacitación es una matriz de entradas. Esencialmente, podemos imaginar que la matriz como un par de vectores x apiladas una encima de otra y cada columna de esa Matriz es una característica.

Finalmente, agreguemos los valores que nuestra clase necesita tener. Como el vector w para mantener los pesos, el número de épocas que indica el número de pases que realizaremos sobre el conjunto de datos de entrenamiento. Y la constante eta, cuya velocidad de aprendizaje multiplicaremos cada actualización de peso para acelerar el procedimiento de entrenamiento al aumentar este valor o si eta es demasiado alto, podemos marcarlo para obtener el resultado ideal (para la mayoría de las aplicaciones del perceptrón sugeriría un valor eta de 0.1).

class perceptron { public: perceptron(float eta,int epochs); float netInput(vector<float> X); int predict(vector<float> X); void fit(vector< vector<float> > X, vector<float> y); private: float m_eta; int m_epochs; vector < float > m_w; };

Ahora con nuestro conjunto de clases. Es hora de escribir cada una de las funciones.

Comenzaremos desde el constructor ( perceptron (float eta, int epochs); )

perceptron::perceptron(float eta, int epochs) { m_epochs = epochs; // We set the private variable m_epochs to the user selected value m_eta = eta; // We do the same thing for eta }

Como puedes ver, lo que haremos es algo muy simple. Así que vamos a pasar a otra función simple. La función de predicción ( int predecir (vector X); ). Recuerde que lo que hace la función de predicción total es tomar la entrada de la red y devolver un valor de 1 si la entrada de red es mayor que 0 y -1 de otro modo.

int perceptron::predict(vector<float> X) { return netInput(X) > 0 ? 1 : -1; //Step Function }

Tenga en cuenta que utilizamos una declaración en línea si para hacer nuestras vidas más fáciles. Así es como funciona la instrucción inline if:

condición? if_true: else

Hasta ahora tan bueno. Continuemos con la implementación de la función netInput ( float netInput (vector X); )

El netInput hace lo siguiente; multiplica el vector de entrada por la transposición del vector de pesos

* x * wT *

En otras palabras, multiplica cada elemento del vector de entrada x por el elemento correspondiente del vector de ponderaciones w y luego toma su suma y agrega el sesgo.

* (x1 * w1 + x2 * w2 + ... + xn * wn) + sesgo *

* sesgo = 1 * w0 *

float perceptron::netInput(vector<float> X) { // Sum(Vector of weights * Input vector) + bias float probabilities = m_w[0]; // In this example I am adding the perceptron first for (int i = 0; i < X.size(); i++) { probabilities += X[i] * m_w[i + 1]; // Notice that for the weights I am counting // from the 2nd element since w0 is the bias and I already added it first. } return probabilities; }

Bien, ahora ya casi hemos terminado. Lo último que tenemos que hacer es escribir la función de ajuste que modifica los pesos.

void perceptron::fit(vector< vector<float> > X, vector<float> y) { for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term { m_w.push_back(0); // Setting each weight to 0 and making the size of the vector // The same as the number of features (X[0].size()) + 1 for the bias term } for (int i = 0; i < m_epochs; i++) // Iterating through each epoch { for (int j = 0; j < X.size(); j++) // Iterating though each vector in our training Matrix { float update = m_eta * (y[j] - predict(X[j])); //we calculate the change for the weights for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; } // we update each weight by the update * the training sample m_w[0] = update; // We update the Bias term and setting it equal to the update } } }

Así que eso era esencialmente eso. ¡Con solo 3 funciones ahora tenemos una clase de percepción de trabajo que podemos usar para hacer predicciones!

En caso de que quiera copiar y pegar el código y probarlo. Aquí está la clase completa (agregué algunas funciones adicionales, como la impresión del vector de pesos y los errores en cada época, así como la opción de importar pesos de exportación).

Aquí está el código:

El encabezado de la clase:

class perceptron { public: perceptron(float eta,int epochs); float netInput(vector<float> X); int predict(vector<float> X); void fit(vector< vector<float> > X, vector<float> y); void printErrors(); void exportWeights(string filename); void importWeights(string filename); void printWeights(); private: float m_eta; int m_epochs; vector < float > m_w; vector < float > m_errors; };

El archivo de clase .cpp con las funciones:

perceptron::perceptron(float eta, int epochs) { m_epochs = epochs; m_eta = eta; } void perceptron::fit(vector< vector<float> > X, vector<float> y) { for (int i = 0; i < X[0].size() + 1; i++) // X[0].size() + 1 -> I am using +1 to add the bias term { m_w.push_back(0); } for (int i = 0; i < m_epochs; i++) { int errors = 0; for (int j = 0; j < X.size(); j++) { float update = m_eta * (y[j] - predict(X[j])); for (int w = 1; w < m_w.size(); w++){ m_w[w] += update * X[j][w - 1]; } m_w[0] = update; errors += update != 0 ? 1 : 0; } m_errors.push_back(errors); } } float perceptron::netInput(vector<float> X) { // Sum(Vector of weights * Input vector) + bias float probabilities = m_w[0]; for (int i = 0; i < X.size(); i++) { probabilities += X[i] * m_w[i + 1]; } return probabilities; } int perceptron::predict(vector<float> X) { return netInput(X) > 0 ? 1 : -1; //Step Function } void perceptron::printErrors() { printVector(m_errors); } void perceptron::exportWeights(string filename) { ofstream outFile; outFile.open(filename); for (int i = 0; i < m_w.size(); i++) { outFile << m_w[i] << endl; } outFile.close(); } void perceptron::importWeights(string filename) { ifstream inFile; inFile.open(filename); for (int i = 0; i < m_w.size(); i++) { inFile >> m_w[i]; } } void perceptron::printWeights() { cout << "weights: "; for (int i = 0; i < m_w.size(); i++) { cout << m_w[i] << " "; } cout << endl; }

Además, si quieres probar un ejemplo, aquí hay un ejemplo que hice:

main.cpp:

#include <iostream> #include <vector> #include <algorithm> #include <fstream> #include <string> #include <math.h> #include "MachineLearning.h" using namespace std; using namespace MachineLearning; vector< vector<float> > getIrisX(); vector<float> getIrisy(); int main() { vector< vector<float> > X = getIrisX(); vector<float> y = getIrisy(); vector<float> test1; test1.push_back(5.0); test1.push_back(3.3); test1.push_back(1.4); test1.push_back(0.2); vector<float> test2; test2.push_back(6.0); test2.push_back(2.2); test2.push_back(5.0); test2.push_back(1.5); //printVector(X); //for (int i = 0; i < y.size(); i++){ cout << y[i] << " "; }cout << endl; perceptron clf(0.1, 14); clf.fit(X, y); clf.printErrors(); cout << "Now Predicting: 5.0,3.3,1.4,0.2(CorrectClass=-1,Iris-setosa) -> " << clf.predict(test1) << endl; cout << "Now Predicting: 6.0,2.2,5.0,1.5(CorrectClass=1,Iris-virginica) -> " << clf.predict(test2) << endl; system("PAUSE"); return 0; } vector<float> getIrisy() { vector<float> y; ifstream inFile; inFile.open("y.data"); string sampleClass; for (int i = 0; i < 100; i++) { inFile >> sampleClass; if (sampleClass == "Iris-setosa") { y.push_back(-1); } else { y.push_back(1); } } return y; } vector< vector<float> > getIrisX() { ifstream af; ifstream bf; ifstream cf; ifstream df; af.open("a.data"); bf.open("b.data"); cf.open("c.data"); df.open("d.data"); vector< vector<float> > X; for (int i = 0; i < 100; i++) { char scrap; int scrapN; af >> scrapN; bf >> scrapN; cf >> scrapN; df >> scrapN; af >> scrap; bf >> scrap; cf >> scrap; df >> scrap; float a, b, c, d; af >> a; bf >> b; cf >> c; df >> d; X.push_back(vector < float > {a, b, c, d}); } af.close(); bf.close(); cf.close(); df.close(); return X; }

La forma en que importé el conjunto de datos del iris no es realmente ideal, pero solo quería algo que funcionara.

Los archivos de datos se pueden encontrar here.

Espero que hayas encontrado esto útil!

Nota: El código de arriba está solo como un ejemplo. Como lo señala juzzlin, es importante que use const vector<float> &X y, en general, pase los objetos vector / vector<vector> por referencia, ya que los datos pueden ser muy grandes y al pasarlos por valor se realizará una copia de los mismos. es ineficiente).


Me parece que estás luchando con backprop y lo que describiste anteriormente no coincide con cómo lo entiendo para que funcione, y tu descripción es un poco ambigua.

Calcula el término de error de salida para propagar hacia atrás como la diferencia entre la predicción y el valor real multiplicado por la derivada de la función de transferencia. Es ese valor de error el que luego propaga hacia atrás. La derivada de un sigmoide se calcula simplemente como y (1-y) donde y es su valor de salida. Hay muchas pruebas de eso disponibles en la web.

Para un nodo en la capa interna, multiplique ese error de salida por el peso entre los dos nodos y sume todos esos productos como el error total de la capa externa que se propaga al nodo en la capa interna. El error asociado con el nodo interno se multiplica luego por la derivada de la función de transferencia aplicada al valor de salida original. Aquí hay algunos pseudocódigo:

total_error = sum(output_errors * weights) node_error = sigmoid_derivative(node_output) * total_error

Este error luego se propaga hacia atrás de la misma manera y regresa a través de los pesos de la capa de entrada.

Los pesos se ajustan utilizando estos términos de error y los valores de salida de los nodos

weight_change = outer_error * inner_output_value

la velocidad de aprendizaje es importante porque el cambio de peso se calcula para cada patrón / fila / observación en los datos de entrada. Desea moderar el cambio de peso para cada fila para que las ponderaciones no se modifiquen indebidamente en una sola fila y para que todas las filas tengan un efecto en los pesos. La tasa de aprendizaje le da eso y usted ajusta el cambio de peso al multiplicarlo.

weight_change = outer_error * inner_output_value * learning_rate

También es normal recordar estos cambios entre las épocas (iteraciones) y agregar una fracción al cambio. La fracción agregada se denomina impulso y se supone que lo acelera a través de las regiones de la superficie de error donde no hay mucho cambio y lo ralentiza donde hay detalles.

weight_change = (outer_error*inner_output_value*learning_rate) + (last_change*momentum)

Hay algoritmos para ajustar la velocidad de aprendizaje y el impulso a medida que avanza la capacitación.

Luego se actualiza el peso agregando el cambio.

new_weight = old_weight + weight_change

Eché un vistazo a su código, pero en lugar de corregirlo y publicarlo, pensé que era mejor describirle la proposición de respaldo para que pueda codificarlo usted mismo. Si lo comprendes, también podrás sintonizarlo según tus circunstancias.

HTH y buena suerte.