Веса, связи и слои

Нейрон сам по себе ничего не решает — решают числа на связях между нейронами. Эти числа называются весами, и именно они делают сеть умной.
Вес — число, показывающее, насколько сильно один нейрон влияет на другой; именно веса меняются при обучении.

Зачем вообще нужны какие-то веса

Представь, что ты решаешь, идти ли сегодня гулять. На решение влияет куча факторов: какая погода, сделаны ли уроки, зовут ли друзья, не сел ли телефон. Но влияют они по-разному. Если на улице ливень — это почти отменяет прогулку, как ни крути. А вот заряд телефона важен, но не настолько: можно и без него выйти.

Получается, у каждого фактора есть свой «вес» в твоей голове. Погода — тяжёлый фактор, телефон — лёгкий. Ты не считаешь это в столбик, но мозг как будто умножает каждый фактор на его важность и складывает. Если сумма «за» перевешивает — идёшь гулять.

Нейросеть устроена ровно так же, только честно, через числа. В прошлом уроке про нейрон и нейросеть мы выяснили, что нейрон — это простой элемент: получает несколько чисел на входе и выдаёт одно число на выходе. Сегодня разберёмся, как именно он превращает входы в выход — и окажется, что вся магия спрятана в весах на связях.

К концу урока ты своими руками посчитаешь в коде, как нейрон решает, кошка перед ним или собака, и увидишь, что «обучение» — это просто аккуратная подкрутка этих чисел.

Метафора: нейрон как строгий вахтёр

Вернёмся к нашему сквозному примеру — задаче отличить кошку от собаки. В самом первом разделе курса мы описывали животное набором признаков: острые ли уши, длинные ли усы, насколько вытянутая морда, громко ли лает. Каждый признак — это число на входе нейрона.

Признак — отдельная измеримая характеристика объекта, по которой модель принимает решение, например форма ушей у животного.

Теперь вообрази нейрон как вахтёра на входе в клуб «Котики». К нему подходят признаки животного и кричат свои значения. Но вахтёр не всем верит одинаково. У него в блокноте записано, насколько важен каждый признак — это и есть веса.

Признак (вход)ЗначениеВес у вахтёраВклад в решение
Острые треугольные уши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. Ждать, что одна поправка всё исправит

Один обучающий пример меняет веса чуть-чуть, и это правильно. Если дёргать веса резко под каждую картинку, сеть будет шарахаться и никогда не устаканится. Это, кстати, прямой путь к переобучению — когда сеть зазубривает отдельные примеры вместо общих правил. Об этом был отдельный разговор в разделе про обучение.

Мини-практика: добавь третьего помощника

Теперь твоя очередь. Возьми код со скрытым слоем из примера выше и доработай его:

  1. Добавь в скрытый слой третьего помощника с весами [0.5, 0.5, -1.0, -2.0] — назови его «проверка размера».
  2. Сделай так, чтобы учитель в выходном слое взвешивал уже три мнения, а не два. Придумай вес для третьего помощника сам.
  3. Прогони сеть на кошке [1, 1, 0, 0.2] и на собаке [0, 0, 1, 1]. Убедись, что ответы остались правильными.
  4. Теперь поэкспериментируй: поменяй один вес у учителя на противоположный по знаку. Как изменился ответ? Это и есть та самая «подкрутка», которой занимается обучение.

Подсказка: тебе не нужно трогать функцию neuron — она уже умеет работать с любым числом входов. Меняй только то, что подаёшь учителю.

Итоги

Сегодня мы заглянули внутрь нейрона и увидели, что вся его «сообразительность» — это арифметика с весами:

  • Вес — число на связи, которое говорит, насколько важен данный вход. Плюс — голос «за», минус — голос «против».
  • Нейрон считает взвешенную сумму: каждый вход умножается на свой вес, всё складывается, результат сравнивается с порогом.
  • Слои соединяют нейроны цепочкой: выход одного слоя — вход следующего. Так сеть улавливает сложные сочетания признаков.
  • Обучение — это изменение весов. Структура сети остаётся, а числа на связях подкручиваются на миллионах примеров, пока ответы не станут точными.

Мы прошли наш сквозной пример «кошка или собака» ещё на шаг глубже: от простого набора признаков к настоящей сети из слоёв. Дальше станет интереснее. В следующих уроках мы возьмёмся за текст — разберём, как слова превращаются в числа через токены и эмбеддинги, и как та же самая взвешенная сумма помогает модели предсказывать слово «молоко» во фразе «Кошка пьёт ...». А потом доберёмся и до трансформера — той самой архитектуры, что крутится внутри ChatGPT. Те же веса, те же слои — просто очень-очень много.

Проверьте себя
1. Что такое вес связи в нейросети?
AРазмер картинки, которую обрабатывает сеть
BЧисло, показывающее, насколько сильно один вход влияет на нейрон
CКоличество слоёв в сети
DПравильный ответ для обучающего примера
2. Признак «громкий лай» имеет значение 0, а его вес равен −3,0. Каков вклад этого признака во взвешенную сумму?
A−3,0 — большой минус
B0 — признак не влияет, ведь лая нет
C3,0 — знак меняется на плюс
D−1,5 — половина веса
3. Как связаны слои нейросети между собой?
AВсе слои получают одни и те же исходные признаки
BВыход одного слоя становится входом для следующего
CСлои работают независимо и не обмениваются числами
DКаждый слой хранит свою копию входной картинки
4. Что в основном меняется, когда нейросеть обучается?
AЧисло слоёв и нейронов в сети
BВеса на связях между нейронами
CСами входные признаки
DПорог, с которым сравнивают сумму, переписывается человеком вручную
5. Почему отрицательный вес — это нормально, а не ошибка?
AЭто всегда баг, отрицательных весов быть не должно
BМинус означает голос «против»: например, лай — аргумент против кошки
CОтрицательный вес отключает нейрон навсегда
DТак помечают слой, который не используется
6. В первом примере у животного острые уши и усы, лая нет, тело мелкое. Взвешенная сумма вышла 3,6 при пороге 0. Что решит нейрон?
AСобака, потому что сумма дробная
BКошка, потому что сумма больше порога
CНичего, нужен ещё один слой
DСобака, потому что сработал вес лая