В предыдущей статье (Синаптические веса в нейронных сетях – просто и доступно https://habr.com/ru/post/589893/) рассказывалось о смысле синаптических весов на примере модели определения цифры для 13-ти сегментного индикатора.

Конечно, для 13-ти сегментов с двумя состояниями (вкл/выкл) можно занести в память все комбинации и определять все простым перебором и совпадением. Но у нас задача учебная, пытаемся осмыслить и переходить к сложному (многослойные нейронные сети) постепенно. Можно сказать, что у нас уже и так нейронная сеть с 13 нейронами на входе и с одним слоем на 10 нейронов. Просто мы пока не используем огромные датасеты и машинное или глубокое обучение. Пока "обучение" прошло простыми расчетами, описанными в предыдущей статье. Итак, продолжим по порядку...

В продолжение составим программу для демонстрации, чтобы сегменты можно было "зажигать" не установкой 1 в ячейке в Excel, а мышкой на сайте.

Немного изменим нумерацию сегментов, чтобы было не по кругу, как в предыдущей статье, а более стандартно – вертикально/горизонтально.

HTML

Рисуем индикатор

Код HTML
<table>
<tr>
<td id="id1" onclick="paint(1)">1</td>
<td id="id2" onclick="paint(2)">2</td>
<td id="id3" onclick="paint(3)">3</td>
</tr>

<tr>
<td id="id4" onclick="paint(4)">4</td>
<td class="td2">&nbsp;</td>
<td id="id5" onclick="paint(5)">5</td>
</tr>

<tr>
<td id="id6" onclick="paint(6)">6</td>
<td id="id7" onclick="paint(7)">7</td>
<td id="id8" onclick="paint(8)">8</td>
</tr>

<tr>
<td id="id9" onclick="paint(9)">9</td>
<td class="td2">&nbsp;</td>
<td id="id10" onclick="paint(10)">10</td>
</tr>

<tr>
<td id="id11" onclick="paint(11)">11</td>
<td id="id12" onclick="paint(12)">12</td>
<td id="id13" onclick="paint(13)">13</td>
</tr>

</table>
<div id="resume">&nbsp;</div>

Задаем стили, чтобы при наведении мышки сегмент «зажигался».

Код CSS
	<style type="text/css">
		body{ background: green;}
		table {color: grey;  border-collapse: collapse;margin:auto;}		
		td {background: #ffffff; border: 1px solid black ;padding:20px;}
		td:hover {background: #333333}
		td.td2 {background: #ffffff;}
	</style>

С рисованием закончили, переходим непосредственно к скрипту на js и расчетам.

JS

Установим начальные значения и зададим веса из таблицы.

Код JS
var sum1=0;
var figure=0;

var indicator_point =  [];
var x_massive = [];
var y_massive = [];

x_massive [0]=[0,1.1,1.1,1.1,1.1,1.1,1.1,-100,1.1,1.1,1.1,1.1,1.1,1.1];
x_massive [1]=[0,-100,-100,2.6,-100,2.6,-100,-100,2.6,-100,2.6,-100,-100,2.6];
x_massive [2]=[0,1.2,1.2,1.2,-100,1.2,1.2,1.2,1.2,1.2,-100,1.2,1.2,1.2];
x_massive [3]=[0,1.2,1.2,1.2,-100,1.2,1.2,1.2,1.2,-100,1.2,1.2,1.2,1.2];
x_massive [4]=[0,1.5,-100,1.5,1.5,1.5,1.5,1.5,1.5,-100,1.5,-100,-100,1.5];
x_massive [5]=[0,1.2,1.2,1.2,1.2,-100,1.2,1.2,1.2,-100,1.2,1.2,1.2,1.2];
x_massive [6]=[0,1.1,1.1,1.1,1.1,-100,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1];
x_massive [7]=[0,1.9,1.9,1.9,-100,1.9,-100,-100,1.9,-100,1.9,-100,-100,1.9];
x_massive [8]=[0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0];
x_massive [9]=[0,1.1,1.1,1.1,1.1,1.1,1.1,1.1,1.1,-100,1.1,1.1,1.1,1.1];

При нажимании на сегменты пересчитываем суммы и выводим результат в виде числа.

Код JS
function paint(id) 
{
sum1=0;
for(var k = 0; k < 10; k++){y_massive[k]=0;}

	if(document.getElementById('id'+id).style.backgroundColor) {
		document.getElementById('id'+id).style.backgroundColor = "";
		indicator_point[id]=0;
		}
        else {
         	document.getElementById('id'+id).style.backgroundColor = "black";
		indicator_point[id]=1;
		}
for(var i = 0; i < 13; i++){ sum1 += indicator_point[i+1]; }

for(var k = 0; k < 10; k++){
	for(var i = 0; i < 13; i++){ y_massive[k] += indicator_point[i+1]*x_massive [k][i+1]; }
	}
max_sum = Math.max.apply(null, y_massive);

for(var k = 0; k < 10; k++){ if (y_massive[k]== max_sum) figure=k; }
if (max_sum==0) figure="";
document.getElementById("resume").innerHTML=figure;
}

Итог

При нажимании на сегменты происходит закрашивание ("зажигание") сегментов и под индикатором показана выявленная цифра. При корректном выборе сегментов все цифры определяются корректно, логика при подборе весов оказалась правильной.

Примечание

При тестировании видно, что программа пытается определить цифру в любом случае, даже если сегменты нажаты не все или не точно по цифре. На этом как раз хорошо заметно, как меняется цифра при нажимании на сегменты. Так можно ощутить важность каждого сегмента для каждой цифры. Хотя это и не входило в задачу в данном случае, но очевидно, что можно так подобрать коэффициенты, что качество восприятия цифры по неполному набору сегментов еще более улучшится.

Ссылка на программу.

Можно тестировать любые комбинации.

Комментарии (5)


  1. SadOcean
    27.08.2022 18:29

    В демке с весами проблема
    0 определяется как 8, как 0 определяется фигура ↄ


    1. AnatolyBelov Автор
      27.08.2022 19:19

      Спасибо )
      для 0 в одном месте коэффициенты неправильно скопировали,
      сейчас поправили, все корректно )


  1. lxsmkv
    28.08.2022 11:52
    +1

    Я расположил входные сигналы на 1,5,6,10, 11 и программа решила, что это похоже на "4", хотя 11 в четверке не возможна.

    пример

    Но, надо сказать, что это наглядно демонстрирует насколько сложной может быть настройка коэффициентов и что тестирование нейросетей совсем не тривиальная задача, хотя, казалось бы, это всего лишь математическая функция, которая проецирует одно множество на другое.

    Количество подмножеств одного множества вычисляется по формуля 2 в степени n. Получается нам для полного покрытия этой функции понадобится 8192 проверки.


    1. AnatolyBelov Автор
      28.08.2022 14:33
      +1

      Спасибо за комментарий )
      Действительно, в ходе применения вылезают ошибки.
      Проверили код, там в цифре "4" на сегменте "11" был коэффициент 1.5, а должно быть -100.
      Поправили, стал определять как 3 )

      Изображение


    1. AnatolyBelov Автор
      28.08.2022 14:37

      Верно. Всего в данном примере возможно 8192 комбинации.