Русский
Русский
English
Статистика
Реклама

Нейросеть с нуля своими руками. Часть 3. Sad Or Happy?

В предыдущей части статьи мы написали реализацию простейшей нейросети в виде JS класса. Теперь давайте попробуем дать ей настоящее задание. Сценарий будет следующим: пользователь будет рисовать в определенном блоке веб-страницы смайл, а наша нейросеть попробует определить грустный он или веселый. Давайте приступим.

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

<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport"       content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="NeuralNetwork.js"></script> <title>Sad Or Happy?</title></head><body> <div id="wrapper">   <canvas width="400" height="400" id="paintField"></canvas>   <div id="controls">     <button class="control" id="happy"></button>     <button class="control" id="sad"></button>     <button class="control" id="clear">       Clear     </button>     <button class="control" id="train">       Train     </button>     <button class="control" disabled id="predict">       Predict     </button>   </div> </div></body><style>   #wrapper {       width: 400px;       margin: 0 auto;   }   #paintField {       height: 400px;       width: 100%;       border: 1px solid black;   }   #controls {       display: grid;       grid-gap: 10px;       grid-template-columns: 1fr 1fr;       margin-top: 30px;   }   #clear, #train, #predict {       grid-column: 1 / -1;   }   .control {       font-size: 20px;       padding: 4px;       cursor: pointer;   }</style><script></script></html>

Коротко пройдемся по элементам управления.

Canvas с id paintField - это канва размером 10 на 10 блоков по 40 пикселей каждый. На ней пользователь с помощью мыши будет рисовать смайл для обучения сети или предсказания от нее.

Кнопки с id happy и sad будут заполнять набор данных для обучения нейросети. Пользователь нарисовал смайл, нажал соответствующую кнопку, сеть запомнила и стала чуточку умнее.

Кнопка Clear будет очищать поле ввода. Вдруг нам не понравилось то, что мы нарисовали.

Кнопка Train будет запускать процесс обучения.

И, наконец, кнопка Predict будет показывать что думает нейросеть по поводу нашего рисунка. Она станет доступной после обучения.

Теперь переходим в пустой тег <script> и начинаем шаг за шагом его заполнять.

const canvas = document.querySelector('#paintField');const clearBtn = document.querySelector('#clear');const sadBtn = document.querySelector('#sad');const happyBtn = document.querySelector('#happy');const trainBtn = document.querySelector('#train');const predictBtn = document.querySelector('#predict');const ctx = canvas.getContext('2d');const paintField = new Array(100);const trainData = [];const NN = new Network(100, 2);let mouseDown = false;let happyCount = 0;let sadCount = 0;NN.learningRate = 0.8;

Здесь мы записали в переменные ссылки на элементы управления для более удобного доступа к ним и объявили несколько ключевых вещей:

paintField - плоский массив для хранения состояния нашего рисунка. Он состоит из 100 элементов, каждый элемент соответствует одному из блоков на нашей канве.

trainData - сюда мы будем складывать данные для обучения сети.

NN - собственно наша нейросеть. У нее будет 100 нейронов во входном слое - по одному на каждый элемент массива paintField и 2 нейрона в выходном слое. Первый будет говорить нам о вероятности того, что это веселый смайл, второй - что грустный.

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

Теперь добавим несколько функций.

function drawGrid() { ctx.strokeStyle = '#CCC' for (let i = 1; i < 10; i++) {   ctx.moveTo(0, i * 40);   ctx.lineTo(400, i * 40);   ctx.moveTo(i * 40, 0);   ctx.lineTo(i * 40, 400); } ctx.stroke();}function clearCanvas() { ctx.fillStyle = '#FFF'; ctx.fillRect(0, 0, 400, 400); drawGrid();}function drawSquare(row, column, color) { ctx.fillStyle = color; ctx.fillRect(column * 40 + 1, row * 40 + 1, 38, 38);}function draw(event) { const rowIndex = Math.floor(event.offsetY / 40); const columnIndex = Math.floor(event.offsetX / 40); const arrayIndex = rowIndex * 10 + columnIndex; paintField[arrayIndex] = 1; const color = paintField[arrayIndex] ? 'green' : 'white'; drawSquare(rowIndex, columnIndex, color);}function clearField() { paintField.fill(false); clearCanvas(ctx)}function updateInterface() { happyBtn.innerText = `=) ${happyCount}`; sadBtn.innerText = `=( ${sadCount}`;}function storeResult(value) { trainData.push([[...paintField], value]); updateInterface()}

drawGrid - рисует сетку на канве.

clearCanvas - очищает канву от наших художеств.

drawSquare - рисует цветной блок по заданным координатам сетки.

draw - функция, в которую мы будем передавать событие мыши. Она по координатам курсора определит номер блока, запишет в массив единицу под соответствующим индексом, и покрасит соответствующий блок в зеленый цвет.

clearField - очищает массив данных и канву.

updateInterface - обновляет надписи на кнопках, в соответствии с тем, сколько грустных и веселых смайлов мы уже показали нашей нейросети.

storeResult - добавляет текущий рисунок в массив данных для обучения.

И, наконец, навесим обработчики на элементы управления и выполним начальную инициализацию.

document.addEventListener('mousedown', (e) => { mouseDown = true;});document.addEventListener('mouseup', (e) => { mouseDown = false;});canvas.addEventListener('mousemove', (e) => { if (!mouseDown) {   return; } draw(e);});clearBtn.addEventListener('click', () => { clearField();});happyBtn.addEventListener('click', () => { happyCount += 1; storeResult([1, 0]); clearField();});sadBtn.addEventListener('click', () => { sadCount += 1; storeResult([0, 1]); clearField();});predictBtn.addEventListener('click', () => { NN.input = [...paintField]; const [happiness, sadness] = NN.prediction; alert(`I think it's a ${happiness > sadness ? 'happy' : 'sad'} face!\n  Happiness: ${Math.round(happiness * 100)}% Sadness: ${Math.round(sadness * 100)}%`);});trainBtn.addEventListener('click', () => { NN.train(trainData, 1000).then(() => {   predictBtn.disabled = false;   alert('Trained!'); })});clearField();updateInterface();

Теперь точно все. Можем открывать страницу в браузере и начинать экспериментировать. Нарисовали грустный или веселый смайл, нажали соответствующую кнопку, повторили. Старайтесь добавлять примерно одинаковое количество кейсов, и добавляйте их не слишком мало - так сеть ничему не научится, и не слишком много - так обучение будет идти слишком долго. Когда решите что уже достаточно, жмите Train и ожидайте соответствующее сообщение. Появилось? Все! теперь наша сеть обучена и мы можем нарисовать смайл и спросить на что он похож с помощью кнопки Predict.

Thats all, Folks!

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

Посмотреть на результат в деле вы можете по ссылке

Весь код можно найти в репозитории

Спасибо за внимание.

Источник: habr.com
К списку статей
Опубликовано: 06.05.2021 18:22:32
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Javascript

Программирование

Научно-популярное

Ml

Нейросети

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru