Форум программистов, компьютерный форум, киберфорум
ИИ, нейросети, LLM, ML, Data Science, ИИ-агенты
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.80/25: Рейтинг темы: голосов - 25, средняя оценка - 4.80
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200

Проблема с обучением простой нейронной сети методом Левенберга-Марквардта

04.09.2019, 17:22. Показов 6253. Ответов 69

Студворк — интернет-сервис помощи студентам
На простом примере сформулирую свой вопрос. Сеть ниже прекрасно обучается методом Левенберга



Вот процесс обучения https://youtu.be/eL8rE4VMBMA Как видим всего 12 итераций
На вход подаю (с шагом 0.05) 17 точек x = 0.1:0.05:0.9, на выходе надо получить параболу: y = (2*x - 1).^2 + 0.1; (синие точки на видео и в программе).
Программа написана на матлабе специально в упрощенном виде так, чтобы каждый мог ее легко понять.
Кликните здесь для просмотра всего текста
Matlab M
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function leven_parabola1
E = eye(12); % единичная матрица
[x y u v h] = start;
i = 0;
while 1
  [dE J] = grad_jac(u, v, x, y);
  [er u v] = one_step(E, dE, J, u, v, x, y);
  i = i + 1;
  h = draw(u, v, x, h, i, er); 
  if er < 10^(-4) || 50 < i
  % выход из цикла когда или ошибка меньше 0.0001 или число итераций больше 50
    break
  end
end
end

Опишу подробно каждую функцию.
Кликните здесь для просмотра всего текста
Matlab M
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
function [x y u v h] = start
x = (0.1:0.05:0.9)'; % столбец входных х
y = (2*x - 1).^2 + 0.1; % парабола, которую надо получить на выходе
plot(x, y, '.'); % выводим параболу на график
u = rand(2,4); v = rand(4,1); % генерация двух матриц весов
y1 = fnet(x, u, v);  % функция сети получает значения у через веса сети
h = plot(x,y1,'-w');  % выводим эти значения на график
% h - указатель на линию x,y1 чтобы потом ее можно было стереть
end
function f = fnet(x, u, v)
% функция сети f = v1*f(xu11+u21)+v2*f(xu12+u22)+v3*f(xu13+u23)+v4*f(xu14+u24);
rows = size(x,1);
for i = 1:rows
  x1 = x(i,1);
  s1 = x1*u(1,1) + u(2,1);
  s2 = x1*u(1,2) + u(2,2);
  s3 = x1*u(1,3) + u(2,3);
  s4 = x1*u(1,4) + u(2,4);
  f1 = smd(s1); f2 = smd(s2);
  f3 = smd(s3); f4 = smd(s4);
  f(i,1) = f1*v(1)+f2*v(2)+f3*v(3)+f4*v(4);
end
end
function f = smd(x)
f = 1./(1+exp(-x)); % сигмоид
end
function [dE J] = grad_jac(u, v, x, y)
J = jacobi_mat(u, v, x); % J - матрица Якоби
y1 = fnet(x, u, v); d = y1 - y; % d - столбец разностей
dE = J'*d; % градиент (J' - символ ' - транспонирование матрицы J)
end

Формула для матрицы Якоби



Матрица ниже есть раскрытие матрицы выше.
Многоточие означает дополнительные строки для каждого х. Всего 17 строк.
Кликните здесь для просмотра всего текста
Matlab M
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
function J = jacobi_mat(u, v, x)
% матрица Якоби для функции: y = v11*f1 + v21*f2 + v31*f3 + v41*f4
J = []; n = numel(x); % n - число элементов в массиве х (в данном случае n = 17)
for i = 1:n
  row = one_row(x(i), u, v);
  J = [J; row];
end
end
function row = one_row(x, u, v)
s1 = x*u(1,1)+u(2,1); [f1 df1] = sgm(s1);
s2 = x*u(1,2)+u(2,2); [f2 df2] = sgm(s2);
s3 = x*u(1,3)+u(2,3); [f3 df3] = sgm(s3);
s4 = x*u(1,4)+u(2,4); [f4 df4] = sgm(s4);
 
du11 = v(1,1)*x*df1;
du12 = v(2,1)*x*df2;
du13 = v(3,1)*x*df3;
du14 = v(4,1)*x*df4;
 
du21 = v(1,1)*df1;
du22 = v(2,1)*df2;
du23 = v(3,1)*df3;
du24 = v(4,1)*df4;
 
du = [du11 du12 du13 du14 du21 du22 du23 du24];
 
dv11 = f1; dv21 = f2; dv31 = f3; dv41 = f4;
dv = [dv11 dv21 dv31 dv41];
row = [du dv];
end
function [f df] = sgm(x)
f = 1./(1+exp(-x)); df = f.*(1-f); % сигмоид и его производная
end


Кликните здесь для просмотра всего текста
Matlab M
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
function [er1 u v] = one_step(E, dE, J, u, v, x, y)
er = sumerr(x, y, u, v);
J2 = J'*J; % произведение транспонированной матрицы на себя - аппроксимация матрицы Гессе
m = 0.0001;
while 1
  H = J2 + m*E;
  H1 = H^(-1); % Н1 - обратная матрица к Н
  dw = H1*dE;  % dw - столбец изменения весов
  du = reshape(dw(1:8),4,2); % из первых восьми чисел dw создаем матрицу размером 4х2
  dv = reshape(dw(9:12),4,1); % из элементов с 9 по 12 столбца dw создаем матрицу 4х1
  % обновляем веса
  u1  = u - du'; % здесь транспонирование du необходимо ввиду того что du сейчас 4х2, а u 2х4
  v1 = v - dv;
  er1 = sumerr(x, y, u1, v1); % er1 - новая ошибка при новых весах
  if er < er1
    m = 2*m;
  else
    u = u1; v = v1; break
  end
end
end
function err = sumerr(x, y, u, v)
% err - суммарная ошибка сети при данных u, v
y1 = fnet(x, u, v);
d = y1 - y; err = sum(d.*d);
end

Перехожу к моей проблеме. Рассмотрим похожую сеть с двумя выходами



Каждый выход должен нарисовать свою параболу. Изменения в функциях ниже
Кликните здесь для просмотра всего текста
Matlab M
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
function [x y u v h] = start
x = (0.1:0.05:0.9)'; % входной столбец значений х тот же самый
y1 = (2*x - 1).^2 + 0.1;  % парабола на верхнем выходе
y2 = -3*(x - 0.6).^2 + 0.9; % парабола на нижнем выходе
y = [y1 y2]; % выходной массив у состоит уже из двух столбцов
pot(x,y1,'.'); plot(x,y2,'.k'); % выводим два графика: первый синие точки, второй - черные
 
u = rand(2,4); v = rand(4,2); % матрица весов v состоит уже из двух столбцов
 
f = fnet(x, u, v); % функция сети выдает два столбца
h(1) = plot(x,f(:,1),'-c');
h(2) = plot(x,f(:,2),'-y');
end
function f = fnet(x, u, v)
% y1 = v11*f1 + v21*f2 + v31*f3 + v41*f4
% y2 = v12*f1 + v22*f2 + v32*f3 + v42*f4
rows = size(x,1);
for i = 1:rows
  x1 = x(i,1);
  s1 = x1*u(1,1) + u(2,1);
  s2 = x1*u(1,2) + u(2,2);
  s3 = x1*u(1,3) + u(2,3);
  s4 = x1*u(1,4) + u(2,4);
  f1 = smd(s1);
  f2 = smd(s2);
  f3 = smd(s3);
  f4 = smd(s4);
  f(i,1) = f1*v(1,1)+f2*v(2,1)+f3*v(3,1)+f4*v(4,1);
  f(i,2) = f1*v(1,2)+f2*v(2,2)+f3*v(3,2)+f4*v(4,2);
end
end

Проблема моя в том что я не знаю как посчитать матрицу Якоби для "функции" с двумя выходами. Есть вариант считать последовательно для первого выхода J и dE, и обновлять веса, затем для второго выхода J и dE и обновлять веса. Но этот метод работает не так хорошо как функции net в матлабе. В матлабе эта сеть обучается за 10-30 итераций, а этот способ последовательного обновления дает десятки тысяч итераций.
Можно минимизировать функцию ошибки сети



Но это тоже не работает: https://youtu.be/ekuE5zfobOo
Считал я это так:

Не по теме:

Кликните здесь для просмотра всего текста
Matlab M
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
function [J dE] = grad_jac(u, v, x, y)
f = fnet(x, u, v); d = f - y; % в d здесь два столбца
J = jacobi_matE(x, u, v, d); % матрица Якоби для функции ошибки сети Е
er = sum(d.*d,2);  % один столбец = сумма квадратов двух столбцов d
dE = J'*er; % градиент ?  
end
function J = jacobi_matE(x, u, v, d)
% матрица Якоби для ф-ции:
% E = 1/2*sum[(y1-Y1)^2+(y2-Y2)^2]
% y1 = v11*f1 + v21*f2 + v31*f3 + v41*f4
% y2 = v12*f1 + v22*f2 + v32*f3 + v42*f4
% аналитические выкладки дифференцирования не привожу, но все проверил
% через функцию численного дифференцирования. Результат совпал.
% если нужно могу это все описать подробно
n = numel(x); e = ones(n,1); xe = [x e]; 
s = xe*u; [f df] = sgm(s); J = [];
for i = 1:numel(x)
  df1 = df(i,:); f1 = f(i,:); dr = d(i,:);
  row = one_row(x(i), df1, f1, dr, v);
  J = [J; row];
end
end
function row = one_row(x, df, f, dy, v)
dE_du11 = x*df(1)*(v(1,1)*dy(1) + v(1,2)*dy(2));
dE_du12 = x*df(2)*(v(2,1)*dy(1) + v(2,2)*dy(2));
dE_du13 = x*df(3)*(v(3,1)*dy(1) + v(3,2)*dy(2));
dE_du14 = x*df(4)*(v(4,1)*dy(1) + v(4,2)*dy(2));
 
dE_du21 = df(1)*(v(1,1)*dy(1) + v(1,2)*dy(2));
dE_du22 = df(2)*(v(2,1)*dy(1) + v(2,2)*dy(2));
dE_du23 = df(3)*(v(3,1)*dy(1) + v(3,2)*dy(2));
dE_du24 = df(4)*(v(4,1)*dy(1) + v(4,2)*dy(2));
 
dE_dv11 = f(1)*dy(1);
dE_dv21 = f(2)*dy(1);
dE_dv31 = f(3)*dy(1);
dE_dv41 = f(4)*dy(1);
 
dE_dv12 = f(1)*dy(2);
dE_dv22 = f(2)*dy(2);
dE_dv32 = f(3)*dy(2);
dE_dv42 = f(4)*dy(2);
 
row = [dE_du11 dE_du12 dE_du13 dE_du14 ...
       dE_du21 dE_du22 dE_du23 dE_du24 ...
       dE_dv11 dE_dv21 dE_dv31 dE_dv41 ...
       dE_dv12 dE_dv22 dE_dv32 dE_dv42];
end

0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.09.2019, 17:22
Ответы с готовыми решениями:

Обучение сверточной нейронной сети LeNet-5 методом Левенберга Марквардта
Здравствуйте! Ранее задавал вопрос о формирований слоя C3 в калссической архитектуре LeNet-5...

Решение системы интегральных уравнений методом Левенберга-Марквардта
Доброго времени суток, уважаемые Гуру форума =) Появилась необходимость решить систему уравнений: \begin{cases} &amp; \text{ }...

Проблемы с обучением нейронной сети
Решаю задачу регрессии. Прогнозируемая величина изменяется в основном в пределах от 1 до 2, но иногда попадаются большие значения вроде 10,...

69
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
05.09.2019, 18:03  [ТС]
Получилось https://youtu.be/JMWKIj6ydB0 Великолепно работает!

На следующей неделе расскажу как сделал. Это вообще надо кому-то?
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
05.09.2019, 21:04
Цитата Сообщение от tur9 Посмотреть сообщение
Это вообще надо кому-то?
Сначала расскажите нам про вычислительную сложность алгоритма обращения матриц.
Затем попробуйте прикинуть, что будет в хоть сколько-нибудь реально интересной сейчас задаче. Например, MNIST - 28*28=784 входа, 10 выходов, на скрытом слое MLPшки пусть будет 300 нейронов (размер где-то в районе точки выхода на асимптоту зависимости точности от размера MLP). Посчитайте размеры H и H^(-1), расскажите нам, как собираетесь впихивать такие матрицы в память компа, посчитайте время обращения , умножьте на число эпох обучения (ну, пусть будет пара десятков - если обычному стохастическому обучению хватает полусотни эпох, то Л-М пусть будет сходиться за меньшее число).
В итоге получится ответ на Ваш вопрос.
0
699 / 575 / 75
Регистрация: 20.09.2014
Сообщений: 3,741
06.09.2019, 04:45
Только академический интерес.
0
47 / 15 / 1
Регистрация: 26.08.2017
Сообщений: 162
06.09.2019, 13:45
Цитата Сообщение от tur9 Посмотреть сообщение
Получилось https://youtu.be/JMWKIj6ydB0 Великолепно работает!
На следующей неделе расскажу как сделал. Это вообще надо кому-то?
Не обращайте внимание на Виктора Геннадиевича пожалуйста, [censored], но и есть доля правды в его отрицаниях, во первых таки да большие входные вектора и чуть более чем тривиальные архитектуры Mlp даже мой супер быстрый алгоритм обращения матриц на Си, будут ложить, а на широком спектре задач преимущества по сравнению с тривиальным SGD достаточно сомнительное, не будет он сходиться также хорошо.
0
1472 / 827 / 140
Регистрация: 12.10.2013
Сообщений: 5,456
07.09.2019, 19:03
tur9, Вот вы реально мучаетесь зря. Выж видите ребят снова перемкнуло на левый холивар.
Чтобы вам полезно ответили нужен “парад планет”. Шарящий в
1) матлабе,
2)в нейросетях, и
3)именно в этом виде обучения
4) да еще и более того, шарящий намного глубже среднего эксперта который по новым книгам только дергает готовые библиотеки тщательно там рекламируемые на выбор.
5)+ ему должно быть не лень “жевать азы”.
Вы просто убиваете время, готовое и работает быстрей и уже есть…Вот реально, будет висеть без ответа.
0
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
08.09.2019, 16:54  [ТС]
Вот работающий код
Кликните здесь для просмотра всего текста
Matlab M
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
function targ2a_forum
% проба совмещения двух выходов
% сеть: вход [x 1] один слой 4 нейрона
% выход два сумматора Y1 Y2
% веса на входе u, на выходе - v
n = 4; E = eye(4*n);
[x y u v h i] = start(n);
while 1
  [J dE] = grad_jac_n(u,v,x,y);
  [er u v] = step(E,dE,J,u,v,x,y,n);
  i = i + 1;
  h = draw(u, v, x, h, i, er);
  if er < 10^(-5) || 1000 < i
    break
  end
end
end
function [J dE] = grad_jac_n(u,v,x,y)
[J1 J2] = jacobi_mat2(x, u, v);
f = fnet(x, u, v); d = f - y;
J = [J1; J2];
dE = J'*d(:);
end
function [er1 u v] = step(E,dE,J,u,v,x,y,n)
er = sumerr(x, y, u, v);
J2 = J'*J; t = 0; m = 0.0001;
while 1
  H = J2 + m*E; t = t + 1;
  H1 = H^(-1); dw = H1*dE; 
  du = reshape(dw(1:2*n),n,2); 
  dv = reshape(dw(2*n+1:4*n),n,2);
  u1  = u - du'; v1 = v - dv;
  er1 = sumerr(x, y, u1, v1);
  if er < er1
    m = 2*m;
  else
    u = u1; v = v1; break
  end
end
end
function [J1 J2] = jacobi_mat2(x, u, v)
% матрица Якоби для ф-ции:
% y1 = v11*f1 + v21*f2 + v31*f3 + v41*f4
% y2 = v12*f1 + v22*f2 + v32*f3 + v42*f4
n = numel(x); o = ones(n,1); x = [x o];
J1 = [];
for i = 1:size(x,1)
  x1 = x(i,1);
  [du dv] = one_row1(x1, u, v);
  row = [du dv];
  J1 = [J1; row];
end
 
J2 = [];
for i = 1:size(x,1)
  x1 = x(i,1);
  [du dv] = one_row2(x1, u, v);
  row = [du dv];
  J2 = [J2; row];
end
end
function [du dv] = one_row1(x, u, v)
s1 = x*u(1,1)+u(2,1); [f1 df1] = sgm(s1);
s2 = x*u(1,2)+u(2,2); [f2 df2] = sgm(s2);
s3 = x*u(1,3)+u(2,3); [f3 df3] = sgm(s3);
s4 = x*u(1,4)+u(2,4); [f4 df4] = sgm(s4);
 
du11 = v(1,1)*x*df1;
du12 = v(2,1)*x*df2;
du13 = v(3,1)*x*df3;
du14 = v(4,1)*x*df4;
 
du21 = v(1,1)*df1;
du22 = v(2,1)*df2;
du23 = v(3,1)*df3;
du24 = v(4,1)*df4;
 
du = [du11 du12 du13 du14 du21 du22 du23 du24];
 
dv11 = f1; dv21 = f2;
dv31 = f3; dv41 = f4;
 
dv12 = 0; dv22 = 0;
dv32 = 0; dv42 = 0;
 
dv = [dv11 dv21 dv31 dv41 dv12 dv22 dv32 dv42];
end
function [du dv] = one_row2(x, u, v)
s1 = x*u(1,1)+u(2,1); [f1 df1] = sgm(s1);
s2 = x*u(1,2)+u(2,2); [f2 df2] = sgm(s2);
s3 = x*u(1,3)+u(2,3); [f3 df3] = sgm(s3);
s4 = x*u(1,4)+u(2,4); [f4 df4] = sgm(s4);
 
du11 = v(1,2)*x*df1;
du12 = v(2,2)*x*df2;
du13 = v(3,2)*x*df3;
du14 = v(4,2)*x*df4;
 
du21 = v(1,2)*df1;
du22 = v(2,2)*df2;
du23 = v(3,2)*df3;
du24 = v(4,2)*df4;
 
du = [du11 du12 du13 du14 du21 du22 du23 du24];
 
dv11 = 0; dv21 = 0;
dv31 = 0; dv41 = 0;
 
dv12 = f1; dv22 = f2;
dv32 = f3; dv42 = f4;
 
dv = [dv11 dv21 dv31 dv41 dv12 dv22 dv32 dv42];
end

Главное здесь 21 и 22 строки
J = [J1; J2]; - совмещение двух матриц Якоби
dE = J'*d( : ); - последовательное умножение удлинненной матрицы на все развернутые невязки
Если бы все это было бы кому-то интересно, то я бы объяснил все подробней.

Добавлено через 19 минут
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Сначала расскажите нам про вычислительную сложность алгоритма обращения матриц.
Затем попробуйте прикинуть, что будет в хоть сколько-нибудь реально интересной сейчас задаче. Например, MNIST - 28*28=784 входа, 10 выходов, на скрытом слое MLPшки пусть будет 300 нейронов (размер где-то в районе точки выхода на асимптоту зависимости точности от размера MLP). Посчитайте размеры H и H^(-1), расскажите нам, как собираетесь впихивать такие матрицы в память компа, посчитайте время обращения , умножьте на число эпох обучения (ну, пусть будет пара десятков - если обычному стохастическому обучению хватает полусотни эпох, то Л-М пусть будет сходиться за меньшее число).
В итоге получится ответ на Ваш вопрос.
Я всего лишь решаю свою небольшую задачу. Сеть должна будет работать онлайн, ни о каких слоях кроме единственного и числа нейронов не более 10 не помышляю. Число входов надеюсь будет порядка 10-14, не более.
- сложность алгоритма обращения матриц - да, это мне скоро будет актуально, но пока об этом не думал. Сеть должна будет обучаться на предварительном запуске машины.

Цитата Сообщение от danila_zaytcev Посмотреть сообщение
мой супер быстрый алгоритм обращения матриц на Си
Вы можете поделиться этим алгоритмом/кодом?

Цитата Сообщение от Excalibur921 Посмотреть сообщение
tur9, Вот вы реально мучаетесь зря. Выж видите ребят снова перемкнуло на левый холивар.
Чтобы вам полезно ответили нужен “парад планет”. Шарящий в
1) матлабе,
2)в нейросетях, и
3)именно в этом виде обучения
4) да еще и более того, шарящий намного глубже среднего эксперта который по новым книгам только дергает готовые библиотеки тщательно там рекламируемые на выбор.
5)+ ему должно быть не лень “жевать азы”.
Вы просто убиваете время, готовое и работает быстрей и уже есть…Вот реально, будет висеть без ответа.
Эта частная задача уже решена, ответ всплыл как-то сам собой. Дальше тоже могут быть другие задачи, тогда и будем думать. Мое положение просто: познакомился с нейронными сетями и с их помощью пытаюсь решить свою практическую задачу. Конечно мне нужна помощь в этом, но где ее взять? Вот нашел это единственное место. Вы знаете другие места?
Матлаб использует этот алгоритм Левенберга-Марквардта по умолчанию, т.е. как основной. Судя по тому что я нашел в русско-язычной сети это вовсе не азы, иначе я бы просто взял готовый код и все.
0
47 / 15 / 1
Регистрация: 26.08.2017
Сообщений: 162
08.09.2019, 17:25
Цитата Сообщение от tur9 Посмотреть сообщение
Вы можете поделиться этим алгоритмом/кодом?
Алгоритм самый обычный, какой в школе изучают, а быстрый так как на Си.

matrix.h
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma once
 
typedef struct
{
    double **data;
    int rows;
    int colls;
} mat;
 
mat* mat_new(int rows, int colls);
void mat_del(mat* m);
mat* mat_transp(mat* m);
void mat_multvec(double* v, mat* m, double* res);
mat* mat_pw(mat* m1, mat* m2, double f(double, double));
mat* mat_fromvec(double* vec, int len);
mat* mat_mult(mat* m1, mat* m2);
mat* mat_copy(mat* m);
mat* mat_one(mat* m);
void mat_print(mat *m);
double mat_det(mat* m);
mat* mat_inverse(mat* m);
matrix.с
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
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sys.h"
#include "matrix.h"
 
mat* mat_new(int rows, int colls)
{
    double **data = malloc(rows * sizeof(double*));
    for (int i = 0; i < rows; ++i) data[i] = calloc(colls, sizeof(double));
    mat tmp = { data,rows,colls };
    return localcpy(&tmp, sizeof(mat));
}
 
void mat_del(mat* m)
{
    for (int i = 0; i < m->rows; ++i) free(m->data[i]);
    free(m->data);
    free(m);
}
 
mat* mat_transp(mat* m)
{
    mat *res = mat_new(m->colls, m->rows);
    for (int i = 0; i < m->rows; ++i)
        for (int j = 0; j < m->colls; ++j)
            res->data[j][i] = m->data[i][j];
 
    return res;
}
 
mat* mat_pw(mat* m1, mat* m2, double f(double, double))
{
    mat *res = mat_new(m1->colls, m1->rows);
    for (int i = 0; i < m1->rows; ++i)
        for (int j = 0; j < m1->colls; ++j)
            res->data[i][j] = f(m1->data[i][j], m2->data[i][j]);
 
    return res;
}
 
mat* mat_fromvec(double* vec, int len)
{
    mat* m = mat_new(len, 1);
    for (int i = 0; i < len; ++i) m->data[i][0] = vec[i];
    return m;
}
 
mat* mat_mult(mat* m1, mat* m2)
{
    mat *res = mat_new(m1->rows, m2->colls);
    for (int i = 0; i < m1->rows; ++i)
    {
        for (int j = 0; j < m2->colls; ++j)
        {
            double p = 0;
            for (int k = 0; k < m1->colls; ++k)
                p += m1->data[i][k] * m2->data[k][j];
 
            res->data[i][j] = p;
        }
    }
    return res;
}
 
void mat_multvec(double* v, mat* m, double* res)
{
    int l = _msize(v) / sizeof(double);
    for (int i = 0; i < m->rows; ++i)
    {
        res[i] = 0;
        for (int j = 0; j < m->colls; ++j)
        {
            double c = j < l ? v[j] : 1;
            res[i] += c * m->data[i][j];
        }
    }
}
 
mat* mat_copy(mat* m)
{
    mat* res = mat_new(m->rows, m->colls);
    for (int i = 0; i < m->rows; ++i)
        for (int j = 0; j < m->colls; ++j)
            res->data[i][j] = m->data[i][j];
 
    return res;
}
 
mat* mat_one(mat* m)
{
    mat* res = mat_new(m->rows, m->colls);
    for (int i = 0; i < m->rows; ++i)
    {
        for (int j = 0; j < m->colls; ++j)
        {
            if (i == j) res->data[i][j] = 1;
            else  res->data[i][j] = 0;
        }
    }
    return res;
}
 
void mat_print(mat *m)
{
    for (int i = 0; i < m->rows; ++i)
    {
        for (int j = 0; j < m->colls; ++j)
            printf("%f\t", m->data[i][j]);
 
        printf("\n");
    }
}
 
double mat_det(mat* m)
{
    mat* tmp = mat_copy(m);
 
    for (int x = 1; x < m->rows; ++x)
    {
        int x1 = x - 1;
        for (int i = x; i < m->rows; ++i)
        {
            if (tmp->data[x1][x1] == 0) return 0;
            double k = tmp->data[i][x1] / tmp->data[x1][x1];
            for (int j = 0; j < m->colls; ++j)
                tmp->data[i][j] -= tmp->data[x1][j] * k;
        }
    }
 
    double det = 1;
    for (int i = 0; i < m->rows; ++i)
        for (int j = 0; j < m->colls; ++j)
            if (i == j) det *= tmp->data[i][j];
 
    mat_del(tmp);
 
    return  det;
}
 
double mat_minor(mat* m, int mi, int mj)
{
    mat *minor = mat_new(m->rows - 1, m->colls - 1);
 
    for (int i = 0; i < m->rows; ++i)
    {
        for (int j = 0; j < m->colls; ++j)
        {
            if (i != mi && j != mj)
            {
                int ii = i < mi ? i : i - 1;
                int jj = j < mj ? j : j - 1;
                minor->data[ii][jj] = m->data[i][j];
            }
        }
    }
 
    double det = mat_det(minor);
    mat_del(minor);
    return det;
}
 
mat* mat_inverse(mat* m)
{
    mat* adds = mat_new(m->rows, m->colls);
    for (int i = 0; i < m->rows; ++i)
    {
        for (int j = 0; j < m->colls; ++j)
        {
            int k = ((i % 2) ^ (j % 2)) ? -1 : 1;
            adds->data[i][j] = k * mat_minor(m, i, j);
        }
    }
 
    mat* tadds = mat_transp(adds);
    mat_del(adds);
    double det = mat_det(m);
    if (det == 0) return NULL;
    mat* res = mat_new(m->rows, m->colls);
 
    for (int i = 0; i < m->rows; ++i)
        for (int j = 0; j < m->colls; ++j)
            res->data[i][j] = tadds->data[i][j] / det; 
 
    mat_del(tadds);
 
    return res;
}
 
void mat_test()
{
    int N = 3;
    mat *m = mat_new(N, N);
    double v1[] = { 2,5,7 };
    double v2[] = { 6,3,4 };
    double v3[] = { 5,-2,-3 };
    m->data[0] = v1;
    m->data[1] = v2;
    m->data[2] = v3;
 
    double right[3][3] = { {1,-1,1},{-38,41,-34},{27,-29,24} };
 
    mat* inv1 = mat_inverse(m);
    mat_print(inv1);
}
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
08.09.2019, 20:36
Цитата Сообщение от tur9 Посмотреть сообщение
Матлаб использует этот алгоритм Левенберга-Марквардта по умолчанию, т.е. как основной.
Для нейросеток - не уверен.
В нейросетках под Эл-Эм'ом подразумевается практически всегда вариант с ЯВНЫМ (но, из-за вычислений, аналогичных бэкпропу, быстрым) вычислением ДИАГОНАЛИ матрицы Гессе. Изобретён в самом конце 1980ых под названием "псевдоньютон", потом переменован в стохастически-диагонального левенберга-марквардта, поскольку, как и Л-М, добавляет некоторую мелкую константу к диагональным элементам.
Проблем же с обращением у диагональной матрицы - нет вообще, обычное 1/a_ii. Хранить тоже можно только вектор-диагональ, а не исходную и обратную матрицы. Т.е. и при расчёте этих вторых производных, и при их обращении - линейная сложность и линейные затраты памяти.

Проверить - легко. Изучите зависимости времени обучения сеток разного размера (задав им одно и то же число итераций) этими дефолтными матлабовскими средствами. Если зависимость времени обучения линейна от размера сети - то Л-М для нейросеток (именно для нейросеток - функции, решающие задачи оптимизации, не берём - там Л-М может быть классическим) в матлабе тот, про который я сказал.
0
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
08.09.2019, 21:24  [ТС]
Цитата Сообщение от danila_zaytcev Посмотреть сообщение
Алгоритм самый обычный, какой в школе изучают, а быстрый так как на Си.
Спасибо. Вряд ли собственно работа с матрицами на С быстрее чем в матлабе.
MATLAB использует высоко оптимизированные библиотеки для умножения матриц
Позднее нам для процессора понадобится библиотека на С для работы с матрицами. Какую посоветуете?

Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Для нейросеток - не уверен.
Следует обратить внимание, что функция TRAINLM используется по умолчанию, поскольку она обеспечивает наиболее быстрое обучение.
http://matlab.exponenta.ru/neu... /newff.php
Обучение НС у нас должно быть на этапе калибровки, т.е. когда память и процессор полупустые. Т.е. и скорость и память в данном случае не существенны (допустимы даже минуты). До решения проблемы (в этой теме) с обучением приходилось обучать (сеть и данные к ней которые я еще не представил) градиентным спуском, а это - уж не знаю почему - требовало сотни миллионов итераций, целая ночь работы, и тем не менее не удавалось достичь требуемой точности. Ту же работу малаб через trainlm делает за секунды.
0
47 / 15 / 1
Регистрация: 26.08.2017
Сообщений: 162
08.09.2019, 21:54
Цитата Сообщение от tur9 Посмотреть сообщение
Спасибо. Вряд ли собственно работа с матрицами на С быстрее чем в матлабе.
При равных прочих однозначно быстрее, но я так понял проверять Вы всё равно не будете...
Цитата Сообщение от tur9 Посмотреть сообщение
Позднее нам для процессора понадобится библиотека на С для работы с матрицами. Какую посоветуете?
Я думаю без разницы, если для матриц нужна сторонняя библиотека, то речь идёт о каком то студенческом творчестве, где производительность не имеет значения, найдите что то модное от Гугл или МелкоМягких, может от Амазона чонить уже есть хз. какой то вебинтерфейс может даже, через облако или соцсети...
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
08.09.2019, 21:55
Цитата Сообщение от tur9 Посмотреть сообщение
Позднее нам для процессора понадобится библиотека на С для работы с матрицами. Какую посоветуете?
Интеловскую MKL.
А все самопальные кривые поделки - забыть.
Либо OpenBLAS. Но MKL в последние годы таки допилили до повышения эффективности работы с мелкими (одна-две-три сотни элементов в строке/столбце) матрицами, а OpenBLAS тут от неё сейчас отстаёт (но всё равно любой наивный самопал уделывает).


Цитата Сообщение от tur9 Посмотреть сообщение
Следует обратить внимание, что функция TRAINLM используется по умолчанию, поскольку она обеспечивает наиболее быстрое обучение.
Это как-то противоречит моим словам о том, что в нейронках может/должен использоваться "неклассический" (не в том виде, в каком он изложен в абстрактной теории градиентной оптимизации) Л-М?
Я ведь согласен, что нейросетевой диагональный Л-М - вещь хорошая. Просто говорю, что это КАЧЕСТВЕННО ОТЛИЧАЮЩИЙСЯ по схеме/формулам вычислений метод. Т.е. если Вы по оптимизационным учебникам напишите свою прогу - то это вероятнее всего будет не тот алг, который стоит за функцией TRAINLM в матлабе.
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
08.09.2019, 22:42
Для иллюстрации неверности того, что наивный код на С/С++ обгонит матлаб, берём очень тупую задачу - перемножение матриц. Это цикл тройной вложенности, никакой сложной алгоритмики.
Вот что было несколько лет назад - пока MKL не допилили (пока она давала околопиковую эффективность только начиная с достаточно больших матриц):
Красным самые высокие гигафлопсы на обоих картинках - результаты той либы, которая собственно и дала тогда хорошего пинка интеловцам.

После допиливания MKL - она значимо подтянулась на матрицах до пары сотен элементов в строке/столбце, где у неё обнаружилось сильное отставание от потанцевала:

Зелёным на первой картинке - Сишный наивный код перемножения матриц. Отставание в гигафлопсах, как видим, в качественные разы. Вы думаете, что в последние несколько лет компиляторы с С/С++ вдруг почему-то качественно улучшились?
Аналогичное отставание С/С++ от вручную написанных на ассемблере с заточкой под разнообразные процессоры математических библиотек (у которых из сишного - только заголовочные файлы с объявлением функций, а сама реализация функций сделана на ассемблере, и используется в ассемблерном коде разнообразный "ИИ" типа настройки на размер кэша конкретного процессора, на котором исполняется прога) - будет и на других матричных функциях.
Так что пусть верящие в мощь сишного кода и разум компиляторов - продолжают верить. А Вы продолжайте пользоваться матлабом, который опирается именно на MKL (ЕМНИП). И при желании написать отвязанную от матлаба прогу - тоже берите MKL. Увы, но ту либу, которая сейчас пиковая по производительности (и название которой я на картинках затёр) - я рассекречивать буду ТОЛЬКО в других условиях
0
699 / 575 / 75
Регистрация: 20.09.2014
Сообщений: 3,741
09.09.2019, 04:32
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Увы, но ту либу, которая сейчас пиковая по производительности (и название которой я на картинках затёр) - я рассекречивать буду ТОЛЬКО в других условиях
Эта либа называется VGT, видно же!
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
09.09.2019, 10:26
Не, не угадал
Из Дании библиотека.
Но я рад, что народ ан масс верит в мои безграничные возможности Как бы нимб мне не начал жать
Особенно на фоне общего отсутствия знаний у контингента (например, один из участников темы/раздела в другом разделе только что спросил, как из целого числа единицы-десятки-сотни выделить-получить).
0
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
09.09.2019, 13:09  [ТС]
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Я ведь согласен, что нейросетевой диагональный Л-М - вещь хорошая. Просто говорю, что это КАЧЕСТВЕННО ОТЛИЧАЮЩИЙСЯ по схеме/формулам вычислений метод. Т.е. если Вы по оптимизационным учебникам напишите свою прогу - то это вероятнее всего будет не тот алг, который стоит за функцией TRAINLM в матлабе.
Так в чем основное отличие? Можете выразить? Может оно несущественное, касается скажем скорости операций или коэффициент m (у меня в проге) вычисляется иначе...? Из сравнения работы моего кода и матлаба пока не вижу какой то радикальной ущербности моего кода.
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
10.09.2019, 16:32
Цитата Сообщение от tur9 Посмотреть сообщение
Так в чем основное отличие?
"Нейросетевой" Л-М явно считает диагональ матрицы Гессе, т.е. вторые производные. Считает способом, аналогичным обратному распространению.
"Обычный" - берёт только первые производные и матрицу Гессе оценивает с их помощью.
Затраты по памяти - линейные и квадратичные (от числа весов в сети) в первом и втором случае соответственно. Вычислительные затраты - линейные и кубические соответственно.
Скорость сходимости - ну, ХЗ, сравнимая наверное. Вот только нейросетевой Л-М спокойно обучает (и обучал ещё в прошлом веке) нейронку с 431 ТЫСЯЧЕЙ весов (LeNet5 - первая "референсная" свёрточная нейросетка для задачи MNIST), и на сетке бОльшего размера не спасует тоже.
0
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
10.09.2019, 17:26  [ТС]
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
"Нейросетевой" Л-М явно считает диагональ матрицы Гессе, т.е. вторые производные. Считает способом, аналогичным обратному распространению.
"Обычный" - берёт только первые производные и матрицу Гессе оценивает с их помощью.
Затраты по памяти - линейные и квадратичные (от числа весов в сети) в первом и втором случае соответственно. Вычислительные затраты - линейные и кубические соответственно.
Скорость сходимости - ну, ХЗ, сравнимая наверное. Вот только нейросетевой Л-М спокойно обучает (и обучал ещё в прошлом веке) нейронку с 431 ТЫСЯЧЕЙ весов (LeNet5 - первая "референсная" свёрточная нейросетка для задачи MNIST), и на сетке бОльшего размера не спасует тоже.
Теперь ясно. Спасибо.
Однажды для простой сети я посчитал на бумажке матрицу Гессе. На это ушло пару дней. С тех пор боюсь прикасаться.
- Считает способом, аналогичным обратному распространению.
Что это за способ, где он описан? Если есть такая автоматизация, то почему только диагональ, а не всю матрицу?
0
2744 / 1670 / 269
Регистрация: 19.02.2010
Сообщений: 4,421
10.09.2019, 19:11
Цитата Сообщение от tur9 Посмотреть сообщение
Что это за способ, где он описан? Если есть такая автоматизация, то почему только диагональ, а не всю матрицу?
У Яна ЛеКуна, в сАмом конце 1980ых, ну и в 1998ом он в паре статей повторил рассказ.
Рабиновичей (если такие были), увы, я не запоминал

Диагональ потому, что вариантом бэкпропа ВСЮ её можно вычислить за время, примерно равное времени вычисления сложной функции. Как и ВЕСЬ вектор градиента при бэкпропе вычисляется за похожее время.
Т.е. на ВСЁ требуется только время ~~t(f(w)), где w - множество адаптивных параметров функции f. А не время ~~t(f(w))*|w|, которое потребуется, например, при вычислении производных через конечные разности.

И потому диагональ, чтобы ВООБЩЕ не было никаких трудозатрат с обращением матрицы. Ибо (diag)^-1=1/a_ii.
Да и последующее матрично-векторное умножение (обратной матрицы Гессе на градиент) в методах Ньютона/Л-М - оно тоже не торт по сравнению с. Ибо в нейросетевом диагональном ЛМ - будет всего лишь покомпонентное произведение двух векторов (вектора обратной диагонали с предварительно добавленной туда мелкой константой - и вектора градиента).

Так что с матрицей или с вычислением диагонали иным способом - всё выходит иного порядка величины временнЫх=вычислительных затрат. А качественной пользы нет. Это в классических градиентных методах оптимизации можно/нужно было тратить время на вычисление более хорошего направления спуска - ибо там вектора-матрицы производных долго считались. А если все/многие производные в нейронках считаются влёт - то и в других алгоритмах (имеются в виду алгоритмы вычисления/коррекции направления градиентного спуска), возникающих/использующихся при обучении MLP и его глубоких/рекуррентных вариантов, лучше отказаться от лишних размерностей.
1
45 / 6 / 1
Регистрация: 20.08.2012
Сообщений: 200
11.09.2019, 14:04  [ТС]
VTsaregorodtsev, спасибо за разъяснения. Вообще говоря, если не возражаете, у меня много вопросов, возможно наивных.
Вот сейчас такой вопрос. Сеть 14 входов + единица, 3 нейрона в единственном слое, выход два сумматора + единица
В нейронах обычные сигмойды. Входные данные Х-26х14 максимум Х 0.08. На выходе надо получить черные точки показанные в первом вложении вложении. Результат работы программы во втором вложении. А в третьем вложении получившиеся матрицы весов. Меня смущают цифры в них: по абс величине более 10 и чуть ли не 40. Это вообще нормально? Ведь сигмойд вообще уходит в ноль после +/- 7. Еще один результат в четвертом вложении, там всего 3428 итераций. Их число меня не смущает, т.к. работает все быстро.
Миниатюры
Проблема с обучением простой нейронной сети методом Левенберга-Марквардта   Проблема с обучением простой нейронной сети методом Левенберга-Марквардта   Проблема с обучением простой нейронной сети методом Левенберга-Марквардта  

Проблема с обучением простой нейронной сети методом Левенберга-Марквардта  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.09.2019, 14:04
Помогаю со студенческими работами здесь

Проблемы с обучением LSTM нейронной сети
Всем привет! Обращаюсь за помощью к людям, имеющим практический опыт обучения LSTM нейронных сетей. Задача - обучить LSTM сеть переводу с...

Как же обучать автокодировщик? Непонятная ситуация с обучением нейронной сети
Доброго времени суток! Сразу к делу. Пытаюсь использовать метод обратного распространения ошибки при обучении автокодировщика. Обучаю на...

Метод Левенберга - Марквардта
Доброго времени суток. Помогите пожалуйста с реализацией метода Левенберга-Марквардта для нахождения значений некоторой заданной функции.

Алгоритм Левенберга-Марквардта
Доброе время суток! Помогите в реализации алгоритма Левенберга-Марквардта в Матлабе. Есть теоретические выкладки, возникает проблема с...

Применение алгоритма Левенберга-Марквардта
представим, есть матрица, в которой содержится нечто похожее на 2умерную ф-цию гаусса, т.е i - это у, j это х, и значение каждого элемента...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут Суть: - Группа наркоманов из 10 человек. - Только один инфицирован ВИЧ. - Колются одной иглой. - Колются раз в день. - Колются последовательно через. . .
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru