Версия этого поста опубликована здесь.

Цель этого поста - перейти от основ предварительной обработки данных к современным методам, используемым в глубоком обучении. Я хочу сказать, что мы можем использовать код (например, Python / NumPy), чтобы лучше понимать абстрактные математические понятия. Думая кодированием! 💥

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

Под предварительной обработкой понимаются все преобразования необработанных данных перед их передачей в алгоритм машинного обучения или глубокого обучения. Например, обучение сверточной нейронной сети на необработанных изображениях, вероятно, приведет к плохим характеристикам классификации (Pal & Sudeep, 2016). Предварительная обработка также важна для ускорения обучения (например, методы центрирования и масштабирования, см. Lecun et al., 2012; см. 4.3).

Вот программа этого урока:

1. Справочная информация: В первой части мы получим несколько напоминаний о дисперсии и ковариации. Мы увидим, как генерировать и отображать фальшивые данные, чтобы лучше понять эти концепции.

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

3. Отбеливание изображений. В третьей части мы будем использовать инструменты и концепции, полученные в 1. и 2., чтобы сделать особый вид отбеливания, который называется Анализ нулевых компонентов (ZCA). Его можно использовать для предварительной обработки изображений для глубокого обучения. Эта часть будет очень практичной и увлекательной ☃️!

Смело раскройте блокнот, связанный с этим постом! Например, проверяйте форму матриц каждый раз, когда у вас возникают сомнения.

1. Фон

А. Дисперсия и ковариация

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

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

Значение ковариации зависит от масштаба переменной, поэтому ее сложно анализировать. Можно использовать коэффициент корреляции, который легче интерпретировать. Коэффициент корреляции - это просто нормализованная ковариация.

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

Давайте просто проверим формулу дисперсии:

где n - длина вектора, а - среднее значение вектора. Например, дисперсия первого вектора-столбца A равна:

Это первая ячейка нашей ковариационной матрицы. Второй элемент на диагонали соответствует отклонению вектора второго столбца от A и так далее.

Примечание: векторы, извлеченные из матрицы A, соответствуют столбцам A.

Другие ячейки соответствуют ковариации между двумя векторами столбцов из A. Например, ковариация между первым и третьим столбцами находится в ковариационной матрице как столбец 1 и строка 3 (или столбец 3 и строка 1).

Давайте проверим, что ковариация между первым и третьим вектором-столбцом A равна -2,67. Формула ковариации между двумя переменными X и Y:

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

  1. Символ суммы (Σ) означает, что мы будем перебирать элементы векторов. Мы начнем с первого элемента (i = 1) и вычислим первый элемент X за вычетом среднего значения вектора X.

2. Умножьте результат на первый элемент Y за вычетом среднего значения вектора Y.

3. Повторите процесс для каждого элемента векторов и вычислите сумму всех результатов.

4. Разделите на количество элементов в векторе.

Пример 1.

Начнем с матрицы A:

Мы рассчитаем ковариацию между первым и третьим векторами столбцов:

а также

x̄ = 3, ȳ = 4 и n = 3, поэтому мы имеем:

Ок, отлично! Это значение ковариационной матрицы.

Теперь простой способ. С NumPy ковариационная матрица может быть вычислена с помощью функции np.cov.

Стоит отметить, что если вы хотите, чтобы NumPy использовал столбцы в качестве векторов, необходимо использовать параметр rowvar=False. Кроме того, bias=True делится на n , а не на n-1.

Давайте сначала создадим массив:

array([[1, 3, 5],
       [5, 4, 1],
       [3, 8, 6]])

Теперь посчитаем ковариацию с помощью функции NumPy:

array([[ 2.66666667, 0.66666667, -2.66666667],
       [ 0.66666667, 4.66666667, 2.33333333],
       [-2.66666667, 2.33333333, 4.66666667]])

Выглядит неплохо!

Нахождение ковариационной матрицы с помощью скалярного произведения

Есть еще один способ вычислить ковариационную матрицу A. Вы можете центрировать A вокруг 0. Среднее значение вектора вычитается из каждого элемента вектора, чтобы получить вектор со средним значением, равным 0. Оно умножается на собственное транспонирование и делится на число. наблюдений.

Давайте начнем с реализации, а затем попытаемся понять связь с предыдущим уравнением:

Давайте проверим это на нашей матрице A:

array([[ 2.66666667, 0.66666667, -2.66666667],
       [ 0.66666667, 4.66666667, 2.33333333],
       [-2.66666667, 2.33333333, 4.66666667]])

Получаем тот же результат, что и раньше.

Объяснение простое. Скалярное произведение между двумя векторами может быть выражено:

Правильно, это сумма произведений каждого элемента векторов:

Если n - это количество элементов в наших векторах, и мы делим его на n:

Вы можете заметить, что это не так уж далеко от формулы ковариации, которую мы видели ранее:

Единственное отличие состоит в том, что в формуле ковариации мы вычитаем среднее значение вектора из каждого его элемента. Вот почему нам нужно центрировать данные перед выполнением скалярного произведения.

Теперь, если у нас есть матрица A, скалярное произведение между A и ее транспонированием даст вам новую матрицу:

Это ковариационная матрица!

Б. Визуализация данных и ковариационных матриц

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

Эта функция вычислит ковариационную матрицу, как мы видели выше. Он создаст две подзаголовки - одну для ковариационной матрицы и одну для данных. Функция heatmap() от Seaborn используется для создания градиентов цвета - маленькие значения будут окрашены в светло-зеленый цвет, а большие - в темно-синий. Мы выбрали один из цветов нашей палитры, но вы можете предпочесть другие цвета. Данные представлены в виде диаграммы рассеяния.

C. Моделирование данных

Некоррелированные данные

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

Эта функция требует ввода среднего значения, стандартного отклонения и количества наблюдений за распределением. Мы создадим две случайные переменные из 300 наблюдений со стандартным отклонением 1. Средняя величина первой будет равна 1, а вторая - 2. Если мы случайным образом возьмем два набора из 300 наблюдений из нормального распределения, оба вектора будут некоррелированный.

(300, 2)

Примечание 1. Мы транспонируем данные с помощью .T, потому что исходная форма - это (2, 300), и мы хотим, чтобы количество наблюдений было строками (то есть с формой (300, 2)).

Примечание 2. Мы используем функцию np.random.seed для воспроизводимости. То же случайное число будет использовано при следующем запуске ячейки.

Давайте проверим, как выглядят данные:

array([[ 2.47143516, 1.52704645],
       [ 0.80902431, 1.7111124 ],
       [ 3.43270697, 0.78245452],
       [ 1.6873481 , 3.63779121],
       [ 1.27941127, -0.74213763],
       [ 2.88716294, 0.90556519],
       [ 2.85958841, 2.43118375],
       [ 1.3634765 , 1.59275845],
       [ 2.01569637, 1.1702969 ],
       [-0.24268495, -0.75170595]])

Хорошо, у нас есть два вектора-столбца.

Теперь мы можем проверить правильность распределения:

Выглядит неплохо!

Мы видим, что распределения имеют эквивалентные стандартные отклонения, но разные средние значения (1 и 2). Это именно то, о чем мы просили.

Теперь мы можем построить наш набор данных и его ковариационную матрицу с помощью нашей функции:

Covariance matrix:
[[ 0.95171641 -0.0447816 ]
 [-0.0447816 0.87959853]]

На диаграмме рассеяния видно, что два измерения не коррелированы. Обратите внимание, что у нас есть одно измерение со средним значением 1 (ось y), а другое - со средним значением 2 (ось x).

Кроме того, ковариационная матрица показывает, что дисперсия каждой переменной очень велика (около 1), а ковариация столбцов 1 и 2 очень мала (около 0). Поскольку мы убедились, что два вектора независимы, это согласовано. Обратное не обязательно: ковариация 0 не гарантирует независимости (см. Здесь).

Коррелированные данные

Теперь давайте создадим зависимые данные, выделив один столбец из другого.

Covariance matrix:
[[ 0.95171641 0.92932561]
 [ 0.92932561 1.12683445]]

Корреляция между двумя измерениями видна на диаграмме рассеяния. Мы видим, что можно провести линию и использовать ее для прогнозирования y от x и наоборот. Ковариационная матрица не диагональная (за пределами диагонали есть ненулевые ячейки). Это означает, что ковариация между измерениями не равна нулю.

Замечательно! Теперь у нас есть все инструменты, чтобы увидеть различные методы предварительной обработки.

2. Предварительная обработка

А. Средняя нормализация

Нормализация среднего - это просто удаление среднего из каждого наблюдения.

где X ’ - нормализованный набор данных, X - исходный набор данных, а - среднее значение X.

Средняя нормализация приводит к центрированию данных вокруг 0. Для этого мы создадим функцию center():

Давайте попробуем с помощью созданной ранее матрицы B:

Before:
Covariance matrix:
[[ 0.95171641 0.92932561]
 [ 0.92932561 1.12683445]]

After:
Covariance matrix:
[[ 0.95171641 0.92932561]
 [ 0.92932561 1.12683445]]

Первый график снова показывает исходные данные B, а второй график показывает центрированные данные (посмотрите на шкалу).

Б. Стандартизация или нормализация

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

где X ' - стандартизированный набор данных, X - исходный набор данных, - среднее значение X, и σ - стандартное отклонение X.

Давайте создадим еще один набор данных с другим масштабом, чтобы убедиться, что он работает.

Covariance matrix:
[[ 0.95171641 0.83976242]
 [ 0.83976242 6.22529922]]

Мы видим, что масштабы x и y различны. Также обратите внимание, что корреляция кажется меньше из-за различий в масштабах. Теперь давайте стандартизируем его:

Covariance matrix:
[[ 1.          0.34500274]
 [ 0.34500274  1.        ]]

Выглядит неплохо. Вы можете видеть, что масштабы одинаковы, и что набор данных отцентрован по обеим осям.

Теперь посмотрим на ковариационную матрицу. Вы можете видеть, что дисперсия каждой координаты - верхней левой ячейки и нижней правой ячейки - равна 1.

Эта новая ковариационная матрица на самом деле является корреляционной матрицей. Коэффициент корреляции Пирсона между двумя переменными (c1 и c2) составляет 0,54220151.

C. Отбеливание

Отбеливание или сферирование данных означает, что мы хотим преобразовать их, чтобы получить ковариационную матрицу, которая является единичной матрицей - 1 по диагонали и 0 для других ячеек. Это называется отбеливанием по отношению к белому шуму.

Вот более подробная информация об единичной матрице.

Отбеливание немного сложнее, чем другая предварительная обработка, но теперь у нас есть все инструменты, которые нам нужны для этого. Он включает в себя следующие этапы:

  • Нулевой центр данных
  • Декорреляция данных
  • Изменить масштаб данных

Возьмем снова C и попробуем проделать эти шаги.

  1. Центрирование нуля

Это относится к средней нормализации (2. A). Проверьте подробности о функции center().

Covariance matrix:
[[ 0.95171641  0.83976242]
 [ 0.83976242  6.22529922]]

2. Decorrelate

На этом этапе нам нужно декоррелировать наши данные. Интуитивно это означает, что мы хотим вращать данные до тех пор, пока корреляция не исчезнет. Посмотрите на следующее изображение, чтобы понять, что я имею в виду:

Левый график показывает коррелированные данные. Например, если вы возьмете точку данных с большим значением x, скорее всего, соответствующий y также будет довольно большим.

Теперь возьмите все точки данных и поверните их (возможно, примерно на 45 градусов против часовой стрелки. Новые данные, показанные справа, больше не коррелированы. Вы можете видеть, что большие и маленькие значения y связаны с одинаковые значения x.

Возникает вопрос: как найти правильное вращение, чтобы получить некоррелированные данные?

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

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

Подробнее о собственном разложении читайте в этом посте.

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

  • Вычислить ковариационную матрицу
  • Вычислить собственные векторы ковариационной матрицы
  • Примените к данным матрицу собственных векторов - это применит вращение

    Давайте упакуем это в функцию:

Давайте попробуем декоррелировать нашу матрицу с нулевым центром C, чтобы увидеть ее в действии:

Covariance matrix:
[[ 0.95171641 0.83976242]
 [ 0.83976242 6.22529922]]

Covariance matrix:
[[ 5.96126981e-01 -1.48029737e-16]
 [ -1.48029737e-16 3.15205774e+00]]

Отлично! Это работает.

Мы видим, что корреляции здесь больше нет. Ковариационная матрица, теперь диагональная матрица, подтверждает, что ковариация между двумя измерениями равна 0.

3. Измените масштаб данных

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

Примечание: мы добавляем небольшое значение (здесь 10 ^ -5), чтобы избежать деления на 0.

Covariance matrix:
[[ 9.99983225e-01 -1.06581410e-16]
 [ -1.06581410e-16 9.99996827e-01]]

Ура! Мы видим, что с ковариационной матрицей все в порядке. У нас есть нечто похожее на единичную матрицу - 1 по диагонали и 0 в другом месте.

3. Отбеливание изображения

Мы увидим, как можно применить отбеливание для предварительной обработки набора данных изображения. Для этого мы будем использовать статью Pal & Sudeep (2016), где они подробно описывают процесс. Этот метод предварительной обработки называется анализом нулевых компонентов (ZCA).

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

Перво-наперво. Мы загрузим изображения из набора данных CIFAR. Этот набор данных доступен в Keras, и вы также можете скачать его здесь.

(50000, 32, 32, 3)

Обучающий набор набора данных CIFAR10 содержит 50000 изображений. Форма X_train - (50000, 32, 32, 3). Каждое изображение имеет размер 32 на 32 пикселя, и каждый пиксель содержит 3 измерения (R, G, B). Каждое значение - это яркость соответствующего цвета от 0 до 255.

Мы начнем с выбора только части изображений, скажем, 1000:

(1000, 32, 32, 3)

Так-то лучше. Теперь мы изменим форму массива, чтобы иметь данные плоского изображения с одним изображением в строке. Каждое изображение будет (1, 3072), потому что 32 x 32 x 3 = 3072. Таким образом, массив, содержащий все изображения, будет (1000, 3072):

(1000, 3072)

Следующий шаг - увидеть изображения. Функция imshow() из Matplotlib (doc) может использоваться для отображения изображений. Ему нужны изображения с формой (M x N x 3), поэтому давайте создадим функцию, чтобы изменить форму изображений и иметь возможность визуализировать их по форме (1, 3072).

Например, давайте построим одно из загруженных изображений:

Милый!

Теперь мы можем реализовать отбеливание изображений. Pal & Sudeep (2016) описывают процесс:

1. Первым шагом является изменение масштаба изображений для получения диапазона [0, 1] путем деления на 255 (максимальное значение пикселей).

Напомним, что формула для получения диапазона [0, 1]:

но здесь минимальное значение равно 0, поэтому это приводит к:

X.min() 0.0
X.max() 1.0

Среднее вычитание: на пиксель или на изображение?

Хорошо, классно, теперь диапазон значений наших пикселей составляет от 0 до 1. Следующий шаг:

2. Вычтите среднее значение для всех изображений.

Здесь будьте осторожны.

Один из способов сделать это - взять каждое изображение и удалить среднее значение этого изображения из каждого пикселя (Jarrett et al., 2009). Интуиция, лежащая в основе этого процесса, заключается в том, что он центрирует пиксели каждого изображения вокруг 0.

Другой способ сделать это - взять каждый из 3072 пикселей, которые у нас есть (32 на 32 пикселя для R, G и B) для каждого изображения, и вычесть среднее значение этого пикселя для всех изображений. Это называется вычитанием среднего попиксельного значения. На этот раз каждый пиксель будет центрирован вокруг 0 ​​для всех изображений. Когда вы загружаете свою сеть изображениями, каждый пиксель рассматривается как отдельная функция. С помощью вычитания среднего попиксельного значения мы центрировали каждую функцию (пиксель) около 0. Этот метод широко используется (например, Wan et al., 2013).

Теперь мы произведем вычитание среднего попиксельного значения из наших 1000 изображений. Наши данные организованы по этим размерам (images, pixels). Это было (1000, 3072), потому что есть 1000 изображений размером 32 x 32 x 3 = 3072 пикселя. Таким образом, среднее значение на пиксель можно получить по первой оси:

(3072,)

Это дает нам 3072 значения, что является количеством средних - одно на пиксель. Давайте посмотрим, какие ценности у нас есть:

array([ 0.5234 , 0.54323137, 0.5274 , …, 0.50369804,
 0.50011765, 0.45227451])

Это близко к 0,5, потому что мы уже нормализовали до диапазона [0, 1]. Однако нам все равно нужно удалить среднее значение для каждого пикселя:

Чтобы убедиться, что это сработало, мы вычислим среднее значение первого пикселя. Будем надеяться, что это 0.

array([ -5.30575583e-16, -5.98021632e-16, -4.23439062e-16, …,
 -1.81965554e-16, -2.49800181e-16, 3.98570066e-17])

Это не совсем 0, но достаточно мало, чтобы можно было считать, что это сработало!

Теперь мы хотим вычислить ковариационную матрицу данных с нулевым центром. Как мы видели выше, мы можем вычислить его с помощью функции np.cov() из NumPy.

Обратите внимание, что наши переменные - это разные изображения. Это означает, что переменные являются строками матрицы X. Для ясности, мы передадим эту информацию NumPy с параметром rowvar=TRUE, даже если по умолчанию он True (см. Doc):

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

Примечание. Для большого количества изображений может потребоваться некоторое время, поэтому мы используем только 1000 изображений. В документе они использовали 10000 изображений. Не стесняйтесь сравнивать результаты в зависимости от того, сколько изображений вы используете:

В статье они использовали следующее уравнение:

где U - левые сингулярные векторы, S - сингулярные значения ковариации исходного нормализованного набора данных изображений, а X - нормализованный набор данных. ϵ - это гиперпараметр, называемый коэффициентом отбеливания. diag (a) соответствует матрице с вектором a по диагонали и 0 во всех остальных ячейках.

Мы попробуем реализовать это уравнение. Начнем с проверки габаритов СВД:

(1000, 1000) (1000,)

S - вектор, содержащий 1000 элементов (сингулярные значения). Таким образом, diag (S) будет иметь форму (1000, 1000) с диагональю S:

[[ 8.15846654e+00 0.00000000e+00 0.00000000e+00 …, 0.00000000e+00
 0.00000000e+00 0.00000000e+00]
 [ 0.00000000e+00 4.68234845e+00 0.00000000e+00 …, 0.00000000e+00
 0.00000000e+00 0.00000000e+00]
 [ 0.00000000e+00 0.00000000e+00 2.41075267e+00 …, 0.00000000e+00
 0.00000000e+00 0.00000000e+00]
 …, 
 [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 …, 3.92727365e-05
 0.00000000e+00 0.00000000e+00]
 [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 …, 0.00000000e+00
 3.52614473e-05 0.00000000e+00]
 [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 …, 0.00000000e+00
 0.00000000e+00 1.35907202e-15]]
shape: (1000, 1000)

Отметьте эту часть:

Он также имеет форму (1000, 1000), а также U и U ^ T. Мы также видели, что X имеет форму (1000, 3072). Форма X_ZCA выглядит следующим образом:

что соответствует форме исходного набора данных. Отлично.

У нас есть:

Неутешительно! Если вы посмотрите на бумагу, они показывают не такой результат. На самом деле это потому, что мы не масштабировали пиксели и есть отрицательные значения. Для этого мы можем вернуть его в диапазон [0, 1] тем же способом, что и выше:

min: 0.0
max: 1.0

Ура! Замечательно! Похоже на картинку с бумаги. Как упоминалось ранее, они использовали 10000 изображений, а не 1000, как мы.

Чтобы увидеть различия в результатах в зависимости от количества используемых изображений и эффекта гиперпараметра ϵ, вот результаты для разных значений:

Результат отбеливания зависит от количества используемых изображений и значения гиперпараметра ϵ. Изображение слева - исходное изображение. В статье Pal & Sudeep (2016) использовано 10000 изображений и epsilon = 0,1. Это соответствует нижнему левому изображению.

Это все!

Я надеюсь, что вы нашли что-то интересное в этой статье. Вы можете прочитать это в моем блоге, с LaTeX для математики, вместе с другими статьями.

Вы также можете форкнуть блокнот Jupyter на Github здесь.

использованная литература

К. Джарретт, К. Кавукчуоглу, М. Ранзато и Я. ЛеКун, «Какая многоступенчатая архитектура является лучшей для распознавания объектов?, На 12-й Международной конференции IEEE по компьютерному зрению, 2009 г., стр. 2146–2153 ».

А. Крижевский, «Изучение множества слоев элементов из крошечных изображений, магистерская работа, Университет Тронта, 2009 г. »

Ю. А. ЛеКун, Л. Ботту, Г. Б. Орр, К.-Р. Мюллер, «Эффективный обратный трафик, в Нейронные сети: хитрости торговли, Springer, Berlin, Heidelberg, 2012, стр. 9–48 ».

К. К. Пал и К. С. Судип, «Предварительная обработка для классификации изображений с помощью сверточных нейронных сетей, Международная конференция IEEE по последним тенденциям в электронике, информационных коммуникационных технологиях (RTEICT), 2016 г., стр. 1778–1781 ».

Л. Ван, М. Цайлер, С. Чжан, Ю. Л. Кун и Р. Фергус, «Регуляризация нейронных сетей с помощью DropConnect, Международная конференция по машинному обучению, 2013 г., стр. 1058–1066 ».

Отличные ресурсы и контроль качества

Википедия - Отбеливающая трансформация

CS231 - Сверточные нейронные сети для визуального распознавания

Дастин Стэнсбери - Умная машина

Некоторые подробности о ковариационной матрице

SO - Отбеливание изображения в Python

Средняя нормализация для изображения или для всего набора данных

Среднее вычитание - все изображения или по изображению?

Почему центрирование важно - см. Раздел 4.3

Ядро Kaggle на ZCA

Как ZCA реализован в Керасе