Свёрточные операции низкого уровня

TensorFlow.js предоставляет возможность работы с нейронными сетями непосредственно в браузере или на сервере через Node.js. Одним из ключевых компонентов в обработке изображений и сигналов являются свёрточные операции. Они позволяют извлекать локальные признаки из входных данных, сохраняя пространственную структуру.


Тензоры и их роль в свёртках

Свёрточные операции работают с многомерными массивами данных — тензорами. В TensorFlow.js тензор обозначается объектом tf.Tensor и может иметь до 4 измерений:

  • 1D тензор: одномерный массив значений [batchSize].
  • 2D тензор: матрица [batchSize, features].
  • 3D тензор: например, изображение с каналами [height, width, channels].
  • 4D тензор: батч изображений [batchSize, height, width, channels].

Для свёрточных операций чаще всего используются 3D или 4D тензоры. Важно понимать порядок измерений: в TensorFlow.js стандартно используется формат NHWCbatch, height, width, channels.


Функция tf.conv2d

Для двухмерной свёртки используется функция tf.conv2d. Её ключевые параметры:

  • x — входной тензор [batch, height, width, channels].
  • filter — ядро свёртки [filterHeight, filterWidth, inChannels, outChannels].
  • strides — шаг свёртки. Может быть числом или массивом [strideHeight, strideWidth].
  • pad — тип паддинга: 'valid' (без дополнений) или 'same' (выравнивание по размеру входа).

Пример создания ядра и свёртки:

const x = tf.randomNormal([1, 28, 28, 3]); // Одно изображение 28x28 с 3 каналами
const filter = tf.randomNormal([3, 3, 3, 16]); // Ядро 3x3, 3 входных канала, 16 выходных
const y = tf.conv2d(x, filter, 1, 'same'); // Свёртка с шагом 1, паддинг same

Особенности работы:

  • При pad='same' выходной размер сохраняется, что удобно для глубоких сетей.
  • Ядро должно иметь количество входных каналов, равное каналам входного тензора.
  • Функция поддерживает обратное распространение градиента для обучения сети.

Использование tf.depthwiseConv2d

Для глубинных свёрток, когда каждый канал обрабатывается отдельно, применяется tf.depthwiseConv2d. Параметры:

  • x — входной тензор [batch, height, width, channels].
  • filter — ядро [filterHeight, filterWidth, inChannels, channelMultiplier].
  • strides и pad аналогичны conv2d.

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


Базовые операции и трансформации

Перед свёрткой данные часто нормализуются или изменяются с помощью операций:

  • tf.reshape — изменение формы тензора.
  • tf.transpose — перестановка осей, например для перехода из NHWC в NCHW.
  • tf.pad — ручное добавление нулевых границ.
  • tf.concat — объединение тензоров по заданной оси.

Пример подготовки данных для свёртки:

let img = tf.randomNormal([32, 28, 28, 3]);
img = tf.pad(img, [[0,0],[1,1],[1,1],[0,0]]); // Паддинг 1 пиксель со всех сторон

Функции активации после свёртки

Свёрточный слой обычно дополняется нелинейной функцией активации:

  • tf.relu — классическая ReLU активация.
  • tf.sigmoid и tf.tanh — сигмоидные функции.
  • tf.leakyRelu — вариант ReLU с небольшой отрицательной наклонной.

Пример:

const conv = tf.conv2d(x, filter, 1, 'same');
const activated = tf.relu(conv);

Ручная реализация свёртки низкого уровня

Для глубокого понимания можно реализовать свёртку через базовые операции:

  1. Извлечение слайдов с помощью tf.image.extractPatches.
  2. Перемножение с ядром.
  3. Суммирование по нужным осям.
  4. Применение активации.

Пример:

const patches = tf.image.extractPatches({
  images: x,
  sizes: [1, 3, 3, 1],
  strides: [1, 1, 1, 1],
  rates: [1, 1, 1, 1],
  padding: 'same'
});
const reshaped = patches.reshape([1, 28, 28, 27]); // 3x3x3
const convManual = reshaped.mul(filter.reshape([1,1,1,27])).sum(-1);

Этот подход полезен для экспериментов и понимания внутренней механики свёртки.


Оптимизация и производительность

  • Использование tf.tidy освобождает память от промежуточных тензоров.
  • Компиляция функций с tf.function ускоряет выполнение.
  • Для больших батчей и изображений рекомендуется WebGL или Node.js с GPU.
tf.tidy(() => {
  const y = tf.conv2d(x, filter, 1, 'same');
  const z = tf.relu(y);
});

Применение свёрточных операций

  • Обработка изображений: выделение краёв, текстур и объектов.
  • Сигналы и временные ряды: свёртки по времени или частоте.
  • Сборка глубоких сетей: VGG, ResNet и MobileNet строятся на комбинации conv2d и depthwiseConv2d.

Эти базовые операции формируют основу любой работы с TensorFlow.js на низком уровне, обеспечивая гибкость в построении кастомных архитектур.