Производные и градиенты

TensorFlow.js предоставляет мощные средства для работы с производными и градиентами, что делает возможным обучение нейронных сетей и оптимизацию произвольных функций прямо в JavaScript. Центральным элементом является автоматическое дифференцирование, реализованное через tf.grad, tf.grads, tf.variable и tf.tidy для управления памятью.


Автоматическое дифференцирование

Автоматическое дифференцирование (Automatic Differentiation) позволяет вычислять производные функций относительно входных тензоров без явного написания формул производных. В TensorFlow.js различают два типа дифференцирования:

  1. Одиночная производная — вычисляется с помощью функции tf.grad.
  2. Производные по нескольким переменным — реализуются через tf.grads или tf.valueAndGrads.

Пример вычисления градиента одной переменной:

const x = tf.scalar(3.0);
const f = x => x.square().add(x);

const gradFunc = tf.grad(f);
const dx = gradFunc(x);

dx.print(); // Выводит градиент функции f(x) = x^2 + x в точке x=3

В этом примере tf.grad(f) возвращает функцию, которая вычисляет производную f по входному тензору x. Ключевой момент — входной тензор должен быть tf.Tensor или tf.Variable.


Градиенты по нескольким переменным

Для функций, зависящих от нескольких тензоров, используется tf.grads. Она возвращает массив градиентов, соответствующих каждому входу:

const f = (x, y) => x.square().add(y.square());

const gradFunc = tf.grads(f);
const [dx, dy] = gradFunc([tf.scalar(2), tf.scalar(3)]);

dx.print(); // 4
dy.print(); // 6

Каждый элемент массива соответствует производной функции f по соответствующему входному тензору. Использование tf.grads удобно при работе с моделями, где несколько параметров одновременно подлежат оптимизации.


Хранение и обновление переменных

Для обучения моделей создаются переменные (tf.Variable), которые поддерживают обновление значений при оптимизации:

const w = tf.variable(tf.scalar(Math.random()));
const b = tf.variable(tf.scalar(Math.random()));

const f = x => w.mul(x).add(b);

const optimizer = tf.train.sgd(0.1);

optimizer.minimize(() => {
    const loss = f(tf.scalar(2)).sub(tf.scalar(5)).square();
    return loss;
});

w.print();
b.print();

Метод optimizer.minimize автоматически вычисляет градиенты по всем переменным, участвующим в функции потерь, и обновляет их значения с учетом выбранного алгоритма оптимизации.


Получение значений функции и градиентов одновременно

Функция tf.valueAndGrads позволяет одновременно получать значение функции и её градиенты, что полезно при сложных вычислениях и отладке:

const x = tf.scalar(2.0);

const f = x => x.pow(tf.scalar(3)).add(x);
const fAndGrads = tf.valueAndGrads(f);

const {value, grads} = fAndGrads(x);

value.print(); // f(x) = x^3 + x
grads[0].print(); // df/dx = 3*x^2 + 1

Такой подход упрощает отслеживание динамики функции и градиентов в процессе обучения.


Оптимизация вычислений и управление памятью

При работе с TensorFlow.js важно управлять памятью, так как тензоры создаются в GPU или WebGL-контексте. Для этого применяется tf.tidy, который автоматически освобождает промежуточные тензоры:

tf.tidy(() => {
    const x = tf.scalar(2.0);
    const y = tf.scalar(3.0);
    const z = x.mul(y).add(x);
    z.print();
}); // после выполнения z, x и y освобождаются автоматически

Это предотвращает утечки памяти при повторных вычислениях градиентов в циклах обучения.


Применение градиентов в нейронных сетях

В глубоких моделях градиенты используются для обратного распространения ошибки (backpropagation). TensorFlow.js позволяет определить слой или модель, вычислить функцию потерь и обновить веса с помощью оптимизатора:

const xs = tf.tensor2d([[1, 2], [3, 4]]);
const ys = tf.tensor2d([[1], [0]]);

const w = tf.variable(tf.randomNormal([2, 1]));
const b = tf.variable(tf.zeros([1]));

const predict = x => x.matMul(w).add(b);

const loss = (pred, label) => pred.sub(label).square().mean();

const optimizer = tf.train.adam(0.01);

for (let i = 0; i < 100; i++) {
    optimizer.minimize(() => loss(predict(xs), ys));
}

w.print();
b.print();

Каждая итерация автоматически вычисляет градиенты функции потерь по w и b и обновляет параметры модели.


Производные высших порядков

TensorFlow.js поддерживает вычисление производных второго и более высоких порядков через tf.grad и tf.grads рекурсивно:

const x = tf.scalar(2.0);
const f = x => x.pow(tf.scalar(3));

const df = tf.grad(f);
const d2f = tf.grad(df);

df(x).print();   // 3 * x^2 = 12
d2f(x).print();  // 6 * x = 12

Такое функциональное построение градиентов позволяет исследовать кривизну функции и применять методы второго порядка, такие как оптимизация с использованием матрицы Гессе.


Вывод

TensorFlow.js предоставляет гибкий инструмент для вычисления производных и работы с градиентами, который интегрируется с WebGL и позволяет обучать модели прямо в браузере. Основные элементы включают tf.grad, tf.grads, tf.valueAndGrads, переменные tf.Variable и оптимизаторы tf.train. Управление памятью через tf.tidy обеспечивает эффективное использование ресурсов, а поддержка производных высших порядков расширяет возможности анализа и оптимизации функций.