Здравствуйте, я реализовал класс Perceptron. Создал первый слой из 3 персептронов и второй слой из 1 персептрона. Когда запускаю обучение, сеть изменяется (ее веса изменяются), но на выходе она дает вообще другой результат, не который нужен мне. Подскажите, пожалуйста, в чем проблема?
perceptron - реализация класса, main - обучение
perceptron.h
C++ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| #pragma once
#include <vector>
#include <cmath>
#include <ctime>
class Perceptron {
private:
std::vector<double> weights; //веса персептрона
double learning_rate; //скорость обучения
double output; //последнее выходное значение
double local_derivative; //локальный градиент
public:
//конструктор по умолчанию
Perceptron(int w_number, double l_r = 0.1) {
srand(time(NULL));
this->learning_rate = l_r;
for (int i = 0; i < w_number; i++) {
this->weights.push_back(-0.5 + (double)rand() / RAND_MAX); //записываем случайное число от -0.5 до 0.5
}
}
double activate(std::vector<double> input);
double predict(std::vector<double> input);
std::vector<double>get_weights();
void set_weights(std::vector<double> weights);
void learn(std::vector<double> input, double error);
//void learn(std::vector<double> input, double loc_der);
std::vector<double> get_local_derivatives();
}; |
|
perceptron.cpp
C++ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| #include "perceptron.h"
double func(double x) {
return 1. / (1. + exp(x));
}
double derivative(double x) {
double y = func(x);
return y * (1. - y);
}
//производная f(x)(1-f(x))
//функция активации
double Perceptron::activate(std::vector<double> input) {
double out = 0;
int size = this->weights.size();
for (int i = 0; i < size; i++) {
out += input[i] * this->weights[i];
}
return out;
}
//логистическая функция предсказания
double Perceptron::predict(std::vector<double> input) {
double out = this->activate(input);
out = func(out);
this->output = out;
return out;
}
//обучение (изменение весов) на основе ошибки и входных данных
void Perceptron::learn(std::vector<double> input, double error) {
this->local_derivative = error * derivative(this->output);
int size = this->weights.size();
for (int i = 0; i < size; i++) {
this->weights[i] -= this->learning_rate * this->local_derivative * input[i];
}
}
//получить локальные градиенты
std::vector<double> Perceptron::get_local_derivatives() {
std::vector<double> loc_der;
int size = this->weights.size();
for (int i = 0; i < size; i++) {
loc_der.push_back(this->weights[i] * this->local_derivative);
}
return loc_der;
}
//получить веса
std::vector<double> Perceptron::get_weights() {
return this->weights;
}
//установить веса
void Perceptron::set_weights(std::vector<double> weights) {
this->weights = weights;
} |
|
main.cpp
C++ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
| #include <iostream>
#include "perceptron.h"
using namespace std;
int main() {
setlocale(LC_ALL, "rus");
//таблица истинности
//исключающее или из 2 входов
vector<vector<double>> inputs(4);
inputs[0] = { 0,0 };
inputs[1] = { 0,1 };
inputs[2] = { 1,0 };
inputs[3] = { 1,1 };
vector<double> answers(4, 0);
answers[1] = answers[2] = 1;
int N_1 = 3;
srand(time(NULL));
vector<Perceptron> first_layer(N_1, Perceptron(2));
for (int i = 0; i < N_1; i++) {
vector<double> weights(2);
for (int j = 0; j < 2; j++) {
weights[j] = -0.5 + (double)rand() / RAND_MAX;
}
first_layer[i].set_weights(weights);
}
//последний персептрон имеет 3 входа
Perceptron last_layer = Perceptron(N_1);
cout << "Веса сети" << endl;
for (int i = 0; i < N_1; i++) {
cout << "Веса нейрона №" << i << endl;
vector<double> weights = first_layer[i].get_weights();
for (int j = 0; j < 2; j++) {
cout << weights[j] << ' ';
}
cout << endl;
}
cout << "Веса выходного нейрона" << endl;
vector<double> weights = last_layer.get_weights();
for (int j = 0; j < 2; j++) {
cout << weights[j] << ' ';
}
cout << endl;
//начинаем обучение
//первая итерация
//прямое распространение
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 4; j++) {
vector<double> out_first_layer;
for (int i = 0; i < N_1; i++) {
out_first_layer.push_back(first_layer[i].predict(inputs[j]));
}
double output = last_layer.predict(out_first_layer);
double error = output - answers[j];
cout << " Ответ сети: " << output << " Нужный ответ " << answers[j] << " итерация №" << i * 4 + j << endl;
//обратное распространение
last_layer.learn(out_first_layer, error);
vector<double> loc_der = last_layer.get_local_derivatives();
for (int i = 0; i < N_1; i++) {
first_layer[i].learn(inputs[j], loc_der[i]);
}
}
}
cout << "Веса сети" << endl;
for (int i = 0; i < N_1; i++) {
cout << "Веса нейрона №" << i << endl;
vector<double> weights = first_layer[i].get_weights();
for (int j = 0; j < 2; j++) {
cout << weights[j] << ' ';
}
cout << endl;
}
cout << "Веса выходного нейрона" << endl;
weights = last_layer.get_weights();
for (int j = 0; j < 2; j++) {
cout << weights[j] << ' ';
}
cout << endl;
return 0;
} |
|
Вернуться к обсуждению:
Обучение сети персептронов для решения xor проблемы C/C++