Примитивная нейронная сеть работает некорректно
написал примитивную нейронную сеть без скрытых слоев. На вход дается два числа, но ответ зависит только от первого: если первый элемент равен 1, то и результатом должна быть единица, если 0, то 0. В итоге после обучения нейронная сеть далеко не всегда дает правильный результат. Вот мой код:
#include <iostream>
#include <time.h>
#include <math.h>
using namespace std;
// Summary value in neuron
float NeuronSum(float input[2], float weights[2],float bweight) {
float result = 0;
for (int i = 0; i<2; i++) {
result += input[i] * weights[i];
}
result += 1.0 * bweight;
return result;
}
float ActivateFunction(float x) {
return 1/(1+pow(2.72,-x));
}
float ActivateFunctionDerivative(float x) {
return ActivateFunction(x) * (1-ActivateFunction(x));
}
// ai result
float aiRes(float input[2], float weights[2],float bweight) {
return ActivateFunction( NeuronSum(input, weights, bweight) );
}
int main() {
/*-----------Neural network--------------------------------
-------------STRUCTURE:------------------------------------
* - input neuron, # - hidden neuron, @ - output neuron
-----------------------------------------------------------
*
* @
-----------------------------------------------------------
*/
srand(time(0));
float imput[4][2] = {{1,0}, {0,0}, {0,1}, {1,1}};
float output[4] = {1,0,0,1};
float weights[2];
float speed = 0.3;
float error;
float result;
float rawResult;
// bias weight
float bweight = (float)rand()/(float)(RAND_MAX) * 2 - 1;
for (int weight = 0; weight < 2; weight++) {
weights[weight] = (float)rand()/(float)(RAND_MAX) * 2 - 1;
}
for (int epoch = 1; epoch <= 2000; epoch++) {
for (int i = 0; i < 4; i++) {
rawResult = NeuronSum(imput[i], weights, bweight);
result = aiRes(imput[i], weights, bweight);
error = output[i] - result;
for (int mask = 0; mask < 2; mask++) {
weights[mask] = weights[mask] + error*ActivateFunctionDerivative(rawResult) * result * speed;
}
bweight = bweight + error * ActivateFunctionDerivative(rawResult) * result * speed;
}
}
float test[2] = {1,0};
cout << aiRes(test, weights, bweight) << endl;
if (aiRes(test, weights, bweight) > 0.5) {
cout << "I think answer is 1!";
} else {
cout << "I think answer is 0!";
}
}
Ответы (3 шт):
Автор решения: Константин
→ Ссылка
Вот так)
/*
* File: main.cpp
* Author: papa
*
* Created on 19 октября 2020 г., 6:30
*/
#include <iostream>
#include <time.h>
#include <math.h>
using namespace std;
// Summary value in neuron
float NeuronSum(float input[2], float weights[2],float bweight) {
float result = 0;
for (int i = 0; i<2; i++) {
result += input[i] * weights[i];
}
result += 1.0 * bweight;
return result;
}
float ActivateFunction(float x) {
return 1/(1+pow(2.72,-x));
}
float ActivateFunctionDerivative(float x) {
return ActivateFunction(x) * (1-ActivateFunction(x));
}
// ai result
float aiRes(float input[2], float weights[2],float bweight) {
return ActivateFunction( NeuronSum(input, weights, bweight) );
}
int main() {
/*-----------Neural network--------------------------------
-------------STRUCTURE:------------------------------------
* - input neuron, # - hidden neuron, @ - output neuron
-----------------------------------------------------------
*
* @
-----------------------------------------------------------
*/
srand(time(0));
float imput[4][2] = {{1,0}, {0,0}, {0,1}, {1,1}};
float output[4] = {1,0,0,1};
float weights[2];
float speed = 0.3;
float error;
float result;
float rawResult;
// bias weight
float bweight = (float)rand()/(float)(RAND_MAX) * 2 - 1;
for (int weight = 0; weight < 2; weight++) {
weights[weight] = (float)rand()/(float)(RAND_MAX) * 2 - 1;
}
for (int epoch = 1; epoch <= 2000; epoch++) {
float gl_error = 0;
for (int i = 0; i < 4; i++) {
// rawResult = NeuronSum(imput[i], weights, bweight); // лишний прямой проход для однослойного
result = aiRes(imput[i], weights, bweight);
error = output[i] - result;
for (int mask = 0; mask < 2; mask++) {
weights[mask] = weights[mask] + error*ActivateFunctionDerivative(rawResult) * imput[i][mask] * speed;
}
bweight = bweight + error * ActivateFunctionDerivative(rawResult) * 1 * speed;
gl_error+= (error * error) / 2;
printf("error: %f\n", gl_error);
//if (gl_error < 0.001)
// break;
}
}
float test[2] = {1,0};
cout << aiRes(test, weights, bweight) << endl;
if (aiRes(test, weights, bweight) > 0.5) {
cout << "I think answer is 1!";
} else {
cout << "I think answer is 0!";
}
}
ep: 1954 error: 0.000007
ep: 1955 error: 0.000007
ep: 1956 error: 0.000007
ep: 1957 error: 0.000007
ep: 1958 error: 0.000006
ep: 1959 error: 0.000006
ep: 1960 error: 0.000006
ep: 1961 error: 0.000006
ep: 1962 error: 0.000006
ep: 1963 error: 0.000006
ep: 1964 error: 0.000006
ep: 1965 error: 0.000006
ep: 1966 error: 0.000006
ep: 1967 error: 0.000006
ep: 1968 error: 0.000006
ep: 1969 error: 0.000006
ep: 1970 error: 0.000006
ep: 1971 error: 0.000006
ep: 1972 error: 0.000006
ep: 1973 error: 0.000006
ep: 1974 error: 0.000006
ep: 1975 error: 0.000006
ep: 1976 error: 0.000006
ep: 1977 error: 0.000006
ep: 1978 error: 0.000006
ep: 1979 error: 0.000006
ep: 1980 error: 0.000006
ep: 1981 error: 0.000006
ep: 1982 error: 0.000006
ep: 1983 error: 0.000006
ep: 1984 error: 0.000006
ep: 1985 error: 0.000006
ep: 1986 error: 0.000006
ep: 1987 error: 0.000006
ep: 1988 error: 0.000006
ep: 1989 error: 0.000006
ep: 1990 error: 0.000006
ep: 1991 error: 0.000006
ep: 1992 error: 0.000006
ep: 1993 error: 0.000006
ep: 1994 error: 0.000006
ep: 1995 error: 0.000006
ep: 1996 error: 0.000006
ep: 1997 error: 0.000006
ep: 1998 error: 0.000006
ep: 1999 error: 0.000006
ep: 2000 error: 0.000006
0.996478
I think answer is 1!
Автор решения: Константин
→ Ссылка
Вот с проверкой(оценкой) на обучающем наборе:
/*
* File: main.cpp
* Author: papa
*
* Created on 19 октября 2020 г., 6:30
*/
#include <iostream>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
using namespace std;
// Summary value in neuron
float NeuronSum(float input[2], float weights[2], float bweight)
{
float result = 0;
for (int i = 0; i < 2; i++)
{
result += input[i] * weights[i];
}
result += 1.0 * bweight;
return result;
}
float ActivateFunction(float x)
{
return 1 / (1 + pow(2.72, -x));
}
float ActivateFunctionDerivative(float x)
{
return ActivateFunction(x) * (1 - ActivateFunction(x));
}
// ai result
float aiRes(float input[2], float weights[2], float bweight)
{
return ActivateFunction(NeuronSum(input, weights, bweight));
}
int main()
{
/*-----------Neural network--------------------------------
-------------STRUCTURE:------------------------------------
* - input neuron, # - hidden neuron, @ - output neuron
-----------------------------------------------------------
*
* @
-----------------------------------------------------------
*/
srand(time(0));
float imput[4][2] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
float output[4] = {1, 0, 0, 1};
float weights[2];
float speed = 0.3;
float error;
float result;
float rawResult;
// bias weight
float bweight = (float)rand() / (float)(RAND_MAX)*2 - 1;
for (int weight = 0; weight < 2; weight++)
{
weights[weight] = (float)rand() / (float)(RAND_MAX)*2 - 1;
}
for (int epoch = 1; epoch <= 2000; epoch++)
{
float gl_error = 0;
printf("ep: %d ", epoch);
for (int i = 0; i < 4; i++)
{
// rawResult = NeuronSum(imput[i], weights, bweight); // лишний прямой проход для однослойного
result = aiRes(imput[i], weights, bweight);
error = output[i] - result;
for (int mask = 0; mask < 2; mask++)
{
weights[mask] = weights[mask] + error * ActivateFunctionDerivative(rawResult) * imput[i][mask] * speed;
}
bweight = bweight + error * ActivateFunctionDerivative(rawResult) * 1 * speed;
gl_error += (error * error) / 2;
printf("error: %f\n", gl_error);
// if (gl_error < 0.001)
// break;
}
}
float test[2] = {1, 0};
cout << aiRes(test, weights, bweight) << endl;
if (aiRes(test, weights, bweight) > 0.5)
{
cout << "I think answer is 1!"<<endl;;
}
else
{
cout << "I think answer is 0!"<<endl;;
}
for (int single_array_ind = 0; single_array_ind < 4; single_array_ind++)
{
float *inputs;
float output_1_layer;
inputs = imput[single_array_ind];
output_1_layer = aiRes(inputs, weights, bweight);
bool equal_flag = 0;
float elem_train_out = 0;
// for (int row = 0; row < 2; row++)
// {
float elem_net = 0;
elem_net = output_1_layer;
elem_train_out = output[single_array_ind];
if (elem_net > 0.5)
elem_net = 1;
else
elem_net = 0;
printf("elem: %f", elem_net);
printf("elem tr out: %f", elem_train_out);
if (elem_net == elem_train_out)
equal_flag = 1;
else
{
equal_flag = 0;
break;
}
// }
if (equal_flag == 1)
printf("-vecs are equal-\n");
else
printf("-vecs are not equal-\n");
printf("========\n");
}
system("pause");
return 0;
}
error: 0.000122
error: 0.000155
ep: 1998 error: 0.000015
error: 0.000089
error: 0.000122
error: 0.000155
ep: 1999 error: 0.000015
error: 0.000089
error: 0.000122
error: 0.000155
ep: 2000 error: 0.000015
error: 0.000089
error: 0.000122
error: 0.000155
0.994562
I think answer is 1!
elem: 1.000000elem tr out: 1.000000-vecs are equal-
========
elem: 0.000000elem tr out: 0.000000-vecs are equal-
========
elem: 0.000000elem tr out: 0.000000-vecs are equal-
========
elem: 1.000000elem tr out: 1.000000-vecs are equal-
========
Для продолжения нажмите любую клавишу . . .
Автор решения: Константин
→ Ссылка
Кому интересно, я сделал функцию для разных функций активации на Python и другого, можно переписать на любой язык и управлять посредством числовых кодов(типа байт-коды),можно вставлять на однослойную сеть)Производная функции будет число функции + 1 :)
TRESHOLD_FUNC = 0
TRESHOLD_FUNC_DERIV = 1
SIGMOID = 2
SIGMOID_DERIV = 3
RELU = 4
RELU_DERIV = 5
TAN = 6
TAN_DERIV = 7
INIT_W_MY = 8
INIT_W_RANDOM = 9
LEAKY_RELU = 10
LEAKY_RELU_DERIV = 11
INIT_W_CONST = 12
INIT_RANDN = 13
SOFTMAX = 14
SOFTMAX_DERIV = 15
PIECE_WISE_LINEAR = 16
PIECE_WISE_LINEAR_DERIV = 17
MODIF_MSE = 18
ready = False
# Различные операции по числовому коду
def operations(op, x):
global ready
alpha_leaky_relu = 1.7159
alpha_sigmoid = 1
alpha_tan = 1.7159
beta_tan = 2/3
if op == RELU:
if (x <= 0):
return 0
else:
return x
elif op == RELU_DERIV:
if (x <= 0):
return 0
else:
return 1
elif op == TRESHOLD_FUNC:
if (x > 0):
return 1
else:
return 0
elif op == TRESHOLD_FUNC_DERIV:
return 1
elif op == LEAKY_RELU:
if (x <= 0):
return alpha_leaky_relu
else:
return 1
elif op == LEAKY_RELU_DERIV:
if (x <= 0):
return alpha_leaky_relu
else:
return 1
elif op == SIGMOID:
y = 1 / (1 + math.exp(-alpha_sigmoid * x))
return y
elif op == SIGMOID_DERIV:
y = 1 / (1 + math.exp(-alpha_sigmoid * x))
return alpha_sigmoid * y * (1 - y)
elif op == PIECE_WISE_LINEAR:
if x >= 1/2:
return 1
elif x <1/2 and x > -1/2:
return x
elif x<= 1/2:
return 0
elif op == PIECE_WISE_LINEAR_DERIV:
if x < 1/2 and x > -1/2:
return 1
else:
return 1
elif op == INIT_W_MY:
if ready:
ready = False
return -0.567141530112327
ready = True
return 0.567141530112327
elif op == INIT_W_RANDOM:
return random.random()
elif op == TAN:
y = alpha_tan * math.tanh(beta_tan * x)
return y
elif op == TAN_DERIV:
return beta_tan * alpha_tan * 4 / ((math.exp(beta_tan * x) + math.exp(-beta_tan * x))**2)
elif op == INIT_W_CONST:
return 0.567141530112327
elif op == INIT_RANDN:
return np.random.randn()
else:
print("Op or function does not support ", op)