Я написал простой «Учебник», который вы можете проверить ниже.
Это простая реализация модели персептрона. Вы можете представить себе персептрон как нейронную сеть с одним нейроном. Существует код проклятия, который вы можете проверить, что я написал на C++. Я прохожу через код шаг за шагом, поэтому у вас не должно быть никаких проблем.
Хотя персептрон на самом деле не является «нейронной сетью», это действительно полезно, если вы хотите начать работу и можете лучше понять, как работает полная нейронная сеть.
Надеюсь, что это поможет! Приветствия!^_^
В этом примере я буду идти через реализацию модели персептрона в C++, так что вы можете получить лучшее представление о том, как она работает.
Прежде всего, это хорошая практика написать простой алгоритм того, что мы хотим сделать.
Алгоритм:
- Сделать вектор для весов и инициализировать его в 0 (Не забудьте добавить термин смещения)
- Держите корректировки весов, пока мы не получим 0 ошибок или низкий количество ошибок.
- Сделайте прогнозы по невидимым данным.
Написав супер простой алгоритм, давайте теперь напишем некоторые из функций, которые нам понадобятся.
- Нам нужна функция для расчета ввода сети (e.я * х * Wt * умножения времени входы весов)
- ступенчатой функции, так что мы получаем предсказание либо 1, либо -1
- И это функция, которая находит идеальные значения для весов.
Итак, без дальнейших церемоний, давайте прямо в него.
Давайте начнем с простого, создав класс перцептрона:
class perceptron
{
public:
private:
};
Теперь давайте добавим функции, которые нам необходимы.
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:
};
Обратите внимание, как функция подходит принимает в качестве аргумента вектор вектор < поплавка>. Это связано с тем, что наш учебный набор данных является матрицей входных данных. По существу мы можем представить себе, что матрица как пара векторов x укладывает один поверх другого и каждый столбец этой матрицы является признаком.
И наконец, добавим значения, которые должен иметь наш класс. Такие, как вектор ж для удержания веса, количества эпох, который указует количество проходов, что мы будем делать по обучающему набору данных. И постоянная ета который является скоростью обучения которых мы умножаем каждое обновление веса для того, чтобы сделать процедуру обучения быстрее, набрав это значение или если эта- слишком высок, мы можем набрать его вниз получить идеальный результат (для большинства применений персептрона я бы предложил eta значение 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;
};
Теперь с нашим классом. Пришло время написать каждую из функций.
Мы будем исходить из конструктора (персептрона (флоат ETA, внутр эпох);)
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
}
Как вы можете видеть, что мы будем делать очень простые вещи. Итак, перейдем к другой простой функции. Функция прогнозирования (int pred (вектор X);). Помните, что то, что все предсказать функция не принимает чистый ввод и возвращает значение 1, если netInput больше, чем 0 и -1 otherwhise.
int perceptron::predict(vector<float> X)
{
return netInput(X) > 0 ? 1 : -1; //Step Function
}
Обратите внимание, что мы использовали заявление inline if, чтобы облегчить нашу жизнь. Вот как работает inline if:
состояние?if_true: else
Пока все хорошо. Давайте перейдем к реализации функции netInput (поплавок netInput (вектор X);)
netInput выполняет следующие действия; умножает входной вектор транспонированной вектора весов
* х * Wt *
Другими словами, она умножает каждый элемент входного вектора х соответствующими элемент вектора весов w, а затем берет свою сумму и добавляет смещение.
* (x1 * w1 + x2 * w2 + ... + х * шп) + смещение *
* смещение = 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;
}
Хорошо так мы в настоящее время в значительной степени сделано последнее, что нам нужно сделать, это написать fit функция, которая изменяет вес.
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
}
}
}
Так было по существу. Имея только 3 функции, теперь у нас есть рабочий класс персептрона, который мы можем использовать для прогнозирования!
Если вы хотите скопировать код и попробовать его. Вот весь класс (я добавил некоторые дополнительные функции, такие как печать вектора весов и ошибки в каждой эпохе, а также добавлена возможность импортировать/экспортировать веса.)
Вот код:
класс заголовка:
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;
};
класс .cpp файл с функциями:
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;
}
Кроме того, если вы хотите попробовать пример здесь пример, который я сделал:
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;
}
Как я импортировал ирис набор данных не совсем идеально, но я просто хотел что-то работал.
Файлы данных можно найти here.
Я надеюсь, что вы нашли это полезным!
@ Мартин ничего плохого с C++ для этого. – Simon
C/C++ Perceptron: http: // sourceforge.net/projects/ccperceptron/ – SomethingSomething