Skip connections (пропускные соединения) представляют собой архитектурный приём в нейронных сетях, позволяющий информации проходить через слои без прямого изменения её содержимого. В ConvNetJS их использование особенно актуально при построении глубоких сверточных сетей, где традиционные последовательные слои могут испытывать затухание градиента.
В глубоких сетях с большим числом слоев градиенты обратного распространения могут становиться крайне малыми, что препятствует эффективному обучению. Skip connections позволяют градиенту распространяться напрямую к более ранним слоям, уменьшая вероятность затухания и ускоряя сходимость сети.
Кроме того, пропускные соединения помогают сети учиться идентичному отображению между слоями. Если оптимальное преобразование ближе к идентичному, слой может просто передавать вход дальше, не мешая обучению.
ConvNetJS предоставляет базовые компоненты для построения нейросетей, включая FullyConnectedLayer, ConvLayer, PoolLayer. Прямой поддержки skip connections как готового слоя нет, поэтому их необходимо реализовывать вручную.
Простейший вариант выглядит так:
// Создание сети
var net = new convnetjs.Net();
net.addLayer(new convnetjs.Layer({type:'input', out_sx:28, out_sy:28, out_depth:1}));
net.addLayer(new convnetjs.Layer({type:'conv', sx:5, filters:8, stride:1, pad:2, activation:'relu'}));
net.addLayer(new convnetjs.Layer({type:'conv', sx:5, filters:8, stride:1, pad:2, activation:'relu'}));
Чтобы реализовать skip connection, необходимо вручную скопировать активации одного слоя и добавить их к выходу следующего слоя:
function forwardWithSkip(layer1, layer2) {
var out1 = layer1.forward();
var out2 = layer2.forward();
// Проверка совместимости размеров
if(out1.w.length !== out2.w.length) {
throw "Размеры слоёв не совпадают!";
}
// Суммирование выходов
for(var i=0; i<out1.w.length; i++) {
out2.w[i] += out1.w[i];
}
return out2;
}
Такой подход позволяет реализовать Residual Block, аналогичный блокам ResNet. Блок может состоять из двух или трёх слоев, между которыми выполняется операция суммирования входа и выхода:
var blockInput = convLayer1.forward();
var blockOutput = convLayer2.forward();
for(var i=0;i<blockOutput.w.length;i++){
blockOutput.w[i] += blockInput.w[i];
}
Для создания глубоких сетей с skip connections рекомендуется придерживаться следующих принципов:
Совпадение размеров: пропускной сигнал должен иметь те же размеры, что и выход слоя, с которым он складывается. Если размеры отличаются, используется проекция через 1x1 свертку.
Активация после суммирования: обычно после объединения пропускного сигнала с выходом слоя применяется активация ReLU, что обеспечивает нелинейность и стабильность обучения.
Повторяемость блоков: глубокая сеть строится из повторяющихся блоков с skip connections, что позволяет легко масштабировать архитектуру и повышает качество обучения.
Пример структуры блока в ConvNetJS:
var inputLayer = new convnetjs.Layer({type:'input', out_sx:28, out_sy:28, out_depth:16});
var conv1 = new convnetjs.Layer({type:'conv', sx:3, filters:16, stride:1, pad:1, activation:'relu'});
var conv2 = new convnetjs.Layer({type:'conv', sx:3, filters:16, stride:1, pad:1, activation:'relu'});
// Forward pass с skip connection
var skipOutput = forwardWithSkip(conv1, conv2);
Skip connections в ConvNetJS обеспечивают возможность создавать глубоко связанные нейросети без потери информации и с устойчивым обучением. Их ручная реализация требует контроля размерностей и порядка суммирования, но значительно повышает гибкость архитектур и качество моделей.