Урок 6 «Практического глубокого обучения для программистов» от fast.ai

Я работаю над курсом Практическое глубокое обучение для программистов Джереми Ховарда и Рэйчел Томас из fast.ai и веду блог о своем опыте. Так как невероятно щедрое сообщество fast.ai уже сделало подробные записи для каждого урока (см. те, что к Уроку 6 здесь), я просто пишу те части лекции и сопровождающие блокноты Jupyter, над которыми мне нужно было остановиться и подумать несколько раз.

Первая тема, которую мне нужно было рассмотреть, возникла во время обсуждения аффинных преобразований в отношении увеличения данных. Что опять означает аффинно? Что-то связанное с линейностью. Я проконсультировался с Google и нашел множество ясных объяснений, но это на Math Stack Exchange мне помогло: линейная функция просто масштабируется, а аффинная функция масштабируется и *смещается*.

Я провел большую часть оставшегося времени Урока 6, разбираясь в извилинах. Джереми говорит, что на всех картинках в документах кошки, потому что Сильвен Гаггер любит кошек, и он написал большую часть документации (хотя Сильвен говорит, что на самом деле не любит кошек и просто вставляет их, чтобы заманить людей в заблуждение). читать документы, что довольно забавно).

Итак, давайте исследуем извилины и сохраним кошачью тему с помощью Grumpy Cat (RIP).

Джереми использует Анимацию ядра изображения Брета Виктора, чтобы проиллюстрировать, как работает арифметика свертки. Учитывая матрицу, элементы которой представляют пиксели изображения, свертка берет элемент этой матрицы и использует (обычно квадратную) матрицу, такую ​​​​как 3 x 3, показанную ниже, для выполнения поэлементного матричного умножения значений элементов вокруг выбранного пикселя элемента/пикселя с этим пикселем в центре матрицы. Если пиксель находится близко к краю изображения, нам может понадобиться дополнить матрицу, как показано на этой анимации Франческо Визина. Наконец, мы складываем все произведения, чтобы получить одно значение (так что в терминах линейной алгебры мы просто делаем скалярное произведение).

Используя изображение Grumpy Cat с ядром «резкости», показанное ниже, мы видим, что ядро ​​будет сильно выделять пиксель, на который оно «смотрит» (тот, что в центре), умножая его на 5, в то время как пиксели вокруг него уменьшаются, на умножая их на 0 или -1, увеличивая контраст между ними.

Точно так же, используя ядро ​​«размытие», мы видим, что это ядро ​​уменьшает значение рассматриваемого пикселя до 0,25, но еще больше уменьшает значение пикселей вокруг него, что снижает общий контраст.

Иногда, изучая что-то, может показаться: «Да, все это имеет смысл, и я полностью понял это», а затем вы пытаетесь объяснить это и понимаете, что на самом деле почти ничего не поняли из того, что только что услышали. Остановка, чтобы объяснить концепцию, которую вы только что изучили, кому-то другому, даже если этот кто-то воображаемый (или блог ;)) — очень эффективный способ определить, действительно ли вы ее понимаете!

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

512 кажется нормальным, будучи степенью двойки, но почему мы останавливаемся на 11, в частности, для двух других измерений?

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

Итак, давайте резервное копирование. Мы начали с тензора, представляющего изображение, и этот тензор имел 3 канала (красный, синий и зеленый), высоту 352 пикселя и ширину 352 пикселя. Вот форма тензора:

У нас много изображений, столько таких тензоров, но PyTorch ожидает, что мы будем использовать мини-пакеты по одному изображению в каждом, поэтому, как говорит Джереми, мы можем индексировать массив специальным значением None , что создает новую единичную ось. , что дает нам тензор ранга 4 формы [1, 3, 352, 352] . Это мини-пакет из 1 изображения, которое имеет 3 канала, высоту 352 пикселя и ширину 352 пикселя. Одна вещь, которую мне приходилось постоянно проверять на работоспособность, заключалась в том, что функция shape возвращает каналы до высоты и ширины, но когда мы рассматриваем тензоры как многомерные матрицы, мы перечисляем размеры как высота x ширина x количество каналов. Таким образом, в матричных терминах приведенный выше тензор имеет размеры 352 x 352 x 3 (помните, что 1 — это не размерность матрицы, а размер мини-пакета).

Затем мы запускаем тензор через серию активаций, начиная с двумерной свертки Conv2d, которая использует шаг размера 2. Это означает, что вместо того, чтобы «смотреть» на каждый элемент матрицы, он «смотрит» на каждый другой. элемент, «перепрыгивая» половину из них. Именно поэтому высота и ширина сокращаются вдвое, а количество выходных каналов удваивается.

Таким образом, когда мы пропускаем тензор через первый сверточный слой, мы берем матрицу размеров 352 x 352 x 3 и пропускаем ее через 64 ​​свертки (или ядра) с шагом размера 2, и мы получаем обратно матрицу размеров (352 /2) х (352/2) х 64; то есть это 176 x 176 x 64 или в терминах формы PyTorch, как показано ниже:

Затем мы пропускаем тензор еще через два слоя: BatchNorm2d и ReLU, которые не меняют форму, а затем объединяющий слой MaxPool2d, который меняет форму до 88 x 88 x 64. Я нашел Джейсона Браунли A Gentle Introduction to Объединение слоев для сверточных нейронных сетей очень полезно для понимания того, как работают объединения слоев.

Мы продолжаем проходить через эти слои несколько раз, и время от времени мы делим высоту и ширину каждого на 2 и удваиваем количество ядер. Итак, в какой-то момент у нас есть 44 х 44 х 256, затем 22 х 22 х 512, затем, наконец, матрица 11 х 11 х 512, о которой мы думали.

Поэтому я думаю, что мы остановимся на 11 для высоты и ширины просто потому, что 11 — нечетное число! Если бы мы разделили 11 на 2, мы бы получили 5,5, что не совсем подходит для матрицы. Такое ощущение, что количество часов, которые я потратил на погоню за этим тензором, было далеко не пропорционально простоте ответа. Тем не менее, я определенно понимаю объемную гимнастику намного лучше, чем раньше, так что, думаю, это что-то!

Ознакомьтесь с полным кодом в ноутбуке домашних животных на GitHub, и увидимся на следующей неделе на уроке 7!

Другие сообщения на эту тему:

Урок 1: Начало работы с fast.ai

Урок 2: Классификация результатов теста на беременность

Урок 2 (продолжение): Может ли Deep Learning работать лучше, чем голуби?

Урок 3: 10 000 способов, которые не сработают

Урок 4: Предсказание чаевых официантам

Урок 5: Но куда девается рассол?

Я преподаю математику в CSU East Bay и начинающий специалист по данным. Свяжитесь со мной в LinkedIn или поздоровайтесь в Twitter.