Веса, связи и слои
Нейрон сам по себе ничего не решает — решают числа на связях между нейронами. Эти числа называются весами, и именно они делают сеть умной.
Вес — число, показывающее, насколько сильно один нейрон влияет на другой; именно веса меняются при обучении.
Зачем вообще нужны какие-то веса
Представь, что ты решаешь, идти ли сегодня гулять. На решение влияет куча факторов: какая погода, сделаны ли уроки, зовут ли друзья, не сел ли телефон. Но влияют они по-разному. Если на улице ливень — это почти отменяет прогулку, как ни крути. А вот заряд телефона важен, но не настолько: можно и без него выйти.
Получается, у каждого фактора есть свой «вес» в твоей голове. Погода — тяжёлый фактор, телефон — лёгкий. Ты не считаешь это в столбик, но мозг как будто умножает каждый фактор на его важность и складывает. Если сумма «за» перевешивает — идёшь гулять.
Нейросеть устроена ровно так же, только честно, через числа. В прошлом уроке про нейрон и нейросеть мы выяснили, что нейрон — это простой элемент: получает несколько чисел на входе и выдаёт одно число на выходе. Сегодня разберёмся, как именно он превращает входы в выход — и окажется, что вся магия спрятана в весах на связях.
К концу урока ты своими руками посчитаешь в коде, как нейрон решает, кошка перед ним или собака, и увидишь, что «обучение» — это просто аккуратная подкрутка этих чисел.
Метафора: нейрон как строгий вахтёр
Вернёмся к нашему сквозному примеру — задаче отличить кошку от собаки. В самом первом разделе курса мы описывали животное набором признаков: острые ли уши, длинные ли усы, насколько вытянутая морда, громко ли лает. Каждый признак — это число на входе нейрона.
Признак — отдельная измеримая характеристика объекта, по которой модель принимает решение, например форма ушей у животного.
Теперь вообрази нейрон как вахтёра на входе в клуб «Котики». К нему подходят признаки животного и кричат свои значения. Но вахтёр не всем верит одинаково. У него в блокноте записано, насколько важен каждый признак — это и есть веса.
| Признак (вход) | Значение | Вес у вахтёра | Вклад в решение |
| Острые треугольные уши | 1 (есть) | +2,0 | сильно «за кошку» |
| Длинные усы | 1 (есть) | +1,5 | «за кошку» |
| Громкий лай | 1 (есть) | −3,0 | сильно «против кошки» |
| Размер тела | 0,2 (мелкое) | +0,5 | чуть «за кошку» |
Вахтёр берёт каждое значение, умножает на свой вес и всё складывает. Положительный вес значит «этот признак говорит за кошку», отрицательный — «против кошки, скорее собака». Чем больше число по модулю, тем сильнее голос.
Почему именно умножение и сложение
Умножение нужно, чтобы важность признака зависела и от веса, и от самого значения. Если усов нет (значение 0), то даже большой вес даст 0 — признак промолчит. Если усы есть (значение 1) и вес большой — признак крикнет громко. А сложение собирает все голоса в одно общее число, которое вахтёр и сравнивает с порогом: «пускать или нет».
Это общее число до сравнения с порогом называют взвешенной суммой. Запомни словосочетание — мы будем считать именно её.
Где ты встречал такое в жизни? Да буквально везде. Когда ты решаешь, смотреть фильм или нет, ты неосознанно взвешиваешь: оценка на сайте, любимый ли это жанр, советовал ли друг, есть ли время. Каждый из этих факторов имеет в твоей голове разную важность, и в итоге ты складываешь их в одно ощущение «да, стоит» или «нет, пропущу». Лента рекомендаций в соцсети делает то же самое с твоими лайками, только числами и в огромном масштабе. Нейрон — это самая маленькая версия такого решателя.
Считаем ответ нейрона в коде
Хватит слов — посмотрим, как это выглядит в реальном расчёте. Заведём массив признаков животного и массив весов, перемножим попарно и сложим.
// Сквозной пример: кошка против собаки.
// Четыре признака одного животного:
const priznaki = [1, 1, 0, 0.2];
// [острые уши, длинные усы, громкий лай, размер тела]
// Веса вахтёра: насколько важен каждый признак.
// Плюс = за кошку, минус = против кошки.
const vesa = [2.0, 1.5, -3.0, 0.5];
// Считаем взвешенную сумму: вход * вес, всё сложить.
let summa = 0;
for (let i = 0; i < priznaki.length; i++) {
summa = summa + priznaki[i] * vesa[i];
}
console.log("Взвешенная сумма:", summa);
// Порог решения: если сумма больше 0 — это кошка.
const porog = 0;
if (summa > porog) {
console.log("Решение нейрона: КОШКА");
} else {
console.log("Решение нейрона: СОБАКА");
}Вывод:
Взвешенная сумма: 3.6 Решение нейрона: КОШКА
Разберём по шагам, откуда взялось 3,6:
- Острые уши:
1 * 2.0 = 2.0 - Длинные усы:
1 * 1.5 = 1.5 - Громкий лай:
0 * (-3.0) = 0(лая нет, признак промолчал) - Размер тела:
0.2 * 0.5 = 0.1 - Итого:
2.0 + 1.5 + 0 + 0.1 = 3.6
Сумма 3,6 больше порога 0 — нейрон уверенно кричит «кошка». Обрати внимание: лай мог бы всё испортить (вес −3,0!), но его значение было 0, поэтому он не повлиял. Вахтёр учитывает признак, только если тот реально есть.
А если подсунуть собаку
Поменяем входы: уши не острые (0), усов нет (0), зато громко лает (1), и тело крупное (1). Веса оставим те же — вахтёр-то один и тот же.
// Теперь на вход — собака.
const priznaki = [0, 0, 1, 1];
// [острые уши, длинные усы, громкий лай, размер тела]
const vesa = [2.0, 1.5, -3.0, 0.5];
let summa = 0;
for (let i = 0; i < priznaki.length; i++) {
summa = summa + priznaki[i] * vesa[i];
}
console.log("Взвешенная сумма:", summa);
console.log(summa > 0 ? "Решение: КОШКА" : "Решение: СОБАКА");Вывод:
Взвешенная сумма: -2.5 Решение: СОБАКА
Теперь громкий лай с весом −3,0 включился на полную и утянул сумму в минус: 0 + 0 + (-3.0) + 0.5 = -2.5. Сумма меньше нуля — нейрон говорит «собака». Заметь: мы не меняли код и не меняли веса. Изменились только входы — и ответ перевернулся. Один и тот же вахтёр с одним блокнотом правильно сортирует обоих.
Откуда берутся слои
Один нейрон-вахтёр умеет проводить только одну простую границу: «сумма больше порога или нет». Для «кошка или собака» по понятным признакам этого хватает. Но представь задачу хитрее: отличить настоящую кошку на фото от кошки на меме с текстом, или от игрушечной кошки. Тут одной прямой границы мало — нужно сначала собрать промежуточные выводы.
Для этого нейроны выстраивают в слои. Это как школьная иерархия проверки сочинения:
| Слой | Кто это в школьной метафоре | Что делает |
| Входной | Сами буквы и слова в тетради | Просто подаёт сырые признаки |
| Скрытый | Одноклассники-помощники | Каждый замечает свою деталь: «тут про уши», «тут про лай» |
| Выходной | Учитель | Собирает мнения помощников и ставит итог |
Главная идея: выход одного слоя становится входом для следующего. Помощники из скрытого слоя — это такие же нейроны-вахтёры. Каждый считает свою взвешенную сумму по исходным признакам и выдаёт число. А учитель в выходном слое берёт уже не сырые признаки, а готовые мнения помощников — и снова взвешивает их своими весами.
// Признаки животного (входной слой).
const x = [1, 1, 0, 0.2];
// Маленькая функция одного нейрона:
// перемножить входы на веса и сложить.
function neuron(vhody, vesa) {
let s = 0;
for (let i = 0; i < vhody.length; i++) {
s = s + vhody[i] * vesa[i];
}
return s;
}
// Скрытый слой: два помощника со своими весами.
const pomoshnik1 = neuron(x, [2.0, 1.5, -3.0, 0.5]); // "котовость"
const pomoshnik2 = neuron(x, [-1.0, 0.0, 2.5, 1.0]); // "собачность"
console.log("Помощник 1 (кот):", pomoshnik1);
console.log("Помощник 2 (пёс):", pomoshnik2);
// Выходной слой: учитель взвешивает мнения помощников.
const itog = neuron([pomoshnik1, pomoshnik2], [1.0, -1.0]);
console.log("Итог учителя:", itog);
console.log(itog > 0 ? "Решение сети: КОШКА" : "Решение сети: СОБАКА");Вывод:
Помощник 1 (кот): 3.6 Помощник 2 (пёс): -0.8 Итог учителя: 4.4 Решение сети: КОШКА
Смотри, что произошло. Первый помощник посчитал «котовость» — у него получилось 3,6 (то же число, что и раньше). Второй помощник смотрел на те же признаки своими глазами и посчитал «собачность» — вышло −0,8, то есть собачности почти нет. Учитель сложил мнения с весами [1.0, -1.0]: 3.6 * 1.0 + (-0.8) * (-1.0) = 3.6 + 0.8 = 4.4. Уверенно кошка.
Вот так из простых нейронов-вахтёров собирается нейросеть, способная замечать сложные сочетания признаков. И заметь: единственное, что отличает помощника 1 от помощника 2, — это их веса. Сами нейроны идентичны. Вся «личность» нейрона живёт в его весах.
Причём тут обучение
В примерах выше я подбирал веса руками, чтобы получилось красиво. Но в настоящей сети их никто не задаёт вручную — их слишком много (у ChatGPT это сотни миллиардов чисел). Веса находятся сами в процессе обучения.
Обучение с учителем — способ обучения, когда модели показывают примеры вместе с правильными ответами (метками).
Происходит это так. Сети показывают фото с меткой «кошка». Сеть со случайными весами выдаёт, скажем, «собака» — ошиблась. Тогда специальный алгоритм чуть-чуть подкручивает веса в ту сторону, где ответ стал бы ближе к правильному. Один пример — крошечная поправка. Но примеров миллионы, и после миллионов микроподкруток веса сами выстраиваются так, что сеть начинает уверенно различать кошек и собак.
Это и есть главная мысль урока: учиться = менять веса. Структура сети (сколько слоёв, сколько нейронов) остаётся прежней. Меняются только числа на связях. Грубо говоря, обучение — это как настройка громкости у каждого голоса в хоре, пока хор не зазвучит правильно.
Сравни это с тем, как ты сам осваиваешь новую игру. Сначала ты тыкаешь кнопки наугад и проигрываешь. Но после каждого поражения ты чуть-чуть меняешь поведение: «ага, в этот момент надо было увернуться, а не бить». Ты не переписываешь себе мозг заново — ты лишь подкручиваешь свои «веса»: чуть важнее стал один сигнал, чуть менее важным — другой. Через сотню попыток ты играешь уверенно. Сеть делает ровно это, только её «попытки» — это обучающие примеры, а «подкрутка» считается алгоритмом автоматически. Никто не объясняет ей правила словами; она нащупывает их сама, мелкими шагами, по множеству примеров с метками.
Та же логика работает и для нашего второго сквозного примера — предсказания следующего слова во фразе «Кошка пьёт ...». Там сеть тоже взвешивает входы (слова перед пропуском) и через слои приходит к выводу, какое слово вероятнее всего идёт дальше — например «молоко». Веса при обучении на горах текста подкручиваются так, чтобы «молоко» после «кошка пьёт» получало большой голос, а «асфальт» — маленький. Мы подробно вернёмся к этому примеру в разделах про токены и языковые модели.
Частые ошибки и подводные камни
Когда начинаешь разбираться с весами, легко споткнуться на нескольких вещах. Лови список граблей.
1. Путать значение признака и его вес
Это разные числа. Значение признака описывает конкретное животное («усы есть = 1»). Вес описывает важность признака вообще, он один на все картинки. В коде это два разных массива: priznaki и vesa. Если их перепутать местами в голове, всё расчёты поедут.
2. Думать, что отрицательный вес — это «плохо» или «ошибка»
Минус у веса не значит, что что-то сломано. Это просто голос «против». Вес −3,0 у признака «лай» абсолютно нормален: лай — сильный аргумент против кошки. Сети нужны и плюсы, и минусы, иначе она умела бы только соглашаться.
3. Считать, что большой вес всегда сильно влияет
Вклад в сумму — это вес умножить на значение. Если значение признака равно 0, то даже вес 100 даст 0. Помнишь молчащий лай в первом примере? Влияние появляется только когда есть и заметный вес, и ненулевое значение.
4. Менять структуру, когда надо менять веса
Новички часто думают: «сеть ошибается — надо добавить слоёв». Иногда да, но в первую очередь обучение исправляет ответ именно подкруткой весов, а не перестройкой сети. Сначала дай весам настроиться.
5. Ждать, что одна поправка всё исправит
Один обучающий пример меняет веса чуть-чуть, и это правильно. Если дёргать веса резко под каждую картинку, сеть будет шарахаться и никогда не устаканится. Это, кстати, прямой путь к переобучению — когда сеть зазубривает отдельные примеры вместо общих правил. Об этом был отдельный разговор в разделе про обучение.
Мини-практика: добавь третьего помощника
Теперь твоя очередь. Возьми код со скрытым слоем из примера выше и доработай его:
- Добавь в скрытый слой третьего помощника с весами
[0.5, 0.5, -1.0, -2.0]— назови его «проверка размера». - Сделай так, чтобы учитель в выходном слое взвешивал уже три мнения, а не два. Придумай вес для третьего помощника сам.
- Прогони сеть на кошке
[1, 1, 0, 0.2]и на собаке[0, 0, 1, 1]. Убедись, что ответы остались правильными. - Теперь поэкспериментируй: поменяй один вес у учителя на противоположный по знаку. Как изменился ответ? Это и есть та самая «подкрутка», которой занимается обучение.
Подсказка: тебе не нужно трогать функцию neuron — она уже умеет работать с любым числом входов. Меняй только то, что подаёшь учителю.
Итоги
Сегодня мы заглянули внутрь нейрона и увидели, что вся его «сообразительность» — это арифметика с весами:
- Вес — число на связи, которое говорит, насколько важен данный вход. Плюс — голос «за», минус — голос «против».
- Нейрон считает взвешенную сумму: каждый вход умножается на свой вес, всё складывается, результат сравнивается с порогом.
- Слои соединяют нейроны цепочкой: выход одного слоя — вход следующего. Так сеть улавливает сложные сочетания признаков.
- Обучение — это изменение весов. Структура сети остаётся, а числа на связях подкручиваются на миллионах примеров, пока ответы не станут точными.
Мы прошли наш сквозной пример «кошка или собака» ещё на шаг глубже: от простого набора признаков к настоящей сети из слоёв. Дальше станет интереснее. В следующих уроках мы возьмёмся за текст — разберём, как слова превращаются в числа через токены и эмбеддинги, и как та же самая взвешенная сумма помогает модели предсказывать слово «молоко» во фразе «Кошка пьёт ...». А потом доберёмся и до трансформера — той самой архитектуры, что крутится внутри ChatGPT. Те же веса, те же слои — просто очень-очень много.