TensorFlow.js предоставляет мощные инструменты для вычисления градиентов и оптимизации нейронных сетей прямо в браузере или на сервере с Node.js. Градиенты — это производные функции потерь по параметрам модели, используемые для обновления весов методом градиентного спуска.
В TensorFlow.js ключевыми объектами являются tf.Tensor, tf.Variable и функции автоматического дифференцирования tf.grad и tf.variableGrads. Тензоры неизменяемы, поэтому для обучения модели используются переменные, которые можно обновлять.
const w = tf.variable(tf.scalar(Math.random()));
const x = tf.tensor([1, 2, 3, 4]);
const f = () => w.square().sum();
const grad = tf.grad(f);
const gradient = grad(w);
В примере вычисляется производная функции потерь по весу w. Это основа, на которой строится обучение нейронных сетей.
Взрывной градиент — ситуация, когда значения градиентов становятся чрезвычайно большими, вызывая нестабильность обучения и переполнение чисел. Затухающий градиент — противоположный эффект, когда градиенты становятся слишком малыми, и обучение замедляется или полностью останавливается.
Эти явления особенно часто встречаются в глубоких сетях и рекуррентных нейронных сетях (RNN), где многократное применение матричного умножения или нелинейных функций приводит к экспоненциальному росту или падению градиентов.
Формально, если сеть имеет L слоев, а градиент для веса первого слоя вычисляется как произведение производных всех слоев:
[ = _{l=1}^{L} ]
Если производные больше 1, градиент растёт экспоненциально (взрывной). Если меньше 1 — затухает.
Для анализа градиентов в TensorFlow.js можно использовать прямой вычислительный подход:
const model = tf.sequential();
model.add(tf.layers.dense({units: 50, inputShape: [100], activation: 'relu'}));
model.add(tf.layers.dense({units: 50, activation: 'relu'}));
model.add(tf.layers.dense({units: 10, activation: 'softmax'}));
const x = tf.randomNormal([1, 100]);
const y = tf.oneHot([2], 10);
const optimizer = tf.train.adam(0.01);
for (let i = 0; i < 10; i++) {
const grads = tf.variableGrads(() => {
const preds = model.apply(x);
return tf.losses.softmaxCrossEntropy(y, preds).mean();
});
Object.keys(grads.grads).forEach(name => {
const norm = grads.grads[name].norm().dataSync()[0];
console.log(`${name}: градиент = ${norm}`);
});
optimizer.applyGradients(grads.grads);
}
В этом коде вычисляются нормы градиентов для каждого веса. Резкий рост нормы указывает на взрывной градиент, очень маленькие значения — на затухающий.
const clippedGrads = {};
Object.keys(grads.grads).forEach(name => {
clippedGrads[name] = tf.clipByValue(grads.grads[name], -1, 1);
});
optimizer.applyGradients(clippedGrads);
Использование подходящей инициализации весов
tf.layers.dense({
units: 50,
kernelInitializer: 'heNormal',
activation: 'relu'
});
Выбор функций активации
Использование нормализации
tf.layers.batchNormalization({axis: -1});
Инициализация весов
Глубокие остаточные связи (Residual Connections)
Для устойчивого обучения важно постоянно отслеживать нормы
градиентов. TensorFlow.js предоставляет возможность выполнять
это через метод tf.variableGrads и вычислять
tf.norm. Графики изменения градиентов позволяют определить,
на каком слое возникает взрыв или затухание, что упрощает отладку и
настройку модели.