Отличный способ упростить работу с CNN с разными размерами ввода!

Сверточные нейронные сети (CNN) [1] широко распространены в сообществе машинного обучения (ML) и являются ключевым оружием в арсенале любого исследователя ML.

Однако работа с CNN может быть головной болью, когда вы не уверены в размере ввода (обычно изображения). Это тот случай, когда вы выбираете разрешение изображения или работаете с изображениями разных размеров, которые требуют обрезки / заполнения. Проблема возникает из-за того, что для полносвязных слоев требуется фиксированное количество нейронов, которое зависит от размера ввода (наряду с размерами и количеством используемых сверток).

Например, недавно я работал над проектом по обнаружению COVID-19 с использованием аудиоклипов, в которых люди дышат и кашляют. Следуя соглашению об обработке звука, я сначала преобразовал эти аудиофайлы в изображение, называемое лог-спектрограммой, которое показывает частоты звуковых волн в зависимости от времени аудиоклипа (см. Пример на Рис.1). Однако аудиоклипы имели разную длину, поэтому мне пришлось обрезать и / или дополнять некоторые сэмплы, что означает, что продолжительность аудиоклипа фактически стала гиперпараметром модели. Чтобы избежать серьезных головных болей и большого количества ручных операций, я разработал простой метод динамической регулировки размеров моей CNN. Читайте подробности, а также демонстрационную реализацию!

Почему CNN не могут обрабатывать данные разных размеров?

Рис. 1 иллюстрирует проблему использования CNN для разных входных размеров. Используя приведенный выше пример обнаружения звука COVID, если мы используем аудиоклип длиной 2 секунды и передаем его через сверточную секцию нашей CNN, тогда наш вывод представляет собой вектор длины 2. Это заставляет первый слой нашего полностью подключенного компонента иметь 2 нейрона. Если вместо этого мы используем клип 8s, это даст результат 8x1, требуя 8 нейронов в первом плотном слое. Поэтому регулировка размера ввода обычно требует ручной настройки размеров плотных слоев¹.

Решение с динамической регулировкой

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

На рис. 2 показана простая реализация CNN. Эта простая сеть настроена для изображений размером 14x14. После прохождения сверточных слоев выходной вектор имеет длину 48. Однако, если мы попробуем сеть с изображениями другого размера, скажем 28x28, сеть выйдет из строя во время прямого прохода. Строка 9 является основной причиной, поскольку она жестко запрограммирована на 48 входных нейронов, но это будет работать только для изображений размером 14x14. Решение - сделать строку 9 динамической, чтобы она соответствовала размеру ввода.

На рис. 3 показана динамическая реализация. Моя версия разделяет сверточные и плотные компоненты на родительский и дочерний классы. Этот метод сначала создает экземпляр сверточного компонента, чтобы затем мы могли запустить прямой проход в этом разделе сети и использовать выходную размерность для получения размеров, требуемых в полностью связном слое в theDynamicCNN. Это реализовано с помощью вспомогательного метода: get_dense_dim.

Используя этот метод, мы можем использовать изображения разного размера (например, 14x14 или 28x28) без необходимости настройки конфигурации сети. Это позволит вам использовать изображения разных размеров в развертке гиперпараметров, что поможет вам обучать лучшие модели.

Однако этот метод следует использовать с умом и, вероятно, только для относительно небольших изменений размера ввода. Сложность полностью связанного слоя линейна по отношению к входным нейронам, поэтому увеличение размера изображения замедлит вашу модель и сделает ее больше. Кроме того, было бы разумно отрегулировать размеры последующих линейных слоев, поскольку в противном случае увеличение размера ввода создаст один очень широкий линейный слой, что приведет к узкому месту в сети. Предлагаемое здесь альтернативное решение - использовать слой AdaptiveAveragePooling PyTorch с более подробной информацией об этом здесь.

Надеюсь, этот совет был интересен / полезен. Как всегда, любые мысли / комментарии / отзывы будут с благодарностью получены. Спасибо за чтение и удачного машинного обучения!

¹ В качестве альтернативы плотные слои в CNN могут быть реализованы как свертка 1x1. В этом случае проблема наличия разных размерностей будет проявляться в выходном слое, а не в сети, поэтому здесь в равной степени применима точка зрения этой статьи.

[1] Янн ЛеКун и Йошуа Бенжио. Сверточные сети для изображений, речи и временных рядов, стр. 255–258. MITPress, Кембридж, Массачусетс, США, 1998 г.