自転車を発明したり、C ++でパーセプトロンを書いたりします。パート1
C ++でパーセプトロンを実装するための簡単なライブラリを書いてみましょう
前書き
みなさん、こんにちは。この投稿では、ニューラルネットワークを作成した最初の経験を皆さんと共有したいと思います。インターネット上でのニューラルネットワーク(将来のニューラルネットワーク)の実装に関する記事はたくさんありますが、他の人の仕事の本質を理解せずに他の人のアルゴリズムを使いたくないので、自分のコードを最初から作成することにしました。
このパートでは、メイトの要点を説明します。私たちに役立つパーツ。理論全体は、主にWikipediaのさまざまなサイトから取得されます。
学習アルゴリズムを使用して第3部にリンクします:habr.com/ru/post/514626
では、行きましょう。
少し理論
私が「最高の機械学習アルゴリズム」の称号を主張しているのではなく、自分の実装とアイデアを示しているだけであることに同意しましょう。また、私は常にコードに関する建設的な批判やアドバイスを受け入れています。これは重要です。これがコミュニティの目的です。
, .

. .
. :

, (1, 2, 3), u (w1, w2, w3), :
u = x1*w1 + x2*w2 + x3*w3
:

. y(u), u – . , .
, , . , , . , – (, ). :
(0; 1), . y(u) .
, . , .
, , .
, . , , ( ).
, 2 : , .
:
8 ( n1 n8), u, «y(u)» «err», (). «err» .
, , .
, .
. , , , . , .
さて、私は必要な値をニューロンに保存する原理を説明することができました。次に、ニューロン間の接続の重みを格納する方法を理解しましょう。
このネットワークを例にとってみましょう。
..。
メモリ内のニューロンを構造化する方法をすでに知っているので、重みについて同様のテーブルを作成しましょう。
その構造はまったく複雑ではありません。たとえば、ニューロンN1とニューロンn1の間の重みの値は、他の重みと同様に、セルw1-1に含まれています。しかし、繰り返しますが、そのようなマトリックスは、最初の2つのレイヤー間でのみ重みを格納するのに適していますが、2番目と3番目のレイヤーの間のネットワークにはまだ重みがあります。すでにおなじみのトリックを使用してみましょう-配列に新しい次元を追加しますが、注意が必要です。線の名前が重みの「バンドル」に対して左側のニューロンのレイヤーを表示し、右側のニューロンのレイヤーが列の名前に収まるようにします。
次に、ウェイトの2番目の「バンドル」について次の表を取得します。

:

«», .. , , « » , - , . )).
, .
C++. 2
, .
, . .
, !
header —
, . header — ( «neuro.h»). :
class NeuralNet {
public:
NeuralNet(uint8_t L, uint16_t *n);
void Do_it(uint16_t size, double *data);
void getResult(uint16_t size, double* data);
void learnBackpropagation(double* data, double* ans, double acs, double k);
private:
vector<vector<vector<double>>> neurons;
vector<vector<vector<double>>> weights;
uint8_t numLayers;
vector<double> neuronsInLayers;
double Func(double in);
double Func_p(double in);
uint32_t MaxEl(uint16_t size, uint16_t *arr);
void CreateNeurons(uint8_t L, uint16_t *n);
void CreateWeights(uint8_t L, uint16_t *n);
};
, , header' ). :
// , ,
#ifndef NEURO_H
#define NEURO_H
#include <vector> //
#include <math.h> // ,
#include <stdint.h> // , .
:
NeuralNet(uint8_t L, uint16_t *n);
, , - .
void Do_it(uint16_t size, double *data);
)), .
void getResult(uint16_t size, double* data);
.
void learnBackpropagation(double* data, double* ans, double acs, double k);
, .
, :
vector<vector<vector<double>>> neurons; // ,
vector<vector<vector<double>>> weights; // ,
uint8_t numLayers; //
vector<double> neuronsInLayers; //,
/*
, , , ,
*/
double Func(double in); //
double Func_p(double in); //
uint32_t MaxEl(uint16_t size, uint16_t *arr);//
void CreateNeurons(uint8_t L, uint16_t *n);//
void CreateWeights(uint8_t L, uint16_t *n);
header — :
#endif
header . — source — ).
source —
, .
:
NeuralNet::NeuralNet(uint8_t L, uint16_t *n) {
CreateNeurons(L, n); //
CreateWeights(L, n); //
this->numLayers = L;
this->neuronsInLayers.resize(L);
for (uint8_t l = 0; l < L; l++)this->neuronsInLayers[l] = n[l]; //
}
, :
void NeuralNet::Do_it(uint16_t size, double *data) {
for (int n = 0; n < size; n++) { //
neurons[n][0][0] = data[n]; //
neurons[n][1][0] = Func(neurons[n][0][0]); //
}
for (int L = 1; L < numLayers; L++) { //
for (int N = 0; N < neuronsInLayers[L]; N++) {
double input = 0;
for (int lastN = 0; lastN < neuronsInLayers[L - 1]; lastN++) {//
input += neurons[lastN][1][L - 1] * weights[lastN][N][L - 1];
}
neurons[N][0][L] = input;
neurons[N][1][L] = Func(input);
}
}
}
そして最後に、結果を表示する機能についてお話したいと思います。さて、ここでは、最後のレイヤーのニューロンからパラメーターとして渡された配列に値をコピーするだけです:
void NeuralNet::getResult(uint16_t size, double* data) {
for (uint16_t r = 0; r < size; r++) {
data[r] = neurons[r][1][numLayers - 1];
}
}
日没に入る
これで停止します。次のパートでは、ネットワークのトレーニングを可能にする1つの機能について説明します。数学の複雑さと豊富さのために、私はそれを別の部分で取り出すことにしました。そこでは、ライブラリ全体の作業もテストします。
繰り返しになりますが、コメントでのアドバイスやコメントを歓迎します。
記事にご注目いただきありがとうございます。またお会いしましょう!
PS:約束通り-ソースへのリンク:GitHub