Визуализация карт активаций

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

Основные концепции

Активация слоя — это выходной тензор, получаемый после применения слоя к входным данным и функции активации. Для сверточных сетей это многомерный массив, где:

  • Первые два измерения соответствуют пространственным координатам (ширина и высота),
  • Третье измерение — количество фильтров (каналов),
  • Четвёртое измерение может обозначать размер батча (в случае одиночного изображения батч = 1).

Карты активаций отражают интенсивность реакции каждого фильтра на различные участки изображения. Яркие или насыщенные участки карты показывают, какие признаки сети оказались важными.

Получение активаций в TensorFlow.js

TensorFlow.js позволяет работать с активациями напрямую через модель и слои. Для этого используется метод model.execute или извлечение промежуточного слоя через tf.model({inputs, outputs}).

Пример:

import * as tf from '@tensorflow/tfjs';

// Загрузка модели
const model = await tf.loadLayersModel('model.json');

// Выбор промежуточного слоя по имени
const layerName = 'conv2d_1';
const intermediateLayerModel = tf.model({
  inputs: model.inputs,
  outputs: model.getLayer(layerName).output
});

// Преобразование изображения в тензор
const imgTensor = tf.browser.fromPixels(imageElement)
  .resizeNearestNeighbor([224, 224])
  .expandDims(0)
  .toFloat()
  .div(tf.scalar(255));

// Получение активаций
const activations = intermediateLayerModel.predict(imgTensor);

В результате переменная activations будет содержать тензор размером [1, height, width, filters]. Для визуализации его нужно преобразовать в удобный формат.

Преобразование активаций в изображение

Для визуализации каждой карты активации используют нормализацию значений и преобразование канала в изображение. Часто применяется мини-батч по фильтрам, например:

const activationData = activations.squeeze().arraySync(); // shape: [height, width, filters]
const numFilters = activationData[0][0].length;

for (let i = 0; i < numFilters; i++) {
  const filter = activationData.map(row => row.map(pixel => pixel[i]));
  const normalized = normalizeArray(filter); // функция нормализации в диапазон [0, 255]
  renderCanvas(normalized, `filter-${i}`);   // функция отрисовки на canvas
}

Нормализация часто выполняется через:

function normalizeArray(arr) {
  const flat = arr.flat();
  const min = Math.min(...flat);
  const max = Math.max(...flat);
  return arr.map(row => row.map(value => ((value - min) / (max - min)) * 255));
}

Визуализация нескольких фильтров одновременно

Чтобы сравнивать активируемые признаки, удобно отображать карты фильтров в виде сетки:

function renderGrid(activationArray, gridSize = 8) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const cellSize = 64; // размер каждой карты в пикселях
  canvas.width = gridSize * cellSize;
  canvas.height = gridSize * cellSize;

  for (let i = 0; i < Math.min(gridSize * gridSize, activationArray.length); i++) {
    const row = Math.floor(i / gridSize);
    const col = i % gridSize;
    const imageData = ctx.createImageData(cellSize, cellSize);
    const normalized = resizeArray(activationArray[i], cellSize, cellSize); 
    for (let y = 0; y < cellSize; y++) {
      for (let x = 0; x < cellSize; x++) {
        const index = (y * cellSize + x) * 4;
        const value = normalized[y][x];
        imageData.data[index] = value;
        imageData.data[index + 1] = value;
        imageData.data[index + 2] = value;
        imageData.data[index + 3] = 255;
      }
    }
    ctx.putImageData(imageData, col * cellSize, row * cellSize);
  }

  document.body.appendChild(canvas);
}

Функция resizeArray выполняет интерполяцию значений до нужного размера, сохраняя пропорции визуализации.

Особенности работы с разными типами слоев

  • Сверточные слои: визуализируются как отдельные карты активаций для каждого фильтра.
  • Пулинговые слои: карты активаций уменьшаются в пространственном разрешении, но сохраняют число каналов.
  • Полносвязные слои: для визуализации используют графики активаций по каждому нейрону, поскольку пространственные координаты теряются.

Практическая ценность

Визуализация активаций помогает:

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

Использование TensorFlow.js позволяет выполнять эти операции непосредственно в браузере, что удобно для интерактивных экспериментов и быстрого прототипирования.