Матрицы и операции над ними

Brain.js — это библиотека для создания и обучения нейронных сетей на JavaScript. В её основе лежат структуры данных, позволяющие хранить и обрабатывать входные и выходные значения, чаще всего представленные в виде матриц. Матрицы здесь используются как для передачи данных, так и для внутренних вычислений весов и активаций нейронов.

Структура данных

В Brain.js матрица представляет собой двумерный массив чисел, где каждая строка соответствует одному примеру данных, а каждый столбец — признаку или значению нейрона на слое. Например:

const inputMatrix = [
  [0, 1, 0],
  [1, 0, 1],
  [1, 1, 0]
];

Эта матрица может быть использована как входные данные для сети, где строки — отдельные объекты, а столбцы — признаки этих объектов.

Основные операции над матрицами

Матрицы в Brain.js подвергаются ряду стандартных математических операций, необходимых для работы нейронных сетей.

  1. Сложение и вычитание Эти операции выполняются элемент-wise, то есть поэлементно. Например, для двух матриц одинакового размера:
const A = [[1, 2], [3, 4]];
const B = [[5, 6], [7, 8]];

const C = A.map((row, i) => row.map((val, j) => val + B[i][j]));
// C = [[6, 8], [10, 12]]

В Brain.js такие операции часто используются при обновлении весов нейронов после вычисления градиента.

  1. Умножение матриц (матричное и поэлементное)

    • Поэлементное умножение применяется для применения масок или при вычислении некоторых функций активации.
    • Матричное умножение используется для перехода между слоями сети:
const weights = [
  [0.2, 0.8],
  [0.5, 0.1]
];

const input = [
  [1, 0],
  [0, 1]
];

function multiplyMatrices(a, b) {
  const result = [];
  for (let i = 0; i < a.length; i++) {
    result[i] = [];
    for (let j = 0; j < b[0].length; j++) {
      let sum = 0;
      for (let k = 0; k < a[0].length; k++) {
        sum += a[i][k] * b[k][j];
      }
      result[i][j] = sum;
    }
  }
  return result;
}

const output = multiplyMatrices(input, weights);
// output = [[0.2, 0.8], [0.5, 0.1]]

Нормализация и масштабирование данных

Работа с матрицами требует, чтобы значения входных данных находились в диапазоне [0,1] или [-1,1], что значительно ускоряет обучение и повышает стабильность сети. Для этого применяется поэлементное деление на максимальное значение или использование стандартного отклонения:

const normalize = matrix => {
  const flat = matrix.flat();
  const max = Math.max(...flat);
  return matrix.map(row => row.map(val => val / max));
};

Транспонирование матриц

Транспонирование необходимо при реализации обратного распространения ошибки или для приведения данных к нужной размерности перед умножением на веса:

const transpose = matrix => matrix[0].map((_, colIndex) => matrix.map(row => row[colIndex]));

const transposed = transpose(inputMatrix);
// transposed = [[0, 1, 1], [1, 0, 1], [0, 1, 0]]

Использование матриц при обучении сети

В Brain.js веса слоев представляют собой матрицы, а обучение — это последовательное умножение входной матрицы на матрицу весов, применение функции активации и последующая корректировка весов с помощью градиентного спуска.

Пример потока данных через один скрытый слой:

  1. Входная матрица X умножается на матрицу весов W1.
  2. К результату применяется функция активации sigmoid или relu.
  3. Полученная матрица служит входом для следующего слоя.
const sigmoid = x => 1 / (1 + Math.exp(-x));

const hiddenLayer = multiplyMatrices(inputMatrix, weights).map(row =>
  row.map(sigmoid)
);

Практические советы при работе с матрицами

  • Размерности матриц должны строго соответствовать друг другу при умножении.
  • Для больших наборов данных рекомендуется использовать батчи, то есть деление матрицы входных данных на части, чтобы уменьшить нагрузку на память.
  • Любые операции над матрицами лучше реализовывать через map или специализированные библиотеки вроде mathjs, чтобы повысить читаемость и избежать ошибок.

Резюме ключевых моментов

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

Работа с матрицами в Brain.js — это фундамент для понимания более сложных алгоритмов обучения и настройки нейронных сетей.