Форум программистов, компьютерный форум, киберфорум
ИИ, нейросети, LLM, ML, Data Science, ИИ-агенты
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37

Не получается реализовать алгоритм обратного обучения в нейросети

30.12.2020, 05:27. Показов 1031. Ответов 12

Студворк — интернет-сервис помощи студентам
Здравствуйте. Написал алгоритм для обучения нейросети по обратному распространению ошибок. Очень недолго изучаю темы нейронных сетей, пока сложно понять ее, помогите разобраться.
У меня есть 3 эллипса, которым принадлежат точки. Пытаюсь научить сеть разделять точки на небольшой плоскости на 3 группы, по принадлежности к эллипсам соответственно. Получается 2 входа (координаты) и 3 выхода, которые должны выдавать в одном 1, а в остальных двух 0. Между ними скрытый слой из N нейронов. Вроде написал все, но сеть не учится, выдает то ли случайные значения, или просто одинаковые выводы на любые входные данные, сложно понять.
Уже не понимаю, где ошибку допускаю, может алгоритм неправильно запрограммировал, или синтаксическая ошибка какая-то.
Больше всего подозрений на изменение весов, скорее всего в нем проблема, для меня это самая непонятная часть. Ее код:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
for oNode in range(3):  # осуществляем изменение весов выходного слоя
    for hNode in range(hiddenNS + 1):
        outdW[oNode][hNode] = (-etta * eOut[oNode] * activHid[hNode]
                               * fDerivative(activOut[oNode]))
        outW[oNode][hNode] += outdW[oNode][hNode]
for hNode in range(hiddenNS):  # Изменяем веса скрытого слоя
    hidError = 0
    for oNode in range(3):  # получаем ошибку нейрона скрытого слоя
        error = eOut[oNode] * fDerivative(activOut[oNode]) * outW[oNode][hNode]
        hidError += error
    for inNode in range(3):  # находим изменение весов аналогично выходному слою
        hiddW[hNode][inNode] = -etta * hidError * sample[inNode] * fDerivative(activHid[hNode])
        hidW[hNode][inNode] += hiddW[hNode][inNode]
Понимаю алгоритм следующим образом:
1. Проходим по каждому нейрону выходного слоя, в нем по каждому весу скрытого слоя, плюс коэффициент сдвига
2. Перемножаем для изменения веса все элементы:
  • etta - скорость обучения
  • eOut[oNode] - ошибку вывода нейрона выходного слоя
  • activHid[hNode] - выход нейрона скрытого слоя
  • fDerivative(activOut[oNode]) - производная выхода нейрона выходного слоя (активация сигмоиды)
3. Прибавляем изменение веса к весу нейрона выходного слоя
4. Для скрытого слоя суммируем ошибку, перемножая для каждого выходного нейрона ошибку eOut[oNode], производную fDerivative(activOut[oNode]) и значение веса связи нейрона outW[oNode][hNode].
5. Перемножаем все элементы для каждого веса связи входного и скрытого слоев:
  • hidError - ошибку нейрона из предыдущего этапа
  • etta - скорость обучения
  • sample[inNode] - выход входного нейрона (координаты и единица)
  • fDerivative(activHid[hNode]) - производная выхода нейрона скрытого слоя
6. Прибавляем изменения весов к текущим весам

Вроде оба пункта аналогичны, может сам алгоритм я неправильно выполняю? Буду очень признателен за помощь, уже долго мучаюсь над задачей.
Дальше весь код программы с функциями и переменными:
Python
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import random
import math
import matplotlib.pyplot as plt
 
 
def Fx(tp, a, b, x0, alpha):  # функция эллипса для х в исходной системе координат
    res = ((a * math.cos(tp) - b * math.tan(alpha) * math.sin(tp) +  # (с поворотом оси и смещением)
            x0 * math.cos(alpha) + x0 * math.sin(alpha) * math.tan(alpha)) /
           (math.cos(alpha) + math.sin(alpha) * math.tan(alpha)))
    return res
 
 
def Fy(tp, a, b, y0, alpha):  # функция эллипса для у в исходной системе координат
    res = ((a * math.tan(alpha) * math.cos(tp) + b * math.sin(tp) +  # (с поворотом оси и смещением)
            y0 * math.cos(alpha) + y0 * math.sin(alpha) * math.tan(alpha)) /
           (math.cos(alpha) + math.sin(alpha) * math.tan(alpha)))
    return res
 
 
def fNet(ins, w):  # результирующая функция
    res = 0
    for i in range(len(ins)):
        res += ins[i] * w[i]
    return res
 
 
def fActiv(q):  # активационная функция
    return 1 / (1 + math.exp(-q))
 
 
def fDerivative(q):  # функция производной
    return q * (1 - q)
 
 
def train():
    N = int(((tfinish - tstart) / h) + 1)
    Raw = []
    for i in range(N):
        t = tstart + i * h  # строим массивы координат точек для каждого эллипса
        Raw.append([Fx(t, a1, b1, xshift1, alpha1), Fy(t, a1, b1, yshift1, alpha1), 1, [1,0,0]])
        Raw.append([Fx(t, a2, b2, xshift2, alpha2), Fy(t, a2, b2, yshift2, alpha2), 1, [0,1,0]])
        Raw.append([Fx(t, a3, b3, xshift3, alpha3), Fy(t, a3, b3, yshift3, alpha3), 1, [0,0,1]])
    random.seed()
    random.shuffle(Raw)  # перемешиваем элементы массива
    Stud = Raw[:int(3 * N * stSize)]  # обучающая выборка занимает первые элементы массива
    Valid = Raw[int(3 * N * stSize):int(3 * N * (vldSize + stSize))]  # валидационная выборка
    Test = Raw[int(3 * N * (vldSize + stSize)):]  # тестовая выборка
    hidW, hiddW, outW, outdW = [], [], [], []  # массивы весовых коэффициентов и их изменений
    for i in range(hiddenNS):  # задаем входные веса и смещения скрытого слоя
        hidW.append([])
        hiddW.append([])
        for j in range(3):  # массив W со значениями между -wArea и wArea
            hidW[i].append(random.random() * 2 * wArea - wArea)
            hiddW[i].append(0)  # объявляем массив изменений весовых коэффициентов нулями
    for i in range(3):  # задаем входные веса и смещения выходного слоя
        outW.append([])
        outdW.append([])
        for j in range(hiddenNS + 1):
            outW[i].append(random.random() * 2 * wArea - wArea)
            outdW[i].append(0)
    #
    # Начинаем обучение нейросети
    #
    Estud = 0
    for i in range(trials):
        Estud = 0
        random.shuffle(Stud)
        for sample in Stud:
            #
            # Получение активаций нейронов сети
            #
            activHid, netHid = [], []
            for node in range(hiddenNS):  # считаем активационные функции нейронов скрытого слоя
                net = fNet(sample[0:3], hidW[node])
                netHid.append(net)  # массив результирующих каждого нейрона скрытого слоя
                activation = fActiv(net)
                activHid.append(activation)  # массив активаций каждого нейрона скрытого слоя
            activHid.append(1)  # добавим свободный коэффициент на вход следующему слою
            netOut, activOut, desiredOut, eOut = [], [], [], []
            for node in range(3):  # считаем активационные функции нейронов выходного слоя
                net = fNet(activHid, outW[node])  # результирующая выходного нейрона по каждому скрытому
                activ = fActiv(net)
                desired = sample[3][node]  # получаем искомый результат активации
                error = activ - desired
                Estud += error ** 2
                netOut.append(net)
                activOut.append(activ)
                eOut.append(error)
            #
            # Начинаем изменение весов
            #
            for oNode in range(3):  # осуществляем изменение весов выходного слоя
                for hNode in range(hiddenNS + 1):
                    outdW[oNode][hNode] = (-etta * eOut[oNode] * activHid[hNode]
                                           * fDerivative(activOut[oNode]))
                    outW[oNode][hNode] += outdW[oNode][hNode]
            for hNode in range(hiddenNS):  # Изменяем веса скрытого слоя
                hidError = 0
                for oNode in range(3):  # получаем ошибку нейрона скрытого слоя
                    error = eOut[oNode] * fDerivative(activOut[oNode]) * outW[oNode][hNode]
                    hidError += error
                for inNode in range(3):  # находим изменение весов аналогично выходному слою
                    hiddW[hNode][inNode] = -etta * hidError * sample[inNode] * fDerivative(activHid[hNode])
                    hidW[hNode][inNode] += hiddW[hNode][inNode]
        #
        # Проверка на валидационной выборке
        #
        vldCorrect = 0
        for sample in Test:
            activHid, netHid = [], []
            for node in range(hiddenNS):  # считаем активационные функции нейронов скрытого слоя
                net = fNet(sample[0:3], hidW[node])
                netHid.append(net)  # массив результирующих каждого нейрона скрытого слоя
                activation = fActiv(net)
                activHid.append(activation)  # массив активаций каждого нейрона скрытого слоя
            activHid.append(1)  # добавим свободный коэффициент на вход следующему слою
            actual = []
            for node in range(3):  # считаем активационные функции нейронов выходного слоя
                net = fNet(activHid, outW[node])
                activ = fActiv(net)
                qactual = 0
                if activ >= 0.5:
                    qactual = 1
                elif activ < 0.5:
                    qactual = 0
                actual.append(qactual)
            if i == trials - 1:
                print(actual)
            if actual[0] == sample[3][0] and actual[1] == sample[3][1] and actual[2] == sample[3][2]:
                vldCorrect += 1  # если ошибки классификации нет, добавим верно разобранный пример
        if i % 10 == 0:
            MSE = math.sqrt(Estud / len(Stud))
            print('Среднеквадратическая ошибка: ' + str(MSE))
            print('Корректно определены ' + str(vldCorrect) + ' из ' + str(len(Valid))
                  + ' точек валидационной выборки')
    #
    # Обучение завершилось
    #
    MSE = math.sqrt(Estud / len(Stud))
    print('Обучение завершено. Среднеквадратическая ошибка: ' + str(MSE))
    xout1, yout1, xout2, yout2, xout3, yout3 = [], [], [], [], [], []
    for i in range(len(Stud)):
        xout1.append(Stud[i][0])
        yout1.append(Stud[i][1])
    for i in range(len(Valid)):
        xout2.append(Valid[i][0])
        yout2.append(Valid[i][1])
    for i in range(len(Test)):
        xout3.append(Test[i][0])
        yout3.append(Test[i][1])
    x1out1, y1out1, x1out2, y1out2, x1out3, y1out3 = [], [], [], [], [], []
    for i in range(N):
        t = tstart + i * h
        x1out1.append(Fx(t, a1, b1, xshift1, alpha1))
        y1out1.append(Fy(t, a1, b1, yshift1, alpha1))
        x1out2.append(Fx(t, a2, b2, xshift2, alpha2))
        y1out2.append(Fy(t, a2, b2, yshift2, alpha2))
        x1out3.append(Fx(t, a3, b3, xshift3, alpha3))
        y1out3.append(Fy(t, a3, b3, yshift3, alpha3))
    plt.plot(x1out1, y1out1, 'g', label='Эллипс 1', linewidth=0.3)
    plt.plot(x1out2, y1out2, 'g', label='Эллипс 2', linewidth=0.3)
    plt.plot(x1out3, y1out3, 'g', label='Эллипс 3', linewidth=0.3)
    plt.scatter(xout1, yout1, color="g", marker="o", s=3, label='Обучающая')
    plt.scatter(xout2, yout2, color="b", marker="o", s=3, label='Тестовая')
    plt.scatter(xout3, yout3, color="r", marker="o", s=3, label='Валидационная')
    plt.axis('equal')
    plt.xlabel('x')  # названия осей
    plt.ylabel('y')
    plt.title('Обучение нейросети')  # заголовок графика
    plt.legend()
    plt.show()  # отображаем результат работы
    return 0
 
 
h = 0.2  # разбиение
hiddenNS = 14  # количество нейронов скрытого слоя
wArea = 0.5  # диапазон значений весовых коэффициентов
etta = 0.5  # скорость обучения
trials = 100  # количество эпох
stSize = 0.7  # доля обучающей выборки
vldSize = 0.2  # доля валидационной выборки
tstSize = 0.1  # доля тестовой выборки
tstart = 0  # начало параметра t
tfinish = 2 * math.pi  # конец параметра t
#
# Параметры функций эллипсов
#
a1 = 0.4  # большая полуось эллипса
b1 = 0.15  # малая полуось эллипса
xshift1 = 0  # смещение центра симметрии по х
yshift1 = 0  # смещение центра симметрии по у
alpha1 = math.pi / 6  # угол поворота системы координат эллипса (в радианах)
a2 = 0.7
b2 = 0.5
xshift2 = 0
yshift2 = 0
alpha2 = math.pi / 3
a3 = 1
b3 = 1
xshift3 = 0
yshift3 = 0
alpha3 = 0
#
train()
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
30.12.2020, 05:27
Ответы с готовыми решениями:

Алгоритм обучения нейросети
Доброго времени суток. В рамках дипломной работы возникла необходимость описать алгоритм обучения нейросети, расчитывающей некоторую...

Определение адаптивного шага обучения алгоритм обратного распространения ошибки
Доброго времени суток. В ходе изучения теории по алгоритму обратного распространения ошибки возник такой вопрос. При определении...

Процесс обучения нейросети
Добрый день. Подскажите, пожалуйста, я хочу написать нейросеть на С++. Это возможно без подключения MATLAB на чистом С++? Дело в том, что...

12
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
30.12.2020, 07:02
Обновлять веса OutW и HidW следует в самом конце, когда будут посчитаны все OutDW и HidDW.
А то получается HidW обновляются от обновленной половинки нейросети, хотя по ней еще не прогоняли в прямом направлении (не испытана). Надо от старой половинки нейросети обновлять.
Уменьшить etta до 0.05.
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 07:11  [ТС]
Mikhaylo, В смысле пройти по всей выборке, поделить изменения весов на число выборок, и потом их поменять? Или что-то другое имеете в виду? Просто в масштабе одной выборки они вроде не конфликтуют
0
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
30.12.2020, 07:17
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. Вычисляем DW
for oNode in range(3):  # сначала вычисляем коррекции выходного слоя
    for hNode in range(hiddenNS + 1):
        outdW[oNode][hNode] = (-etta * eOut[oNode] * activHid[hNode]
                               * fDerivative(activOut[oNode]))
for hNode in range(hiddenNS):  # потом коррекции скрытого слоя
    hidError = 0
    for oNode in range(3):  # получаем ошибку нейрона скрытого слоя
        error = eOut[oNode] * fDerivative(activOut[oNode]) * outW[oNode][hNode]
        hidError += error
    for inNode in range(3):  # находим изменение весов аналогично выходному слою
        hiddW[hNode][inNode] = -etta * hidError * sample[inNode] * fDerivative(activHid[hNode])
 
# 2. Вычисляем W
for oNode in range(3):  # осуществляем изменение весов выходного слоя
    for hNode in range(hiddenNS + 1):
        outW[oNode][hNode] += outdW[oNode][hNode]
for hNode in range(hiddenNS):  # Изменяем веса скрытого слоя
    for inNode in range(3):  # находим изменение весов аналогично выходному слою
        hidW[hNode][inNode] += hiddW[hNode][inNode]
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 07:24  [ТС]
Mikhaylo, Понял, переписал, но результат от этого не меняется - на выходе все также нет обучения
0
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
30.12.2020, 07:46
Проверьте формулы вычисления ошибок DW.
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 08:10  [ТС]
Mikhaylo, Да я бы с удовольствием, уже 2 раза их переписывал, ничего не вижу в формуле. Может глаз замылился, или алгоритм неверный. Изучал и адаптировал отсюда
Как я написал, я в этом не очень разбираюсь, с математикой как таковой проблем нет, а с применением этих запутанных формул имею трудности. Потому и обратился за помощью в исправлении алгоритма
0
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
30.12.2020, 08:14
Под fDerivative() должен подводиться не выход, а вход. Так: fDerivative(вход)
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 09:28  [ТС]
Mikhaylo, а там разве не функция производной сигмоиды? У меня получается на выход идет активация нейрона (функция сигмоиды), а fDerivative(x) возвращает только число x*(1-x). Или вход это не сумма произведений выходов предыдущего слоя на веса, просто тогда я не знаю, как правильно задать обработку функции fDerivative(x)?
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 09:51  [ТС]
Сделал некоторые исправления в коде по замечаниям, еще 1 ошибку в выборке у себя нашел, проверочная выборка неправильная была подставлена, и считалось в 2 раза меньше примеров. Главная странность в том, что выходной вектор результатов работы нейросети в среднем звене получается полностью без единиц (ну или изредка они бывают). И если подставить везде, где 3 выхода выдали 0 во второй элемент единицу, то результаты получаются близкие к идеальным. Но это какой-то странный костыль получается, так сеть не должна работать, какую-то ошибку я делаю.
Вывод после прохождения обучения, последний вектор активаций нейронов выходного слоя:
Кликните здесь для просмотра всего текста

Обновленный код:
Python
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
import random
import math
import matplotlib.pyplot as plt
 
 
def Fx(tp, a, b, x0, alpha):  # функция эллипса для х в исходной системе координат
    res = ((a * math.cos(tp) - b * math.tan(alpha) * math.sin(tp) +  # (с поворотом оси и смещением)
            x0 * math.cos(alpha) + x0 * math.sin(alpha) * math.tan(alpha)) /
           (math.cos(alpha) + math.sin(alpha) * math.tan(alpha)))
    return res
 
 
def Fy(tp, a, b, y0, alpha):  # функция эллипса для у в исходной системе координат
    res = ((a * math.tan(alpha) * math.cos(tp) + b * math.sin(tp) +  # (с поворотом оси и смещением)
            y0 * math.cos(alpha) + y0 * math.sin(alpha) * math.tan(alpha)) /
           (math.cos(alpha) + math.sin(alpha) * math.tan(alpha)))
    return res
 
 
def fNet(ins, w):  # результирующая функция
    res = 0
    for i in range(len(ins)):
        res += ins[i] * w[i]
    return res
 
 
def fActiv(q):  # активационная функция
    return 1 / (1 + math.exp(-q))
 
 
def fDerivative(q):  # функция производной
    return fActiv(q) * (1 - fActiv(q))
 
 
def train():
    N = int(((tfinish - tstart) / h) + 1)
    Raw = []
    for i in range(N):
        t = tstart + i * h  # строим массивы координат точек для каждого эллипса
        Raw.append([Fx(t, a1, b1, xshift1, alpha1), Fy(t, a1, b1, yshift1, alpha1), 1, [1,0,0]])
        Raw.append([Fx(t, a2, b2, xshift2, alpha2), Fy(t, a2, b2, yshift2, alpha2), 1, [0,1,0]])
        Raw.append([Fx(t, a3, b3, xshift3, alpha3), Fy(t, a3, b3, yshift3, alpha3), 1, [0,0,1]])
    random.seed()
    random.shuffle(Raw)  # перемешиваем элементы массива
    Stud = Raw[:int(3 * N * stSize)]  # обучающая выборка занимает первые элементы массива
    Valid = Raw[int(3 * N * stSize):int(3 * N * (vldSize + stSize))]  # валидационная выборка
    Test = Raw[int(3 * N * (vldSize + stSize)):]  # тестовая выборка
    hidW, hiddW, outW, outdW = [], [], [], []  # массивы весовых коэффициентов и их изменений
    for i in range(hiddenNS):  # задаем входные веса и смещения скрытого слоя
        hidW.append([])
        hiddW.append([])
        for j in range(3):  # массив W со значениями между -wArea и wArea
            hidW[i].append(random.random() * 2 * wArea - wArea)
            hiddW[i].append(0)  # объявляем массив изменений весовых коэффициентов нулями
    for i in range(3):  # задаем входные веса и смещения выходного слоя
        outW.append([])
        outdW.append([])
        for j in range(hiddenNS + 1):
            outW[i].append(random.random() * 2 * wArea - wArea)
            outdW[i].append(0)
    #
    # Начинаем обучение нейросети
    #
    Estud = 0
    for i in range(trials):
        Estud = 0
        random.shuffle(Stud)
        for sample in Stud:
            #
            # Получение активаций нейронов сети
            #
            activHid, netHid = [], []
            for node in range(hiddenNS):  # считаем активационные функции нейронов скрытого слоя
                net = fNet(sample[0:3], hidW[node])
                netHid.append(net)  # массив результирующих каждого нейрона скрытого слоя
                activation = fActiv(net)
                activHid.append(activation)  # массив активаций каждого нейрона скрытого слоя
            activHid.append(1)  # добавим свободный коэффициент на вход следующему слою
            netOut, activOut, desiredOut, eOut = [], [], [], []
            for node in range(3):  # считаем активационные функции нейронов выходного слоя
                net = fNet(activHid, outW[node])  # результирующая выходного нейрона по каждому скрытому
                activ = fActiv(net)
                desired = sample[3][node]  # получаем искомый результат активации
                error = activ - desired
                Estud += error ** 2
                netOut.append(net)
                activOut.append(activ)
                eOut.append(error)
            #
            # Подсчитываем изменение весов
            #
            for oNode in range(3):  # сначала вычисляем коррекции выходного слоя
                for hNode in range(hiddenNS + 1):
                    outdW[oNode][hNode] = (-etta * eOut[oNode] * activHid[hNode]
                                           * fDerivative(netOut[oNode]))
            for hNode in range(hiddenNS):  # потом коррекции скрытого слоя
                hidError = 0
                for oNode in range(3):  # получаем ошибку нейрона скрытого слоя
                    error = eOut[oNode] * fDerivative(netOut[oNode]) * outW[oNode][hNode]
                    hidError += error
                for inNode in range(3):  # находим изменение весов аналогично выходному слою
                    hiddW[hNode][inNode] = (-etta * hidError * sample[inNode]
                                            * fDerivative(netHid[hNode]))
 
            # Вычисляем W
            for oNode in range(3):  # осуществляем изменение весов выходного слоя
                for hNode in range(hiddenNS + 1):
                    outW[oNode][hNode] += outdW[oNode][hNode]
            for hNode in range(hiddenNS):  # Изменяем веса скрытого слоя
                for inNode in range(3):  # находим изменение весов аналогично выходному слою
                    hidW[hNode][inNode] += hiddW[hNode][inNode]
        #
        # Проверка на валидационной выборке
        #
        vldCorrect = 0
        for sample in Valid:
            activHid, netHid = [], []
            for node in range(hiddenNS):  # считаем активационные функции нейронов скрытого слоя
                net = fNet(sample[0:3], hidW[node])
                netHid.append(net)  # массив результирующих каждого нейрона скрытого слоя
                activation = fActiv(net)
                activHid.append(activation)  # массив активаций каждого нейрона скрытого слоя
            activHid.append(1)  # добавим свободный коэффициент на вход следующему слою
            actual = []
            for node in range(3):  # считаем активационные функции нейронов выходного слоя
                net = fNet(activHid, outW[node])
                activ = fActiv(net)
                qactual = 0
                if activ >= 0.5:
                    qactual = 1
                elif activ < 0.5:
                    qactual = 0
                actual.append(qactual)
            if i == trials - 1:
                print(actual)
            # if actual[0] == 0 and actual[1] == 0 and actual[2] == 0:
            #     actual[1] = 1  # второй элемент вектора выхода всегда равен 0, остальные верные
            if actual[0] == sample[3][0] and actual[1] == sample[3][1] and actual[2] == sample[3][2]:
                vldCorrect += 1  # если ошибки классификации нет, добавим верно разобранный пример
        if i % 10 == 0:
            MSE = math.sqrt(Estud / len(Stud))
            print('Среднеквадратическая ошибка: ' + str(MSE))
            print('Корректно определены ' + str(vldCorrect) + ' из ' + str(len(Valid))
                  + ' точек валидационной выборки')
    #
    # Обучение завершилось
    #
    MSE = math.sqrt(Estud / len(Stud))
    print('Обучение завершено. Среднеквадратическая ошибка: ' + str(MSE))
    #
    # Проверка на тестовой выборке
    #
    testCorrect = 0
    for sample in Test:
        activHid, netHid = [], []
        for node in range(hiddenNS):  # считаем активационные функции нейронов скрытого слоя
            net = fNet(sample[0:3], hidW[node])
            netHid.append(net)  # массив результирующих каждого нейрона скрытого слоя
            activation = fActiv(net)
            activHid.append(activation)  # массив активаций каждого нейрона скрытого слоя
        activHid.append(1)  # добавим свободный коэффициент на вход следующему слою
        actual = []
        for node in range(3):  # считаем активационные функции нейронов выходного слоя
            net = fNet(activHid, outW[node])
            activ = fActiv(net)
            qactual = 0
            if activ >= 0.5:
                qactual = 1
            elif activ < 0.5:
                qactual = 0
            actual.append(qactual)
        # if actual[0] == 0 and actual[1] == 0 and actual[2] == 0:
        #     actual[1] = 1  # второй элемент вектора выхода всегда равен 0, остальные верные
        if actual[0] == sample[3][0] and actual[1] == sample[3][1] and actual[2] == sample[3][2]:
            testCorrect += 1  # если ошибки классификации нет, добавим верно разобранный пример
    print('Корректно определены ' + str(testCorrect) + ' из ' + str(len(Test))
          + ' точек тестовой выборки')
 
    xout1, yout1, xout2, yout2, xout3, yout3 = [], [], [], [], [], []
    for i in range(len(Stud)):
        xout1.append(Stud[i][0])
        yout1.append(Stud[i][1])
    for i in range(len(Valid)):
        xout2.append(Valid[i][0])
        yout2.append(Valid[i][1])
    for i in range(len(Test)):
        xout3.append(Test[i][0])
        yout3.append(Test[i][1])
    x1out1, y1out1, x1out2, y1out2, x1out3, y1out3 = [], [], [], [], [], []
    for i in range(N):
        t = tstart + i * h
        x1out1.append(Fx(t, a1, b1, xshift1, alpha1))
        y1out1.append(Fy(t, a1, b1, yshift1, alpha1))
        x1out2.append(Fx(t, a2, b2, xshift2, alpha2))
        y1out2.append(Fy(t, a2, b2, yshift2, alpha2))
        x1out3.append(Fx(t, a3, b3, xshift3, alpha3))
        y1out3.append(Fy(t, a3, b3, yshift3, alpha3))
    plt.plot(x1out1, y1out1, 'g', linewidth=0.3)
    plt.plot(x1out2, y1out2, 'g', linewidth=0.3)
    plt.plot(x1out3, y1out3, 'g', linewidth=0.3)
    plt.scatter(xout1, yout1, color="g", marker="o", s=3, label='Обучающая')
    plt.scatter(xout2, yout2, color="b", marker="o", s=3, label='Тестовая')
    plt.scatter(xout3, yout3, color="r", marker="o", s=3, label='Валидационная')
    plt.axis('equal')
    plt.xlabel('x')  # названия осей
    plt.ylabel('y')
    plt.title('Обучение нейросети')  # заголовок графика
    plt.legend()
    plt.show()  # отображаем результат работы
    return 0
 
 
h = 0.05  # разбиение
hiddenNS = 14  # количество нейронов скрытого слоя
wArea = 0.5  # диапазон значений весовых коэффициентов
etta = 0.1  # скорость обучения
trials = 200  # количество эпох
stSize = 0.7  # доля обучающей выборки
vldSize = 0.2  # доля валидационной выборки
tstSize = 0.1  # доля тестовой выборки
tstart = 0  # начало параметра t
tfinish = 2 * math.pi  # конец параметра t
#
# Параметры функций эллипсов
#
a1 = 0.4  # большая полуось эллипса
b1 = 0.15  # малая полуось эллипса
xshift1 = 0  # смещение центра симметрии по х
yshift1 = 0  # смещение центра симметрии по у
alpha1 = math.pi / 6  # угол поворота системы координат эллипса (в радианах)
a2 = 0.7
b2 = 0.5
xshift2 = 0
yshift2 = 0
alpha2 = math.pi / 3
a3 = 1
b3 = 1
xshift3 = 0
yshift3 = 0
alpha3 = 0
#
train()
0
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
30.12.2020, 09:57
В fDerivative() подставлять не выход активационной функции, а вход. Посмотрите в интернете математические выкладки, в результате которых появляется эта fDerivative().
0
0 / 0 / 0
Регистрация: 28.06.2016
Сообщений: 37
30.12.2020, 10:08  [ТС]
Ну правильно - получается это моя функция fNet(), которая суммирует произведения каждого выхода нейрона предыдущего слоя на вес связи между ним и нейроном текущего слоя, для которого сумма и находится. Я ее как раз в коде так и переписал по вашему совету
0
698 / 574 / 75
Регистрация: 20.09.2014
Сообщений: 3,726
31.12.2020, 08:44
Отследите вычисления вручную: считать не надо, просто проконтролируйте знак ошибки и сравните со знаками коррекции (отрицательное, положительное, ноль).
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.12.2020, 08:44
Помогаю со студенческими работами здесь

Нюансы обучения нейросети
Добрый день. 1. При обучение модели, есть возможность задать параметр validation_split. Как он работает? Можно разбить выборку и...

Скорость нейросети и её обучения
Начинаю разбираться с нейросетями и возник вопрос, если кто сможет подскажите. Нейросеть должна выполнять некоторую работу, т.е. после...

Матрица для обучения нейросети
Здравствуйте!Изучаю C код нейросети одного програмиста,провел немного рефакторинга.Мне нужно сделать обучение для логического И.Там у него...

Задача реализации обучения нейросети без учителя
Нужно реализировать залачу обучения нейросети без учителя. Можете посоветовать какие-то примеры или библиотеки что б можно было посмотреть...

Поясните код нейросети на основе обучения с подкреплением
Здравствуйте. Искала как сделать нейросеть на основе обучения с подкреплением и вот нашла. В теории, как работает я понимаю, а вот на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru