ConvNetJS — это чисто JavaScript-библиотека для построения и обучения нейронных сетей, включая сверточные нейронные сети (CNN). Одной из важных возможностей при работе со сверточными сетями является визуализация фильтров сверток. Эта визуализация позволяет понять, какие признаки сети обнаруживают на ранних и глубоких слоях.
Сверточный слой состоит из набора фильтров (ядр свертки), каждый из которых представлен матрицей весов. При применении свертки к входному изображению фильтры извлекают локальные признаки — края, текстуры или более сложные паттерны на последующих слоях.
В ConvNetJS фильтры создаются объектами типа Vol с
параметрами:
sx — ширина фильтраsy — высота фильтраdepth — количество каналов (например, 3 для RGB)w — массив весов фильтраdw — массив градиентов весов (используется при
обучении)Для визуализации фильтров необходимо извлечь веса из сверточного
слоя. Если сверточный слой conv определён в сети:
let layer = net.layers[convIndex]; // convIndex — индекс сверточного слоя
let filters = layer.filters; // массив фильтров
Каждый фильтр хранится как объект Vol, содержащий
линейный массив весов w. Для преобразования его в двумерное
изображение используется функция Vol.toNumbers() или
простая итерация по индексам.
Вес каждого фильтра можно интерпретировать как пиксели. Для одноцветного (grayscale) изображения:
function filterToImage(filter) {
let size = Math.sqrt(filter.w.length);
let canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
let ctx = canvas.getContext('2d');
let imgData = ctx.createImageData(size, size);
for (let i = 0; i < filter.w.length; i++) {
let value = Math.floor((filter.w[i] - Math.min(...filter.w)) / (Math.max(...filter.w) - Math.min(...filter.w)) * 255);
imgData.data[i * 4 + 0] = value;
imgData.data[i * 4 + 1] = value;
imgData.data[i * 4 + 2] = value;
imgData.data[i * 4 + 3] = 255;
}
ctx.putImageData(imgData, 0, 0);
return canvas;
}
В этом коде выполняется нормализация весов фильтра к диапазону 0–255, что позволяет корректно отобразить как положительные, так и отрицательные значения.
Для фильтров с глубиной больше 1 (например, RGB) каждый канал визуализируется отдельно или комбинируется:
function filterToRGBImage(filter) {
let size = filter.sx;
let canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
let ctx = canvas.getContext('2d');
let imgData = ctx.createImageData(size, size);
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
let idx = y * size + x;
for (let c = 0; c < 3; c++) { // R, G, B
let val = filter.w[idx + c * size * size];
val = Math.floor((val - Math.min(...filter.w)) / (Math.max(...filter.w) - Math.min(...filter.w)) * 255);
imgData.data[(idx) * 4 + c] = val;
}
imgData.data[idx * 4 + 3] = 255;
}
}
ctx.putImageData(imgData, 0, 0);
return canvas;
}
Этот метод полезен для первых слоев сети, где фильтры имеют три канала. В более глубоких слоях визуализация отдельных каналов позволяет выявлять сложные текстуры и паттерны.
Для наглядного представления фильтров удобно создавать сетку изображений:
function drawFilterGrid(filters, containerId, perRow = 8) {
let container = document.getElementById(containerId);
container.innerHTML = '';
filters.forEach((filter, index) => {
let canvas = filterToImage(filter);
canvas.style.margin = '2px';
container.appendChild(canvas);
});
}
Можно менять filterToImage на
filterToRGBImage для цветных фильтров. Параметр
perRow позволяет задавать количество фильтров в одной
строке, формируя аккуратную визуальную сетку.
Кроме фильтров, полезно визуализировать активации
слоев, показывая, какие области изображения вызывают отклик
сети. Активации извлекаются через объект Vol:
let activations = layer.out_act; // Vol активаций
Каждое поле activations.w соответствует отклику нейрона
на входное изображение. Аналогично фильтрам, активации можно
нормализовать и отобразить в виде изображения для каждого канала.
При большом количестве фильтров рендеринг на канвасе может замедлять интерфейс. Рекомендуется:
Эти подходы позволяют создавать динамическую и интерактивную визуализацию даже в браузере с ограниченными ресурсами.