CodeSide DataSide

Нейронные сети

Свёрточные нейронные сети: взгляд изнутри

Автор: rustam1208 .

Свёрточные нейронные сети: взгляд изнутри

Введение

Свёрточные нейронные сети (СНС, CNN) очень похожи на обычные нейронные сети: они также построены на основе нейронов, которые обладают изменяющимся весом и смещениями. Каждый нейрон получает некоторые входные данные, выполняет скалярное произведение информации и в отдельных ситуациях сопровождает это нелинейностью. Как и в случае с обычными нейронными сетями, вся CNN выражает одну дифференцируемую функцию взноса (эффективный взнос): с одной стороны это необработанные пиксели изображения, с другой — вывод класса или группы вероятных классов, характеризующих картинку. Здесь также присутствует функция потери на последнем (полностью подключенном) слое, а все «фишки» и хитрости, разработанные и изученные в течение знакомства с нейронными сетями, остаются справедливыми при работе с CNN.

Но в чем же тогда отличия? Архитектура свёрточных нейросетей делает явное предположение вида «входные данные есть изображения», что позволяет закодировать определенные свойства под архитектуру. Благодаря этой особенности, предварительное объявление можно реализовать более эффективно, уменьшая при этом количество параметров в сети.

Подробное знакомство с архитектурой CNN

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

Обычные нейронные сети плохо масштабируются в случае с изображениями больших размеров. Так, в системе компьютерного зрения CIFAR-10, картинки имеют размер [32×32×3] (32 — ширина, 32 — высота, 3 — цветовые каналы), поэтому один полностью подключенный нейрон в первом скрытом слое обычной нейронной сети обладает весом 3 072 (32*32*3). Кажется, что это значение можно изменять, но полносвязная структура не масштабируется для больших изображений. Картинка с разрешением посолиднее, например, [200×200×3], приведет к тому, что полностью подключенный нейрон будет весить 120 000. Кроме того, мы почти наверняка хотели бы иметь несколько таких нейронов, что привело бы к добавлению параметров. Полная связность — это расточительство, и огромное количество параметров может быстро привести к переобучению.

Свёрточные нейронные сети пользуются тем, что вводные данные состоят из изображений, и они ограничивают построение сети более разумным путем. В отличие от обычной нейронной сети, слои CNN состоят из нейронов, расположенных в 3-х измерениях: ширине, высоте и глубине, т. е. измерениях, которые формируют объем. Например, изображения на входе CIFAR-10 являются входными активационными объемами, а объем сформирован измерениями 32×32×3. Как мы скоро увидим, нейроны будут подключены только к небольшой области слоя перед этим участком. Кроме того, результирующий выходной слой для данной системы компьютерного зрения составит 1x1x10, поскольку к концу построения CNN мы преобразуем полное изображение в единый вектор оценок класса, расположенных по измерению глубины. Ниже приводится визуализация описанного процесса.

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 1. - Обычная нейронная сеть

Рисунок 1. — Обычная нейронная сеть

Рисунок 2. - Свёрточная нейронная сеть

Рисунок 2. — Свёрточная нейронная сеть

Слева: Расположение нейронов в обычной трехслойной нейросети. Справа: Нейроны свёрточной нейронной сети располагаются в 3-х измерениях, как это показано на одном из слоев. Каждый слой CNN преобразует входной 3D-объем в выходной активационный 3D-объем нейронов. В данном примере красный входной слой содержит изображение, поэтому его ширина и высота определяется размерами картинки, а глубина будет равна 3 (красный, зеленый, синий каналы).

---------------------------------------------------------------------------------------------------------------------------------------------------

Итого: Основу свёрточных нейросетей составляют слои. Каждый слой характеризуется простым API: он преобразует входные данные в виде 3D-объема в выходной 3D-объем с некоторой дифференцируемой функцией, которая может иметь или не иметь параметры.

Какие слои используются в CNN?

Как уже было сказано выше, схематично CNN — это последовательность слоев. Каждый слой преобразует один активационный объем в другой с помощью дифференцируемой функции. Для организации свёрточной нейронной сети применяется 3 основных слоя:

  1. свёртки,
  2. пулинга (иначе подвыборки или субдискретизации),
  3. полносвязный слой.

Эти слои используются с целью построения полной архитектуры CNN.

Далее мы рассмотрим организацию CNN более подробно, а простым примером свёрточной нейросети в контексте классификации системы распознавания изображений CIFAR-10 может послужить архитектура [INPUT — CONV — RELU — POOL — FC].

  • В INPUT (входные данные) [32×32×3] содержатся исходная информация об изображении (в данном случае 32 — ширина, 32 — высота, 3 — цветовые каналы R, G, B).
  • Слой CONV (слой свёртки) умножает значения фильтра на исходные значения пикселей изображения (поэлементное умножение), после чего все эти умножения суммируются. Каждая уникальная позиция введенного изображения производит число. Пример: Если используется 12 фильтров, объем будет равен 32*32*12 [32×32×12].
Сверточный слой фильтр

Рисунок 3. — Визуализация свёртки входного изображения фильтром 5×5 на активационной карте

  • Слой RELU (блок линейной ректификации) применяет поэлементную функцию активации вроде f (x) = max(0,x), устанавливая нулевой порог. Иными словами, RELU выполняет следующие действия: если x > 0, то объем остается прежним ([32×32×12]), а если x < 0, то осекаются ненужные детали в канале и путем замены на 0.
  • Слой POOL (слой пулинга) выполняет операцию по понижающей дискретизации пространственных размеров (ширина и высота), в результате чего объем может сократиться до [16×16×12]. То есть на этом этапе выполняется нелинейное уплотнение карты признаков. Логика работы такова: если на предыдущей операции свертки уже были выявлены некоторые признаки, то для дальнейшей обработки настолько подробное изображение уже не нужно, и оно уплотняется до менее подробной картинки.
  • Слой FC (полносвязный слой) выводит N-мерный вектор (N — число классов) для определения нужного класса. Работа организуется путем обращения к выходу предыдущего слоя (карте признаков) и определения свойств, которые наиболее характерны для определенного класса.
Рисунок 4. - Полная свёрточная нейронная сеть

Рисунок 4. — Полная свёрточная нейронная сеть

Именно таким образом CNN слой за слоем трансформирует исходное изображение, начиная с исходных значений пикселов и заканчивая определением класса. Обратите внимание, что слои не обязательного должны содержать параметры. В частности, слой свёртки и полносвязный слой выполняют преобразования, которые являются не только функцией от входного активационного объема, но и параметров (веса и смещения нейронов). С другой стороны, блок линейной ректификации и слой пулинга реализуют фиксированную функцию. Параметры в слоях CONV и FC будут обучаться с помощью градиентного спуска, поэтому определение класса свёрточной нейросетью зависит от меток в обучающем наборе для каждого изображения.

В итоге:

  1. В простейшем случае архитектура CNN — это набор слоев, которые преобразуют образ изображения в выходной образ (например, определение класса).
  2. Каждый слой отвечает за определенный этап процесса обработки изображения (слой свёртки, линейной ректификации, пулинга и полносвязный слой самые популярные на сегодняшний день).
  3. Каждый слой получает на входе объемную 3D информацию и трансформирует с сохранением 3D-объема с помощью дифференцируемой функции.
  4. Слой может не иметь параметров (CONV и FC имеют, RELU и POOL — нет).
  5. Слой может не иметь дополнительные гиперпараметры (например, CONV, FC и POOL имеют, RELU — нет).

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 5. - Обработка изображения слоями CNN

Рисунок 5. — Обработка изображения слоями CNN

Как показано на Рисунке 5, исходный объем содержит необработанные пиксели (слева), а окончательный объем — определенный класс (справа). Каждый активационный объем в ходе обработки изображения показан в виде столбца. Когда визуализировать 3D-объем становится тяжело, производится выкладка объема каждого слоя в ряд. Объем последнего слоя содержит вероятностную оценку для каждого возможного класса, причем FC визуализирует классы в отсортированном порядке. Архитектура, описанная здесь, представляет собой уменьшенную VGG (Visual Geometry Group) сеть, о которой речь пойдет далее. Рабочая демо-версия представлена здесь.

---------------------------------------------------------------------------------------------------------------------------------------------------

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

Слой свёртки

Слой свёртки — это основополагающий слой CNN, который выполняет большинство тяжелой работы.

Обзор и логика работы без учета «мозговых» способностей

Предположим, что слой CONV работает без «мозговой» или нейронной подоплеки. Параметры слоя свёртки состоят из набора обучающихся фильтров. Каждый фильтр имеет малые пространственные габариты (ширину и высоту), но проходит по всей глубине объема ввода. Например, стандартный фильтр первого слоя свёрточной нейронной сети может быть размера [5x5x3]. Во время прохода вперед, мы проскальзываем (точнее, скручиваем) каждый фильтр по ширине и высоте входных данных и вычисляем скалярное произведение между записями фильтра и входом в любое положение. По мере прохождения фильтра по ширине и высоте изображения, мы составляем 2-мерную активационную карту, которая предоставляет отклики этого фильтра на каждой пространственной позиции. Сеть выучивает фильтры, активирующиеся при обнаружении некоторой визуальной особенности. Это может быть грань некоторой направленности, пятнистость конкретного цвета на первом слое или кольцеобразные узоры на более высоких уровнях сети. Теперь мы будем работать с целым набором фильтров в каждом слое свёртки, и каждый из них будет формировать отдельную 2-мерную активационную карту. Мы будем складывать эти активационные карты вдоль измерения «глубина» и формировать выходной объем.

«Мозговая» точка зрения

Если вы привыкли проводить аналогии с нейронами, тогда каждую запись в выходном объеме можно интерпретировать как выходной нейрон, который смотрит только на небольшой участок входного объема и пространственно делит параметры со всеми нейронами слева и справа (поскольку они являются результатом применения такого же фильтра). Теперь давайте обсудим детали связей между нейронами, их расположение в пространстве и модель разделения параметров.

Локальная связность

Когда речь идет о работе с входной информацией с высокой размерностью, установка связи между нейронами и всеми нейронами с прежним объемом является нецелесообразной. Вместо этого мы будем подключать каждый нейрон только к локальной области входного объема. Пространственная протяженность этой связи является гиперпараметром и называется рецептивым полем (полем восприимчивости). Легко догадаться, что площадь поля восприимчивости равна площади фильтра. Пространственная протяженность вдоль оси глубины всегда эквивалента глубине входного объема. Следует еще раз подчеркнуть асимметрию в том, как мы рассматриваем пространственные измерения (ширину и высоту), а как — глубину: соединения являются локальными по ширине и высоте, но всегда проходят через всю глубину входного объема.

Пример 1. Предположим, что картинка на входе имеет размер [32×32×3] (например, RGB-изображение CIFAR-10). Если рецептивное поле (размер фильтра) равно 5×5, тогда каждый нейрон в слое свёртки будет иметь вес в пределах [5x5x3] входного объема, что в итоге даст 5*5*3=75 (+1 параметр смещения). Заметьте, что пространственная протяженность вдоль оси глубины должна быть равна 3: тогда есть гарантия математической верности.

Пример 2. Пускай теперь входное изображение имеет размер [16×16×20]. Тогда, если мы используем поле восприимчивости 3×3, каждый нейрон в слое свёртки будет иметь в сумме 180 (3*3*20) соединений с объемом на входе. Снова обращаем ваше внимание на то, что связность является локальной по ширине и высоте (здесь — 3×3), но проходит через всю глубину ввода (20).

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 6. - Соединение нейронов слоя свёртки с локальной входной областью (частью входного изображения)

Рисунок 6. — Соединение нейронов слоя свёртки с локальной входной областью (частью входного
изображения)

Рисунок 7. - Математические вычисления нейронов

Рисунок 7. — Математические вычисления нейронов

Слева: Пример входного объема (красный прямоугольник, параметры [32×32×3], изображение CIFAR-10) и предположительный объем нейронов в первом слое свёрточной нейронной сети. Каждый нейрон в свёрточном слое соединен только с локальной входной областью, где пространственная протяженность определяется шириной и высотой, но нейрон проходит через всю глубину, т. е. охватывает все цветовые каналы. Обратите внимание, что существует несколько нейронов (здесь — 5), проходящих через всю глубину и охватывающих одну область на входе (рассмотрение глубины столбцов приводится ниже). Справа: Нейроны из раздела обычных нейросетей остаются неизменными: они по-прежнему вычисляют скалярное произведение их весов и входных данных с последующей нелинейностью, но их подключение ограничивается локальными пространственными измерениями.

---------------------------------------------------------------------------------------------------------------------------------------------------

Пространственное расположение

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

  1. Начнем с первого гиперпараметра выходного объема — глубины. Он эквивалентен числу фильтров, которые мы бы хотели использовать; каждый из фильтров обучается нахождению различных данных на входе. Например, первый свёрточный слой в качестве входной информации берет необработанное изображение, после различные нейроны, располагающиеся вдоль глубины, могут активироваться в случае наличия, например, сгустков определенного цвета. Будем называть множество нейронов, которые «смотрят» на один участок входного объема, столбцом глубины (некоторые предпочитают термин «волокно»).
  2. Во-вторых, следует указать шаг, с которым фильтр выполняет проход. Когда шаг равен 1, то мы за один раз перемещаем фильтры на 1 пиксель. Когда шаг равен 2 (иногда бывает 3, но это редко используется на практике), фильтры «перепрыгивают» через 2 точки за раз при каждом обращении к ним. Это позволит вырабатывать меньшие выходные объемы пространственных измерений.
  3. Как мы скоро увидим, иногда бывает удобно окружать границу входного изображения нулями. Размер этого дополнения нулями и есть гиперпараметром. Ключевой особенностью дополнения нулями является то, что оно позволяет контролировать пространственный размер выходных объемов (чаще всего мы будем использовать данное свойство, чтобы сохранить пространственный размер входной информации, т. е. с целью сохранения входных и выходных значений высоты и ширины одинаковыми).

Пространственный размер выходного объема можно вычислить как функцию от входного объема (W), размера рецептивного поля нейронов свёрточного слоя (F), шага, с которым они перемещаются (S), и количества заполнения нулями на границе входной картинки (P). Вы можете убедиться, что формула (W−F+2P)/S+1 для подсчета количества «подходящих» нейронов является правильной. Например, для входного объема 7×7 и фильтра 3×3 с шагом 1 и дополнением 0, на выходе мы получим объем 5×5. С шагом 2 выходное значение было бы равно 3×3. Давайте посмотрим на еще один графический пример.

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 8. - Пространственное расположение нейронов

Рисунок 8. — Пространственное расположение нейронов

Иллюстрация пространственного расположения нейронов. В этом примере есть только одно пространственное измерение (ось x), один нейрон с рецептивным полем размера F=3, входной размер W=5 и дополнение нулями P=1. Слева: Нейрон, протянутый вдоль входного объема с шагом S=1, выводит выходной размер (5−3+1)/1+1 = 5. Справа: Нейрон, использующий шаг S=2, обеспечивает выходной размер (5−3+1)/2+1 = 3. Обратите внимание, что шаг S=3 не может быть использован, поскольку он не сможет аккуратно покрыть весь объем. С точки зрения арифметики это определяется так: (5−3+2) = 4 не делится на 3 без остатка. Веса нейронов в данном примере — [1,0,-1] (показано справа на Рисунке 9), поэтому их смещение равно нулю. Эти веса являются общими для всех желтых нейронов (смотрите «Совместное использование параметров» ниже).

---------------------------------------------------------------------------------------------------------------------------------------------------

Применение дополнения нулями. В приведенном выше примере, входная размерность была равна 5; размер на выходе остался таким же — 5. Это возможно благодаря тому, что размер рецептивных полей был равен 3, а также мы использовали дополнение нулями, равное 1. Если бы дополнение нулями отсутствовало, тогда пространственная размерность выходного объема была вы равна 3, поскольку именно 3 нейрона смогли бы идеально пройти по всему исходному объему. В общем случае, установка дополнения нулями P = (F-1)/2 при шаге S=1 гарантирует, что входной и выходной объемы будут иметь одинаковый пространственный размер. Чаще всего дополнение нулями используется как раз для сохранения исходных показателей ширины и высоты. Причины такого подхода мы рассмотрим более детально в ходе дальнейшего изучения архитектуры CNN.

Ограничения на шаги. Отметим еще раз, что пространственное расположение гиперпараметров имеет взаимные ограничения. Например, когда входной объем имеет размер W=10, дополнение нулями отсутствует (P=0), а размер фильтра F=3, тогда использование шага S=2 будет невозможно, поскольку (W-F+2P)/S+1 = (10−3+0)/2+1 = 4.5, т. е. получается равенство дробному число, указывающему, что нейроны как бы «не вписываются» и не могут расположиться симметрично вдоль входного объема. Таким образом, установка этих гиперпараметров считается неверной, и библиотека ConvNet может создать исключение, произвести дополнение нулями, обрезать входные данные или выполнить другую операцию для подгонки корректных значений. Как будет показано в разделе «Архитектуры свёрточных нейронных сетей», определение размеров CNN и всех измерений в частности, может стать настоящей проблемой, решение которой значительно облегчается путем использования нулевых дополнений и некоторых принципов проектирования.

Практический пример. Архитектура Крижевского и других, которая выиграла соревнование ImageNet в 2012 году, принимала изображения размера [227×227×3]. На первом свёрточном слое она использовала нейроны с рецептивным полем размера F=11, шагом S=4, а дополнение нулями отсутствовало (P=0). Поскольку (227−11)/4+1 = 55 и слой свёртки имел глубину K=96, выходной объем был размера [55×55×96]. Каждый из 55*55*96 нейронов в этом объеме был соединен с областью входного объема размера [11×11×3]. Кроме того, все 96 нейронов в каждом волокне соединены с той же входной областью размера [11×11×3], но с разными весами. Интересно, что согласно официальной документации, входные изображения были размера 224×224, что, очевидно, неправильно, поскольку результат выполнения всех операций в выражении (224−11)/4+1 не даст целое число. Это смутило многих людей, которые так или иначе затрагивали CNN, и никто до сих пор не знает наверняка, что произошло. Можно предположить, что разработчик использовал дополнение нулями 3 дополнительных пикселей, о чем не упомянул в бумагах.

Совместное использование параметров

Совместное использование параметров используется в слоях свёртки с целью контроля количества параметров. Используя приведенный выше практический пример, замечаем, что в первом свёрточном слое есть 55*55*96 = 290 400 нейронов, и каждый имеет 11*11*3 = 363 весов и 1 смещение. В обще сложности это дает 290400 * 364 = 105 705 600 параметров в первом слое свёрточной нейронной сети. Очевидно, что это очень большое число.

Оказывается, мы можем значительно уменьшить количество параметров путем следующего предположения: если одно свойство подходит для вычислений в некотором пространственном положении (x, y), то это же свойство должно быть полезно при работе на площадке (x2,y2). Другими словами, обозначая один 2-мерный глубинный срез как срез глубины (например, объем размера [55×55×96] имеет 96 срезов глубины, каждый размером [55×55]), мы сдерживаем нейроны каждого среза, чтобы использовать одни и те же веса и смещения. Благодаря схеме разделения параметров, первый слой свёртки в нашем примере теперь будет иметь всего 96 уникальных наборов весов (по одному для каждого среза глубины), что в общей сложности дает 96*11*11*3 = 34 848 уникальных весов или 24 944 параметров (+96 смещений). Все 55*55 нейронов в каждом глубинном срезе теперь будут использовать одинаковые параметры. На практике во время метода обратного распространения ошибки, каждый нейрон в объеме будет вычислять градиент для его веса, но эти градиенты будут добавлены вдоль каждого среза глубины, и обновлять будут только один набор весов на одном срезе. Обратите внимание: если все нейроны в одном глубинном срезе используют один и тот же весовой вектор, то прямой проход слоя свёртки в каждом глубине среза может быть посчитан как свёртка весов нейрона с объемом входной информации (отсюда и название — свёрточный слой). Именно поэтому он является общим для обозначения набора весов в качестве фильтра (ядра), которое скручено со входом.

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 9. - Фильтры, исследуемые Крижевским и др.

Рисунок 9. — Фильтры, исследуемые Крижевским и др.

Примеры фильтров, исследуемых Крижевским и остальными. Каждый из представленных здесь 96 фильтров имеет размер [11×11×3], и каждый использует совместно 55*55 нейронов в одном срезе глубины. Заметьте, что совместное использование параметров базируется на логическом предположении: если обнаружение горизонтального ребра важно в определенном месте изображения, оно должно быть полезно и интуитивно понятно на других участках картинки в связи с поступательно-инвариантной структурой изображения. Необходимость переучиваться, чтобы обнаруживать горизонтальное ребро в каждом из 55*55 различных мест выходного объема свёрточного слоя, отсутствует.

---------------------------------------------------------------------------------------------------------------------------------------------------

Иногда совместное использование параметров лишено смысла. Это касается случая, когда входное изображение, подающееся в CNN, имеет специфическую центрированную структуру, в которой ожидается, к примеру, на противоположных сторонах изображения должно быть произведено изучение совершенно разных свойств. Яркий практический пример: входные данные — лица, которые были центрированы на изображении. Логично ожидать, что свойства, касающиеся глаз, и свойства, касающиеся волос, могут и должны быть изучены в разных точках пространства. В этом случае принято отходить от схемы совместного использования параметров, а вместо нее используют локально соединенный слой.

Примеры с NumPy

Для того чтобы конкретизировать все вышеизложенное, выразим те же идеи в виде кода на конкретном примере. Предположим, что наши входные данные — это NumPy-массив X. Тогда:

  • столбец глубины (волокно) в положении (x, y) будет активацией X[x, y:].
  • срез глубины, эквивалентный активационной карте на глубине d, будет активацией X[, d].

Предположим, что входной объем X (это NumPy-массив) имеет форму X.shape: (11,11,4). Далее предполагаем, что дополнение нулями не используется (P=0), размер фильтра F=5, а шаг равен S=2. Таким образом, пространственный размер выходного объема будет (11−5)/2+1 = 4, т. е. значение высоты и ширины устанавливаются равные четырем. Активационная карта в выходном объеме (назовем ее V) будет выглядеть следующим образом (в данном примере вычисляется только несколько элементов):

  • V[0,0,0] = np. sum (X[:5:5:] * W0) + b0
  • V[1,0,0] = np. sum (X[2:7:5:] * W0) + b0
  • V[2,0,0] = np. sum (X[4:9:5:] * W0) + b0
  • V[3,0,0] = np. sum (X[6:11:5:] * W0) + b0

Напоминаем, что в NumPy операция * обозначает поэлементное умножение массивов. Обратите внимание, что весовой вектор W0 является весовым вектором этого нейрона, а b0 — это смещение. Здесь значение W0 вытекает из формы W0.shape: (5,5,4), поскольку размер фильтра равен 5, а глубина входного объема — 4. В каждой точке производится вычиление скалярного произведение так же, как это было в обычных нейронных сетях. Также мы видим, что применяется тот же вес и смещение (за счет совместного использования параметров), а измерения по ширине увеличиваются с шагом 2. Чтобы построить вторую активационную карту в выходном объеме, нам следовало бы:

  • V[0,0,1] = np. sum (X[:5:5:] * W1) + b1
  • V[1,0,1] = np. sum (X[2:7:5:] * W1) + b1
  • V[2,0,1] = np. sum (X[4:9:5:] * W1) + b1
  • V[3,0,1] = np. sum (X[6:11:5:] * W1) + b1
  • V[0,1,1] = np. sum (X[:5,2:7:] * W1) + b1 (прохождение по оси y)
  • V[2,3,1] = np. sum (X[4:9,6:11:] * W1) + b1 (прохождение по обеим осям)

Поскольку мы вычисляем вторую активационную карту и другой набор параметров (W1) сейчас используется, здесь производится индексация по второму измерению по глубине V (на индексе 1). В приведенном выше примере мы, с целью краткости, опустили некоторые операции, которые слой свёртки будет выполнять, чтобы заполнить оставшиеся части выходного массива V. Напомним, что активационные карты часто следуют поэлементно благодаря функциям активации (например, ReLu), но это здесь не показано.

Резюме по свёрточному слою

Подбиваем итоги по слою свёртки:

  • Принимает данные размера W1xH1xD1
  • Требует 4 гиперпараметра:
  1. количество фильтров K,
  2. их пространственную протяженность F,
  3. шаг S,
  4. количественное выражение дополнения нулями P.
  • Создает объем размера W2xH2xD2, где:
  1. W2=(W1F+2P)/S+1
  2. H2=(H1F+2P)/S+1 (ширина и высота вычисляются в равной степени)
  3. D2=K
  • С помощью совместного использования параметров, вводится FFD1 весов на фильтр, что в общей сложности дает (FFD1)K весов и K смещений.
  • В выходном объеме d-й срез глубины (размера W2xH2) есть результат выполнения корректной свёртки d-го фильтра по входному объему с шагом S с последующей поправкой d-го смещения.

Наиболее распространенные значения гиперпараметров равны: F=3, S=1, P=1. Тем не менее, существуют общие указания и эмпирические правила, которые обосновывают конкретные значения гиперпараметров. Подробнее об этом читайте в разделе «Архитектуры свёрточных нейронных сетей».

Демо-свёртка

Ниже приводится работающая демо-версия сверточного слоя. Поскольку трехмерную информацию тяжело визуализировать, все объемы (входной объем (синий), веса объемов (красный), выходной объем (зеленый)) визуализированы с каждым срезом глубины, расположенным в строках. Входной объем имеет размер W1=5, H1=5, D1=3, параметры свёрточного слоя — K=2, F=3, S=2, P=1. То есть мы имеем 2 фильтра размера 3×3, и они работают с шагом 2. Отсюда пространственный размер выходного объема составляет (5−3+2)/2+1 = 3. Кроме того, дополнение нулями, равное P=1, применяется ко входному объему, делая его внешнюю границу нулевой. Приведенная ниже визуализация перебирает выходные активации (зеленый) и демонстрирует, что каждый элемент вычисляется путем поэлементного умножения выходных данных (синий) и фильтра (красный), последующего суммирования значений и дальнейшей корректировки результатов по смещению.

Реализация в виде умножения матриц

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

  1. Локальные области входного изображения растягиваются в столбцы в ходе процесса, который обычно называют im2col. Например, если на вход подается объем размером [227×227×3], который должен быть свёрнут с фильтрами [11×11×3] при шаге 4, необходимо взять блоки пикселов размера [11×11×3] на входе и растянуть каждый блок в вектор-столбец размером 11*11*3 = 363. Повторение этого процесса дает (227−11)/4+1 = 55 мест вдоль измерений ширины и высоты, что приводит к выводу матрицы X_col размера [363×3025], где каждый столбец представляет собой вытянутое рецептивное поле (в общей сложности есть 55*55 = 3 025 рецептивных полей).
  2. Веса слоя свёртки аналогично растянуты в строки. Например, если есть 96 фильтров размера [11×11×3], то это даст матрицу W_row размера [96×363].
  3. Результат выполнения свёртки теперь эквивалентен результату выполнению одной большой матрицы умножения np.dot (W_row, X_col), которая вычисляет скалярное произведение между каждым фильтром и каждым рецептивным полем. В нашем примере результатом этой операции будет [96×3025], что дает на выходе скалярное произведение каждого фильтра в каждой локации.
  4. Результат должен быть приведен к исходному виду относительно измерений: [55×55×96].

Такой подход имеет весомый недостаток: ввиду многократного повторения некоторых значений в матрице X_col, память не всегда используется целесообразно. С другой стороны, главное преимущество заключается в том, что существует множество эффективных умножения матриц, которые можно использовать в своих интересах (практикуется в BLAS API). Также идея функционирования im2col может быть использована для реализации пулинга, о котором речь пойдет далее.

Метод обратного распространения ошибки

Обратный проход для операции свёртки (как для данных, так и для весов) — это также свёртка, только с пространственно-перевернутыми фильтрами. Это легко выводится на 1-мерном игровом примере.

Свёртка 1x1

В качестве отступления скажем, что в ряде работ (например, Network in Network) была использована свёртка формата 1×1. Некоторые люди приходят в замешательство, когда видят такие свёртки, особенно когда они поступают от обработки фоновых сигналов. Обычно сигналы имеют 2 измерения, поэтому свёртки 1×1 бессмысленны (это просто точечное масштабирование). Однако в CNN это не так, ведь нужно помнить, что мы работаем с 3-мерными данными, и что фильтры всегда проходят по всему размеру по глубине входного объема. Так, если на входе имеем [32×32×3], то свёртки 1×1 будут эффективно выполнять 3-мерное скалярное произведение (поскольку входная глубина состоит из 3 каналов).

Расширенные свёртки

Новая разработка (смотрите статью Фишера Ю и Владлена Колтуна) открыла еще один гиперпараметр слоя свёртки — дилатацию (расширение). Недавно мы обсуждали фильтры свёрточного слоя, которые являются смежными. Тем не менее, могут быть фильтры, имеющие между каждой ячейкой пробелы. Эти проблемы называются расширениями. Пример: в одном измерении фильтра w размера 3 над входом x будет проводиться операция w[0]*x[0] + w[1]*x[1] + w[2]*x[2]. Это дилатация нуля. Для дилатации 1, будут выполнены следующие вычисления: w[0]*x[0] + w[1]*x[2] + w[2]*x[4]. Другими словами, существует разрыв 1. Использования сочетания с 0-расшриненными фильтрами может быть полезно в отдельных настройках, поскольку это позволяет объединить пространственную информацию входного объема с использованием меньшего количества слоев. Например, если вы расположите два слоя свёртки размером 3×3 наверху каждого из фильтров, будет видно, что нейроны 2-го слоя являются функцией области входа 5×5 (можно сказать, что эффективное рецептивное поле этих нейронов — 5×5). Если мы будем использовать расширенные свёртки, то это эффективное рецептивное поле будет расти гораздо быстрее.

Слой пулинга

В архитектуре CNN обычной практикой является вставка слоя пулинга (подвыборки) между последовательностями свёрточных слоев. Его функция состоит в постепенном уменьшении пространственные габариты изображения с целью уменьшения количества параметров и вычислений в сети, а также контроля переобучения. Слой пулинга работает независимо от среза глубины входных данных и масштабирует объем пространственно, используя функцию максимума. Чаще всего используется слой с фильтрами размера 2×2 с шагом 2; подобный слой снижает дискретизацию каждого среза глубины входа в 2 раза как по ширине, так и по высоте, откидывая при этом 75% активация. Каждая операция MAX в этом случае будет выбирать максимальное значение из 4 чисел. Размер по глубине при этом остается неизменным. В общем случае слой пулинга:

  • Получает объем на входе размером W1xH1xD1
  • Требует 2 гиперпараметра:
  1. их протяженность F,
  2. шаг S.
  • Вводит нулевые параметры, поскольку производится вычисление фиксированной функции ввода.

Обратите внимание, что дополнение нулями не принято использовать в подвыборке. На практике можно увидеть только две вариации слоя пулинга: слой с гиперпараметрами F=3, S=2 (также называют перекрывающей подвыборкой) и еще более распространенный слой F=2, S=2. Размеры пулингов с большими рецептивными полями являются деструктивными.

Общий пулинг

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

---------------------------------------------------------------------------------------------------------------------------------------------------

Рисунок 10. - Субдискретизация пространственных измерений с сохранением глубины                        

Рисунок 10. — Субдискретизация пространственных
измерений с сохранением глубины

Рисунок 11. - Пулинг с функцией максимума и фильтром 2x2 с шагом = 2

Рисунок 11. — Пулинг с функцией
максимума и фильтром 2×2 с шагом = 2

Слой пулинга снижает дискретизацию по пространственным измерениям, независимо от глубины среза входного объема. Слева: В этом примере входной объема размера [224×224×64] объединяется с фильтром размера 2×2 и шагом 2 -> выходной объем [112×112×64]. Измерение глубины остается прежним. Справа: Пулинг с функцией максимума и фильтром 2×2 с шагом = 2.

---------------------------------------------------------------------------------------------------------------------------------------------------

Метод обратного распространения ошибки

Рассматривая свёрточный слой, мы уже говорили о том, что обратный проход для операции max (x, y) интерпретируется как градиент на вход, который имел наибольшее значение при прямом проходе. Следовательно, при прямом проходе слоя пулинга общепринятым является отслеживание индекса максимальной активации (его иногда называют переключателем) так, чтобы градиент пути был эффективен во время обратного распространения.

Избавление от пулинга

Отдельные специалисты не любят операцию пулинга и считают, что можно обойтись и без нее. Например, Д. Т. Спрингенберг, А. Досовицкий, Т. Брокс и М. Ридмиллер в своей работе предложили отказаться от слоя пулинга в пользу архитектуры, которая состоит исключительно из повторяющихся слоев свёртки. Чтобы уменьшить размер представления, они предлагают использовать больший в свёрточных слоях. Отказ от субдискретизации может сыграть важную роль в обучении генеративных моделей вроде вариационных автоасоциаторов (VAE) или генеративных состязательных сетей (GAN). Похоже, что уже в ближайшем будущем архитектура типовой свёрточной нейронной сети будет лишена слоев пулинга, либо они будут представлены в очень малом количестве.

Полносвязный слой

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

Преобразование полносвязных слоев в свёрточные

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

  • Для любого слоя свёртки существует полносвязный слой, который реализует ту же функцию прохода. Матрица весов будет представлять собой большую матрицу, которая в основном заполнена нулями за исключением некоторых блоков (из-за локальной связности), веса большинства из которых будут равными (из-за совместного использования параметров).
  • И наоборот: любой полносвязный слой может быть преобразован в слой свёртки. Например, полносвязный слой с глубиной K=4 096, направленный на некоторый входной объем размера [7x7x512] может быть выражен как слой свёртки со следующими параметрами: размер фильтра F=7, дополнение нулями отсутствует (P=0), шаг S=1 и глубина фильтра K=4 096. Другими словами, мы устанавливаем размер фильтра точно такой же, как и размер входного объема. На выходе мы получим [1x1x4096], потому что только один столбец глубины «правильно» проходит по всем входным данным, давая точно такой же результат, как и исходный полносвязный слой.

Роль преобразований

Возможность преобразовывать полносвязные слои в свёрточные и наоборот широко используется на практике. Рассмотрим свёрточную нейронную сеть, которая принимает на входе изображение [224×224×3], а затем использует ряд слоев свёртки и пулинга, чтобы уменьшить изображение до активационного объема в размере [7x7x512]. В архитектуре AlexNet, которую мы рассмотрим позже, это делается путем использования 5 слоев пулинга, которые понижают дискретизацию входных пространственных измерений, благодаря чему окончательный пространственный размер равен 224/2/2/2/2/2 = 7. Архитектура AlexNet использует 2 полносвязных слоя размером 4 096 и еще 1 полносвязный слой с 1 000 нейронов, который подсчитывает оценки классов. Мы можем преобразовать любой из этих 3 слоев в свёрточный по описанному алгоритму:

  1. Заменить первый полносвязный слой, направленный на участок объема [7x7x512], свёрточным слоем с фильтром размера F=7, который обеспечит выходной объем [1x1x4096].
  2. Заменить второй полносвязный слой свёрточным слоем фильтром размера F=1, который обеспечит выходной объем [1x1x4096].
  3. Заменить последний полносвязный слой свёрточным слоем фильтром размера F=1, который обеспечит выходной объем [1x1x1000].

Каждое из этих преобразований может включать в себя определенные манипуляции (например, изменение формы) матрицы весов W в каждом полносвязном слое в фильтрах слоя свёртки. Оказывается, что эти преобразования позволяют «протаскивать» за один прямой проход исходную CNN через многие пространственные положения в более крупных изображениях.

К примеру, если картинка размера 224×224 дает объем размера [7x7x512], т. е. производит сокращение на 32, тогда пересылка изображения с размером 384×384 через преобразованную архитектуру даст эквивалентный объем в размере [12×12×512], поскольку 384/32 = 12. Вместо одного вектора оценки класса размера [1x1x1000], теперь мы получаем целый массив оценки класса 6×6 по всему изображению размера 384×384.

Вычисление исходной свёрточной нейросети (с полносвязными слоями), независимо проходящей через 224x224 изображения размером 384×384 с шагом в 32 пиксела, дает такой же результат, как и единоразовое прохождение конвертированной CNN.

Естественно, единоразовое прохождение преобразованной нейронной сети куда эффективнее, нежели многократное итерирование оригинальной CNN по всем 36 позициям. Данная «фишка» часто используется на практике с целью повышения производительности. Так, когда необходимо изменить размер изображения в большую сторону, используют конвертированную свёрточную нейронную сеть, чтобы дать характеристику оценке класса на многих пространственных позициях, а затем ее усреднить.

А что если нужно эффективно применить исходную CNN на изображении, но с шагом меньшим 32 пикселей. Это можно осуществить с помощью перемножения прямых проходов. Например, если мы хотим использовать шаг в 16 пикселей, то требуется объединить объемы, полученные путем прохода преобразованной сёрточной нейросети, дважды: сначала по исходному изображению, потом — также по изображению, но сдвинутому на 16 пискелей как по ширине, так и высоте.

  • В интерактивной оболочке IPython Notebook на Net Surgery показано, как на практике, в коде использовать преобразование.

Архитектуры CNN

Мы увидели, что свёрточные нейронные сети обычно состоят из 3 основных типов слоев: свёрточных, пулинга и полносвязных. Мы будем также явно записывать функцию активации ReLu в качестве слоя, в котором используется поэлементная нелинейность. Давайте обсудим, как эти слои взаимодействуют вместе, образуя целостную CNN.

Паттерны слоев

Чаще всего при построении архитектуры CNN складывают несколько слоев слоев свёртки и ректификации (ReLu), за ними следуют слои пулинга; этот шаблон продолжает работать, пока изображение не будет объединено до малого размера. В некоторый момент осуществляется переход к полносвязным слоям. Последний полносвязный слой содержит выходную информацию, например, оценки класса. Другими словами, наиболее распространенная архитектура CNN соответствует схеме:

INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC

Здесь «*» означает повторение, а POOL? указывает на дополнительный слой пулинга. Кроме того, N >= 0, (обычно N <= 3), M >= 0, K >= 0 (обычно K < 3). Ниже представлены архитектуры CNN, организованные по этому образцу:

  • INPUT -> FC, реализует линейный классификатор. Здесь N = M = K = 0.
  • INPUT -> CONV -> RELU -> FC
  • INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC. Здесь один свёрточный слой — между каждый слоем пулинга.
  • INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC. Здесь 2 слоя свёртки укладываются перед каждым слоем пулинга.

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

Как правило, отдают предпочтение стеку слоев с небольшими фильтрами, нежели одному большому рецептивному полю свёрточного слоя. Предположим, вы, соблюдая нелинейность между слоями, выкладываете 3 слоя свёртки размера 3×3 друг на друга. При таком расположении, каждый нейрон на первом свёрточном слое обладает видом 3×3 входного объема. Нейроны на втором слое обладают видом 3×3 первого слоя и 5×5 входного объема. Точно так же нейроны на третьем слое обладают видом 3×3 второго слоя и 7×7 входного объема. Допустим вместо этих трех свёрточных слоев, мы хотим использовать только один CONV-слой с рецептивными полями размера 7×7. Нейроны такого слоя будут иметь рецептивное поле входного объема, аналогичное пространственной протяженности (7×7), но с некоторыми недостатками. Во-первых, нейроны будут вычислять линейную функцию входного объема, в то время как стек из 3 слоев свёртки содержит нелинейности, подчеркивающие свойства слоев. Во-вторых, если мы предположим, что весь входной объем имеет C каналов, тогда один свёрточный слой размера 7×7 будет содержать Cx (7x7xC)=49C2 параметров, в то время как стек из 3 слоев содержит лишь 3x (Cx (3x3xC))=27C2 параметров. Очевидно, что «укладка» нескольких CONV-слоев с небольшими фильтрами позволяет подчеркнуть более мощные особенности входной информации с меньшим количеством параметров. Недостатком является больший объем используемой памяти для сохранения всех промежуточных результатов.

На практике используют то, что лучше работает с базой данных ImageNet. Разработчикам не следует беспокоиться о более чем 90% архитектур, ведь главная задача — выбрать ту, которая в настоящее время наилучше совместима с ImageNet, скачать предварительно обученную модель и настроить ее под свои данные. Разработчикам практически никогда не приходится обучать свёрточную нейросеть с нуля.

Конкретные примеры

Рассмотрим наиболее популярные архитектуры свёрточных нейронных сетей:

  • LeNet. Первое успешное применение свёрточной нейронной сети удалось разработать Яну Лекуну в 1990-е годы. Архитектура LeNet применялась для считывания почтовых индексов, цифр и т. п.
  • AlexNet. Это работа Алекса Крижевского, Ильи Суцкевера и Джеффа Хинтона, которая сыграла существенную роль в популяризации CNN в области компьютерного зрения. Архитектура AlexNet была представлена на ImageNet ILSVRC Challenge в 2012 году и обошла все работы конкурентов (16% ошибок против 26% у архитектуры, занявшей второе место).
  • ZF Net. А вот победителем ILSVRC 2013 стала свёрточная нейронная сеть Мэтью Зеллера и Роба Фергюса, которая известка как ZF Net (аббревиатура от Zeiler и Fergus). Данная архитектура была улучшенной версией AlexNex: здесь увеличили размеры средних свёрточных слоев и уменьшили шаг и размер фильтра на первом слое.
  • GoogLeNet. В 2014 году вышеупомянутый конкурс выиграла CNN разработки Шегеди и других — сотрудников корпорации Google. Основная заслуга данной архитектуры состоит в разработке и внедрении входного модуля (Inception Module), что позволило резко сократить число параметров до 4 млн с 60 млн в Сокращение параметров происходит также благодаря замене полносвязных слоев в верхней части сети слоями среднего пулинга.
  • VGGNet. Сразу за GoogLeNet на ILSVRC 2014 расположилась сеть Карена Симоняна и Эндрю Циссермана, которая стала известна как Разработчикам удалось наглядно продемонстрировать, что глубина является ключевым фактором для производительности. Их сеть содержит 16 свёрточных и полносвязных слоев и имеет чрезвычайно однородную архитектуру, которая выполняет свёртывание 3×3 и пулинг 2×2 от начала до конца. Исходная модель доступна в режиме Plug and Play во фреймворке для глубинного обучения Caffe.
  • ResNet. Остаточная сеть (Residual Network), разработанная Каймингом Хе и другими, стала победителем ILSVRC Ключевые особенности — интенсивное использование пакетной нормализации и специальные скип-соединения. В конце архитектуры отсутствую полносвязные слои. ResNet по состоянию на сегодняшний день является настоящим произведением искусства в мире свёрточных нейронных сетей и используется наиболее часто.

VGGNet в деталях

Рассмотрим VGGNet более детально. Вся сеть состоит из свёрточных слоев, которые выполняют свёртывание 3×3 с шагом 1 и дополнением 1, и слое пулинга, выполняющих максимальную подвыборку 2×2 с шагом 2 без дополнения нулями. Можно выписать размер представления на каждом шаге и отслеживать как его изменение, так и изменение количества весов:

INPUT: [224×224×3] память: 224*224*3=150K веса: 0

CONV3−64: [224×224×64] память: 224*224*64=3.2M веса: (3*3*3)*64 = 1,728

CONV3−64: [224×224×64] память: 224*224*64=3.2M веса: (3*3*64)*64 = 36,864

POOL2: [112×112×64] память: 112*112*64=800K веса: 0

CONV3−128: [112×112×128] память: 112*112*128=1.6M веса: (3*3*64)*128 = 73,728

CONV3−128: [112×112×128] память: 112*112*128=1.6M веса: (3*3*128)*128 = 147,456

POOL2: [56×56×128] память: 56*56*128=400K веса: 0

CONV3−256: [56×56×256] память: 56*56*256=800K веса: (3*3*128)*256 = 294,912

CONV3−256: [56×56×256] память: 56*56*256=800K веса: (3*3*256)*256 = 589,824

CONV3−256: [56×56×256] память: 56*56*256=800K веса: (3*3*256)*256 = 589,824

POOL2: [28×28×256] память: 28*28*256=200K веса: 0

CONV3−512: [28×28×512] память: 28*28*512=400K веса: (3*3*256)*512 = 1,179,648

CONV3−512: [28×28×512] память: 28*28*512=400K веса: (3*3*512)*512 = 2,359,296

CONV3−512: [28×28×512] память: 28*28*512=400K веса: (3*3*512)*512 = 2,359,296

POOL2: [14×14×512] память: 14*14*512=100K веса: 0

CONV3−512: [14×14×512] память: 14*14*512=100K веса: (3*3*512)*512 = 2,359,296

CONV3−512: [14×14×512] память: 14*14*512=100K веса: (3*3*512)*512 = 2,359,296

CONV3−512: [14×14×512] память: 14*14*512=100K веса: (3*3*512)*512 = 2,359,296

POOL2: [7x7x512] память: 7*7*512=25K веса: 0

FC: [1x1x4096] память: 4096 веса: 7*7*512*4096 = 102,760,448

FC: [1x1x4096] память: 4096 веса: 4096*4096 = 16,777,216

FC: [1x1x1000] память: 1000 веса: 4096*1000 = 4,096,000


TOTAL память: 24M * 4 bytes ≅ 93MB / image (only forward! ~*2 for bwd)

TOTAL параметры: 138M параметров

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

Рекомендации по вычислениям

Наибольшие препятствия при организации CNN может чинить память. Современные графические процессоры имеют лимит памяти в 3, 4 или 6 Гб, в то время как лучшие GPU располагают 12 Гб. Есть 3 основных источника памяти, за которыми обязательно нужно следить:

  • Из промежуточных размеров объемов. Это необработанное количество активаций на каждом слое CNN, а также их градиенты. Обычно большинство активаций располагаются на самых первых слоях свёрточной нейросети. Это следует иметь в виду, ведь данные активации нужны для обратного распространения ошибки. Однако «умная» реализация, которая запустает CNN только во время испытаний, может уменьшить количество активаций путем сохранения лишь текущих из них на любом слое и отбрасывания всех предыдущих на слоях ниже.
  • Из размеров параметров. Это числа, которые содержат параметры сети, их градиенты во время обратного распространения и, как правило, шаг кэша. Таким образом, память для хранения вектора параметров должна быть умножена на коэффициент, примерно равный 3.
  • Любая реализация свёрточной нейронной сети должна поддерживать разнородную память вроде пакета данных изображений, возможно, их усовершенствованные реализации.

Как только вы получили приблизительный размер общего количества значений (для активаций, градиентов и прочего), результат необходимо преобразовать в Гб. Возьмите количество значений, умножьте его на 4, чтобы получить число байтов, а затем разделите на 1 024 несколько раз, чтобы получить память сначала в килобайтах, потом мегабайтах и, наконец, гигабайтах. Если ваша сеть «неподходящая», тогда «подогнать» ее можно путем уменьшения пакетного размера, поскольку большинство памяти обычно потребляется активациями.

Дополнительные источники

rustam1208

rustam1208

Комментариев нет.

Посмотреть комментарии (0) ...
Навигация