Обратное распространение ошибки

Обратное распространение ошибки (backpropagation) — это ключевой метод обучения нейронных сетей, включая свёрточные сети, реализованные в ConvNetJS. Он позволяет эффективно вычислять градиенты функции потерь по параметрам сети и корректировать веса для минимизации ошибки.


Архитектура и слои сети

ConvNetJS реализует сети через последовательность слоев (layers). Каждый слой имеет входные и выходные данные:

  • Vol — основной объект для хранения значений нейронов и градиентов. Он представляет собой многомерный массив с числовыми данными (w) и соответствующими градиентами (dw).
  • Слои могут быть различных типов: input, fully connected (fc), convolutional (conv), pooling, relu, softmax и др.

Каждый слой имеет методы:

  • forward(input): вычисляет выход слоя на основе входных данных.
  • backward(): рассчитывает градиенты относительно входов и весов слоя.

Основные этапы обратного распространения

  1. Прямое распространение (Forward pass) Каждое входное изображение или вектор проходит через все слои сети. На этом этапе сохраняются промежуточные значения (vol.w) для дальнейшего вычисления градиентов.

  2. Вычисление функции потерь После последнего слоя вычисляется ошибка сети. В ConvNetJS обычно используется SoftmaxLossLayer или RegressionLayer, которые предоставляют метод loss для расчета ошибки и backward для градиента.

  3. Обратное распространение (Backward pass) Метод backward вызывается в последнем слое для вычисления градиента функции потерь по выходам слоя. Затем градиенты последовательно передаются в предыдущие слои, вычисляя градиенты по весам и входам каждого слоя.


Механизм вычисления градиентов

Каждый слой хранит два ключевых свойства:

  • this.out_act: выходной Vol после прямого распространения.
  • this.in_act: входной Vol, необходимый для вычисления производной.

Пример работы fully connected слоя:

// Прямое распространение
this.out_act = new Vol(1, 1, this.num_outputs, 0);
for (var i = 0; i < this.num_outputs; i++) {
  var a = this.biases.w[i];
  for (var j = 0; j < this.num_inputs; j++) {
    a += this.filters[i].w[j] * input.w[j];
  }
  this.out_act.w[i] = a;
}

// Обратное распространение
this.in_act.dw = new Array(this.num_inputs).fill(0);
for (var i = 0; i < this.num_outputs; i++) {
  var chain_grad = this.out_act.dw[i];
  for (var j = 0; j < this.num_inputs; j++) {
    this.in_act.dw[j] += this.filters[i].w[j] * chain_grad;
    this.filters[i].dw[j] += this.in_act.w[j] * chain_grad;
  }
  this.biases.dw[i] += chain_grad;
}

Ключевые моменты:

  • dw — градиенты весов и смещений, на основе которых обновляются параметры.
  • in_act.dw — градиенты по входам, передаваемые в предыдущий слой.
  • Обратное распространение требует хранения промежуточных активаций (in_act.w) для корректного вычисления градиентов.

Свёрточный слой (Convolutional Layer)

Свёрточный слой выполняет линейное преобразование с использованием фильтров. Основные шаги обратного распространения:

  1. Для каждого фильтра вычисляется градиент весов через умножение соответствующего региона входного объёма на градиент выхода.
  2. Градиент смещения вычисляется как сумма градиентов по всем выходным нейронам, соответствующим конкретному фильтру.
  3. Градиенты по входам формируются суммированием вкладов всех фильтров, перекрывающих конкретный элемент входного объёма.

Пример формулы градиента для веса фильтра:

[ = {x,y} {x,y,f} a_{x+i, y+j}]

где ( {x,y,f} ) — градиент выхода слоя по элементу ((x, y, f)), ( a{x+i, y+j} ) — соответствующая активация входного объёма.


Пуллинговые и нелинейные слои

  • ReLU: Градиент передается только тем элементам, которые были положительными при прямом проходе.
for (var i = 0; i < n; i++) {
  this.in_act.dw[i] = this.out_act.dw[i] * (this.in_act.w[i] > 0 ? 1 : 0);
}
  • MaxPooling: Градиенты передаются только к тем входам, которые были максимальными в прямом проходе.

  • Softmax: Градиент вычисляется как разность предсказанной вероятности и целевого класса для каждой позиции:

[ _i = p_i - t_i]


Особенности ConvNetJS

  • Vol обеспечивает компактное хранение данных и градиентов для CPU- и GPU-вычислений.
  • Каждый слой реализует forward и backward, что позволяет строить сети произвольной глубины.
  • Веса обновляются через оптимизаторы (SGD, AdaGrad), которые используют накопленные градиенты dw.

Применение обратного распространения

  • Обучение сети проводится через итеративное применение forwardlossbackwardupdate.
  • Градиенты аккумулируются и позволяют корректно настраивать все слои, включая свёрточные, полносвязные и нелинейные.
  • Структура ConvNetJS делает возможным обучение небольших и средних сетей в браузере без дополнительных библиотек.