me escribió un simple un "Tutorial" que se puede comprobar 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 problemas.
Aunque el perceptrón no es realmente una "red neuronal", es realmente útil si desea comenzar y puede ayudarlo a comprender mejor cómo funciona una red neuronal completa.
Espero que ayude! ¡Salud!^_^
En este ejemplo voy a ir a través de la implementación del modelo de perceptrón en C++ para que pueda tener una mejor idea de cómo funciona.
Lo primero es una buena práctica para escribir un algoritmo simple de lo que queremos hacer.
Algoritmo:
- Hacer un vector de los pesos e inicializar a 0 (No se olvide de añadir el término de sesgo)
- seguir ajustando los pesos hasta que consigamos 0 errores o mínima recuento de errores
- Haga predicciones sobre datos no vistos.
Al haber escrito un algoritmo super simple, ahora escribamos algunas de las funciones que necesitaremos.
- Necesitaremos una función para calcular la entrada de la red (p.i * x * wT * multiplicando el tiempo entradas los pesos)
- una función escalonada de manera que se obtiene una predicción de ya sea 1 o -1
- y una función que encuentra los valores ideales para los pesos.
Así que sin más preámbulos vamos a entrar en eso.
Vamos a empezar sencilla mediante la creación de una clase perceptrón:
class perceptron
{
public:
private:
};
Ahora vamos a añadir las funciones que vamos a necesitar.
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:
};
Aviso cómo la función encaja toma como argumento un vector de vectores < flotador>. Eso es porque nuestro conjunto de datos de capacitación es una matriz de entradas. Básicamente, podemos imaginar que la matriz como un par de vectores x superó una sobre otra y cada columna de esa matriz es una característica.
Finalmente, agreguemos los valores que nuestra clase necesita tener. Tal como el vector w para sujetar los pesos, el número de épocas que indica el número de pasadas que vamos a hacer sobre el conjunto de datos de entrenamiento. Y la constante eta que es la tasa de aprendizaje de los cuales vamos a multiplicar cada actualización de peso con el fin de hacer que el procedimiento de entrenamiento más rápido marcando este valor hacia arriba o si eta es demasiado alto podemos marcarlo hasta obtener el resultado ideal (para la mayoría de aplicaciones del perceptrón que sugeriría un eta valor 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.
Vamos a empezar desde el constructor (perceptrón (eta flotador, épocas int);)
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 se puede ver lo que vamos a hacer es algo muy simple. Pasemos a otra función simple. La función predecir (int predecir (vector X);). Recuerde que lo que el todo predicen función no se está llevando a la entrada de red y devuelve un valor de 1 si el netInput es mayor que 0 y -1 otherwhise.
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
Tenga en cuenta que utilizamos una instrucción If en línea para hacer nuestras vidas más fáciles. Así es como funciona la instrucción if en línea:
condición?if_true: else
Hasta ahora todo bien. Vamos a pasar a la aplicación de la funciónnetInput (flotador netInput (vector X);)
El netInput hace lo siguiente; multiplica el vector de entrada por la transpuesta del vector de pesos
* x * wT *
En otras palabras, se multiplica cada elemento del vector de entrada x por el correspondiente elemento del vector de pesos w y luego toma su suma y agrega el sesgo.
* (x1 * x2 + w1 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 por lo que ahora están casi hechas. 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 fue esencialmente. ¡Con solo 3 funciones, ahora tenemos una clase de perceptrón de trabajo que podemos usar para hacer predicciones!
En caso de que quiera copiar y pegar el código y probarlo. Aquí está toda la clase (he añadido algunas funciones extra como imprimir el vector de pesos y los errores en cada época, así como añadió la opción de importar los pesos/exportación.)
Aquí está el código:
El cabecera 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 .cpp clase 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 que aquí se muestra 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 Importé el conjunto de datos del iris no es realmente ideal, pero yo sólo quería algo que funcionó.
Los archivos de datos se pueden encontrar here.
espero que haya encontrado útil esta información!
@Martin nada malo con C++ para esto. – Simon
C/C++ Perceptron: http: // sourceforge.net/projects/ccperceptron/ – SomethingSomething