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

Fast.ai использует подход «вот как использовать программное обеспечение для чего-то, а затем заглядывает за кулисы, изучая детали».

Выбывать

learn = ConvLearner.pretrained(arch, data, ps=0.5, precompute=True)

precompute=True предварительно вычисляет активации, которые происходят из последнего сверточного слоя. Активация - это число, рассчитываемое на основе некоторых весов, также известных как параметры, составляющие ядро, или фильтры, которые применяются к активации предыдущих слоев, которые в противном случае могли бы быть входными данными или результатами других вычислений.

Набрав имя вашего обучаемого объекта, вы действительно сможете увидеть в нем слои:

learn
Sequential(
  (0): BatchNorm1d(1024, eps=1e-05, momentum=0.1, affine=True)
  (1): Dropout(p=0.5)
  (2): Linear(in_features=1024, out_features=512)
  (3): ReLU()
  (4): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True)
  (5): Dropout(p=0.5)
  (6): Linear(in_features=512, out_features=120)
  (7): LogSoftmax()
)

Linear(in_features=1024, out_features=512) линейный слой означает матричный множитель. В этом случае у нас есть матрица с 1024 строками и 512 столбцами. Принимает 1024 активаций и выплевывает 512 активаций.

ReLu. Заменяет отрицательные числа нулями.

Linear(in_features=512, out_features=120) второй линейный слой принимает активации 512 первого линейного слоя и пропускает их через новую матрицу, умноженную 512 на 120, и выводит 120 активаций.

Softmax - функция активации, которая возвращает числа, которые в сумме составляют 1, каждое из которых находится в диапазоне от 0 до 1. По причинам незначительной числовой точности, оказывается, лучше вести журнал softmax, чем softmax напрямую. Вот почему, когда мы получаем прогнозы на основе наших моделей, мы должны делать np.exp(log_preds).

Что делает Dropout(p=0.5)?

Применение исключения означает выбор активации в слое и их удаление. p - вероятность удаления активации. Активация выхода не сильно меняет.

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

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

p=0.01 вы отбрасываете 1% активаций, это вообще ничего не изменит, поэтому не предотвратит переобучение, т.е. не будет обобщать.

p=0.99 вы скинете 99% активаций. Он также не будет переоснащаться, поэтому отлично подходит для обобщения, но убьет вашу точность.

Высокие p значения хорошо обобщают, но снижают точность обучения, низкие p значения будут хуже обобщать, но дадут вам большую точность.

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

Вам нужно что-то делать, чтобы приспособиться к тому, что вы выбрасываете активации? Мы не делаем (fast.ai) Когда мы говорим p=0.5 за сценой, pytorch отбрасывает половину активаций и удваивает уже существующую активацию, поэтому средняя активация не меняется.

В Fast.ai вы можете передать ps, что является значением p для всех добавленных слоев. Это не изменит отсев в предварительно обученной сети, поскольку она уже должна была быть обучена с некоторым подходящим уровнем отсева:

learn = ConvLearner.pretrained(arch, data, ps=0.5, precompute=True)

Мы можем удалить выпадение, установивps=0, но через пару эпох мы начинаем массово переобучаться. Потеря обучения меньше, чем потеря проверки. С ps=0 дропаут в модель вообще не добавляется.

Как вы могли заметить, он добавлял два Linear слоя. Мы не обязаны этого делать. Вы можете установить параметр xtra_fc (дополнительные полностью связанные слои). Который вы можете передать список того, насколько большим вы хотите, чтобы каждый из дополнительных полностью подключенных слоев был. Вам нужен хотя бы один, который принимает выходные данные сверточного слоя (1096 в этом примере) и превращает его в количество классов 120 пород собак, то есть определяется вашей проблемой:

Если xtra_fc пусто, это означает, что не добавляйте никаких дополнительных линейных слоев, только тот, который у нас должен быть, что дает нам минимальную модель.

Есть ли какое-то конкретное значение p, которое мы должны использовать по умолчанию? Для первого слоя у нас есть p=0.25, а для второго уровня у нас есть p=0.5, которое, похоже, работает для большинства вещей. Если вы обнаружите, что переобучение, продолжайте увеличивать это, скажем, до 0,2. Если недостаточно, уменьшите его.

ResNet34 имеет меньше параметров, поэтому он не слишком подходит, но для более крупной архитектуры, такой как ResNet50, вам часто нужно увеличивать отсев.

Есть ли какой-то особый способ определить, не переоборудован ли он? Да, вы можете видеть, что потери при обучении намного ниже, чем потери при проверке. Вы не можете сказать, слишком ли переоборудован. Нулевое переоснащение обычно не является оптимальным. Единственное, что вы пытаетесь сделать, - это снизить потери при проверке, поэтому вам нужно поиграть с некоторыми вещами и посмотреть, что делает потери при проверке низкими.

Почему важна средняя активация? Если мы удалим половину активаций, следующая активация, которая принимает их в качестве входных данных, также будет уменьшена вдвое, и все после этого. Например, пушистые ушки будут пушистыми, если активация больше 0,6, а теперь пушистыми будут только если больше 0,3, что меняет смысл. Цель здесь - удалить активации без изменения смысла.

Можно ли иметь разный уровень отсева по слоям? Да, поэтому он называется ps, и мы можем передавать массив: ps =[0.1,0.2]

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

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

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

Структурированные данные и данные временных рядов

В данных есть два типа столбцов:

Категориальный - имеет ряд «уровней», например StoreType, Assortment

Непрерывный - у него есть число, в котором разница или соотношение этого числа имеет какое-то значение. например CompetitionDistance

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

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

Такие числа, как year, month и day, хотя мы можем рассматривать их как непрерывные, нам не обязательно. когда мы решаем сделать что-то категоричным, мы говорим нейронной сети обрабатывать каждый уровень по-разному. Но когда говорят, что он непрерывен, мы говорим ему придумать плавную функцию, которая бы соответствовала им.

Очень часто вещи, которые на самом деле являются непрерывными, но не имеют большого количества отдельных уровней (например, Year, DayOfWeek), часто лучше рассматривать их как категориальные. Ведь каждый день может вести себя качественно иначе.

Мы можем сказать, какие переменные являются категориальными, а какие - непрерывными, это решение моделирования, которое вы должны принять.

Если что-то закодировано в ваших данных как «a, b, c», вы должны называть это категориальным, если оно начинается как непрерывное, вы должны выбрать, рассматривать ли это как категориальное или непрерывное.

Обратите внимание, что непрерывные переменные - это действительные числа с плавающей запятой. Плавающие числа имеют много уровней, то есть имеют высокую мощность, например мощность DayOfWeek равна 7.

Вы когда-нибудь объединяете непрерывные переменные? На данный момент нет, но мы могли бы сделать, скажем, Max_Temperature, сгруппировать их в 0–10, 10–20, 20–30 и называть это категориальным. Группа исследователей обнаружила, что иногда может быть полезно объединение в группы.

Если вы используете год в качестве категории, что произойдет, если модель встретит год, которого она никогда раньше не видела? Он будет рассматриваться как неизвестная категория. У Pandas есть особая категория под названием «unknown», и если он видит категорию, которую не видел раньше, она считается неизвестной.

Если в нашем наборе обучающих данных нет категорий, но в ходе тестирования неизвестно, что будет делать модель, будет ли она предсказывать? Он будет частью неизвестной категории, он все равно будет предсказывать, что он обработает значение 0, стоящее за видимым, если в обучающем наборе есть неизвестные, он научится предсказывать с ними, если нет, он не будет иметь случайный вектор.

n = len(joined); n
844338

У нас есть 844338 строк, которые представляют собой даты в каждом магазине.

Прокрутите cat_vars и превратите соответствующие столбцы фрейма данных в столбцы по категориям.

Пройдите через contin_vars и установите их как float32 (32-битная плавающая точка), потому что это то, что ожидает PyTorch. например Promo, SchoolHoliday

Начать с образца

Мы склонны начинать с небольшой выборки из набора данных. Для изображений это будет означать изменение размера изображения до 64 x 64 или 128 x 128. Но со структурированными данными мы начинаем со случайной выборки строк.

Таким образом, мы получаем 150000 строк данных для начала.

Глядя на данные:

Несмотря на то, что мы установили некоторые столбцы как «категория», например ‘StoreType’, ‘Year’. Это было внутренне сохранено, Панды по-прежнему отображаются в виде строки в записной книжке.

proc_df (кадр данных процесса) - это быстрая AI-функция, которая:

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

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

nas Он также обрабатывает пропущенные значения, для категориальной переменной она становится ID: 0, а другие категории становятся 1, 2, 3 и так далее. Для непрерывной переменной он заменяет отсутствующее значение на медиану и создает новый столбец с логическим значением, в котором указано, пропало оно или нет.

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

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

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

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

Собираем нашу модель

Важно, чтобы у вас было четкое представление о своей метрике, то есть о том, как вас будут оценивать. В этом соревновании нас будут оценивать по среднеквадратичной процентной ошибке (RMSPE).

Это означает, что мы берем фактическую продажу за вычетом прогнозируемого значения одного прогноза, находим ее процент, а затем находим среднее значение.

Когда вы ведете журнал данных, получение среднеквадратичной ошибки фактически даст вам среднеквадратичную ошибку в процентах:

Мы можем создать объект ModelData прямо из фрейма данных:

md = ColumnarModelData.from_data_frame(PATH, val_idx, df, 
         yl.astype(np.float32), cat_flds=cat_vars, bs=128, 
         test_df=df_test)

Мы начнем с создания объекта данных модели md, который имеет встроенный набор проверки, обучающий набор и дополнительный набор тестов. Из этого мы получим ученика, затем, при желании, вызовем lr_find, затем вызовем learn.fit и так далее.

Разница в том, что мы не используем ImageClassifierData.from_csv или from_paths, нам нужен другой тип данных модели, называемый ColumnarModelData, и мы вызываем from_data_frame.

Path указывает, где хранить файл модели и т. Д.

val_idx список индексов строк, которые мы добавим в набор проверки.

df фрейм данных независимые переменные.

yl зависимая переменная, которая представляет собой журнал y, возвращенный proc_df, т.е. yl = np.log(y)

cat_flds указывает, какие вещи вы хотите рассматривать как категориальные. Все было преобразовано в число, если мы не укажем, все они будут считаться непрерывными. передать список имен cat_vars

bs размер партии

Теперь у нас есть объект данных стандартной модели, который содержит train_dl, val_dl, train_ds, val_ds и т. Д.

Создание обучаемого, подходящего для данных нашей модели:

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars),
                   0.04, 1, [1000,500], [0.001,0.01], 
                   y_range=y_range)
  • 0.04: сколько отсева использовать в самом начале
  • [1000,500]: сколько активаций иметь на каждом слое
  • [0.001,0.01]: сколько отсева использовать на более поздних уровнях
  • emb_szs вложения

Вложения

Давайте на мгновение оставим категориальные переменные в стороне и посмотрим на непрерывные переменные:

Вы никогда не захотите помещать ReLU на последний уровень, потому что softmax требует негативов для создания низкой вероятности.

Простой вид полностью подключенного слоя:

Принимает входные данные в качестве тензора первого ранга, пропускает его через линейный слой (матричный продукт), через активацию (ReLu), снова линейный слой, затем softmax и, наконец, выход. Мы можем добавить больше линейных слоев или выпадать.

Пропустите softmax для проблем с регрессией.

Категориальные переменные

Мы создаем новую матрицу из 7 строк и столько столбцов, сколько выберем, например, 4 и заполняем ее плавающими числами. Чтобы добавить «воскресенье» к нашему тензору ранга 1 с непрерывными переменными, мы просматриваем эту матрицу, которая возвращает 4 плавающих числа, и мы используем их как «воскресенье».

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

Матрица внедрения - это то, с чего мы начинаем с целого числа от нуля до максимального количества уровней этой категории. Мы индексируем матрицу, чтобы найти конкретную строку, и мы добавляем ее ко всем нашим непрерывным переменным, и все после этого точно так же, как и раньше (linear → ReLU → linear и т. Д.).

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

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

Выше приведен список всех категориальных переменных и их количество элементов.

У нас есть 7 дней в неделе, но если посмотреть на DayOfWeek количество элементов, равное 8, добавляется дополнительная мощность на случай, если в тестовом наборе есть неизвестное, разделите это на 2, то есть 4 случайных числа. Даже если в исходных данных не было пропущенных значений, вы все равно должны на всякий случай отложить одно значение для неизвестного. Года тоже 3, но мы добавляем еще один для неизвестного e.t.c

Эмпирическое правило для определения размера встраивания - это количество элементов, деленное на 2, но не более 50.

При просмотре магазина у нас будет 1116 магазинов для поиска, которые возвращают тензор первого ранга длины 50. Мы должны построить матрицу вложения для каждой категориальной переменной.

Затем мы передаем размеры внедрения emb_szs в get_learner, который сообщает учащемуся, что для каждой категориальной переменной встраивание следует использовать для этой переменной.

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars),
 0.04, 1, [1000,500], [0.001,0.01], y_range=y_range)
m.summary()

Есть ли способ инициализировать матрицы внедрения помимо случайного? Основная идея заключается в том, что если кто-то еще в Rossmann уже обучил нейронную сеть прогнозированию продаж сыра, вы также можете начать с их встраивания матрицы магазинов для прогнозирования продаж спиртных напитков. Так происходит, например, в Pinterest и Instacart. Instacart использует этот метод для маршрутизации своих покупателей, а Pinterest использует его для принятия решения о том, что отображать на веб-странице. У них есть встраиваемые матрицы продуктов / магазинов, которые используются в организации, поэтому людям не нужно обучать новые.

В чем преимущество использования встраиваемых матриц по сравнению с однократным горячим кодированием? В приведенном выше примере дня недели вместо 4 чисел мы могли бы легко передать 7 чисел, например [0, 1, 0, 0, 0, 0, 0] для воскресенья. Это также список чисел с плавающей запятой, и он будет полностью работать, и именно так, вообще говоря, категориальные переменные использовались в статистике в течение многих лет, называемых «фиктивными переменными». Проблема в том, что понятие воскресенья может быть связано только с одним числом с плавающей запятой. Итак, он получает такое линейное поведение, он говорит, что воскресенье - это более или менее единое целое. С вложениями воскресенье - это концепция в четырехмерном пространстве. Что происходит, так это то, что эти векторы внедрения стремятся получить эти богатые семантические концепции. Например, если выясняется, что у выходных другое поведение, вы склонны видеть, что суббота и воскресенье будут иметь какое-то конкретное число выше или, например, определенные дни недели, как правило, связаны с более высокими продажами, например, покупка спиртных напитков в пятницу.

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

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

Подходят ли вложения для определенных типов переменных? Встраивание подходит для любых категориальных переменных. Единственное, в чем он не может хорошо работать, - это что-то со слишком высокой мощностью. Если у вас 600 000 строк, а у переменной 600 000 уровней, это просто бесполезная категориальная переменная. Но в целом третий победитель в этом конкурсе действительно решил, что все, что не слишком большой мощности, они все ставят как категоричные. Хорошее практическое правило состоит в том, что если вы можете создать категориальную переменную, вы также можете сделать это, потому что таким образом она может изучить это богатое распределенное представление; где еще, если вы оставите его непрерывным, максимум, что он может сделать, - это попытаться найти единую функциональную форму, которая хорошо ей подходит.

Как матричная алгебра работает за кадром:

Выполнение поиска идентично выполнению матричного произведения между вектором с горячим кодированием и матрицей внедрения.

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

Не могли бы вы коснуться использования даты и времени как категориального и как это влияет на сезонность? Следующее извлекает определенные поля даты из полного datetime с целью построения категорий. Вы должны всегда учитывать этот шаг извлечения функции при работе с датой и временем. Без расширения даты и времени в этих дополнительных полях вы не сможете зафиксировать какие-либо тенденции / циклическое поведение как функцию времени на любой из этих уровней детализации. Мы добавим в каждую таблицу поле даты.

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

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

Это отличный способ работать с временными рядами. Вам просто нужно убедиться, что индикатор цикла в вашем временном ряду существует в виде столбца. Если бы у вас не было столбца с названием день недели, нейронной сети было бы очень сложно научиться разделите мод на семь и найдите матрицу вложения. Это не невозможно, но очень сложно.

Например, если вы прогнозируете продажи напитков в Сан-Франциско, вам, вероятно, нужен список, когда в парке AT&T идет игра с мячом, потому что это повлияет на количество людей, пьющих пиво в SoMa. Итак, вам нужно убедиться, что основные индикаторы или периодичность есть в ваших данных, и пока они есть, нейронная сеть будет учиться их использовать.

Ученик

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars),
                   0.04, 1, [1000,500], [0.001,0.01], y_range=y_range)
m.summary()

emb_szs размер вложения

len(df.columns)-len(cat_vars) количество непрерывных переменных во фрейме данных.

0.04 матрица внедрения имеет собственное выпадение, и это показатель отсева.

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

[1000, 500] количество активаций в первом линейном слое и втором линейном слое.

[0.001,0.01] выпадение в первом линейном слое и втором линейном слое.

У нас есть более компактный, давайте найдем скорость обучения (lr = 1e-3):

Соответствовать

начнем с образца данных:

metrics это настраиваемая метрика, которая определяет функцию exp_rmspe, которая вызывается в конце каждой эпохи и выводит результат.

подходят все данные:

m.fit(lr, 1, metrics=[exp_rmspe], cycle_len=1)
[ 0.       0.00676  0.01041  0.09711]

Используя все данные обучения, мы получаем RMSPE 0,09711. Это позволило бы нам попасть в верхний% таблицы лидеров.

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

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

Используем ли мы какие-либо временные ряды в любом из них? Косвенно, да. Как мы только что видели, в наших столбцах есть DayOfWeek, MonthOfYear и т. Д., И большинство из них обрабатываются как категории, поэтому мы строим распределенное представление января, воскресенья и так далее. Мы не используем никаких классических методов временных рядов, все, что мы делаем, - это два полностью связанных слоя в нейронной сети. Матрица встраивания может обрабатывать такие вещи, как периодичность дня недели, более богатым способом, чем любые стандартные методы временных рядов.

В чем разница между имиджевыми моделями и этой моделью? Есть разница в способе вызова get_learner. При визуализации мы просто сделали Learner.trained и передали данные:

learn = ConvLearner.pretrained(arch, data, ps=0., precompute=True)

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

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars), 0.04, 1,
                   [1000,500], [0.001,0.01], y_range=y_range)

Шаги

Шаг 1. Перечислите категориальные имена переменных и перечислите непрерывные имена переменных и поместите их в фреймворк Pandas:

cat_vars = ['Store', 'DayOfWeek', 'Year', 'Month', 'Day', 'StateHoliday', 'CompetitionMonthsOpen',
    'Promo2Weeks', 'StoreType', 'Assortment', 'PromoInterval', 'CompetitionOpenSinceYear', 'Promo2SinceYear',
    'State', 'Week', 'Events', 'Promo_fw', 'Promo_bw', 'StateHoliday_fw', 'StateHoliday_bw',
    'SchoolHoliday_fw', 'SchoolHoliday_bw']
contin_vars = ['CompetitionDistance', 'Max_TemperatureC', 'Mean_TemperatureC', 'Min_TemperatureC',
   'Max_Humidity', 'Mean_Humidity', 'Min_Humidity', 'Max_Wind_SpeedKm_h', 
   'Mean_Wind_SpeedKm_h', 'CloudCover', 'trend', 'trend_DE',
   'AfterStateHoliday', 'BeforeStateHoliday', 'Promo', 'SchoolHoliday']

Шаг 2. Создайте список индексов строк, которые вы хотите включить в набор проверки:

val_idx = np.flatnonzero(
    (df.index<=datetime.datetime(2014,9,17)) & (df.index>=datetime.datetime(2014,8,1)))

Шаг 3. Назовите эту точную строку кода:

md = ColumnarModelData.from_data_frame(PATH, val_idx, df, 
         yl.astype(np.float32), cat_flds=cat_vars, bs=128, 
         test_df=df_test)

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

emb_szs = [(c, min(50, (c+1)//2)) for _,c in cat_sz]
emb_szs
[(1116, 50),
 (8, 4),
 (4, 2),
 (13, 7),
 (32, 16),
 (3, 2),
 (26, 13),
 (27, 14),
 (5, 3),
 (4, 2),
 (4, 2),
 (24, 12),
 (9, 5),
 (13, 7),
 (53, 27),
 (22, 11),
 (7, 4),
 (7, 4),
 (4, 2), ...

Шаг 5. Вызовите get_learner - вы можете использовать эти точные параметры для начала, если он вам больше подходит, вы можете поиграть с ними.

m = md.get_learner(emb_szs, len(df.columns)-len(cat_vars), 0.04, 1,
                   [1000,500], [0.001,0.01], y_range=y_range)

Шаг 6. Звоните m.fit

m.fit(lr, 3, metrics=[exp_rmspe])

Как использовать расширение данных для этого типа данных и как работает отсев? Понятия не имею. Может быть, это должно быть предметно-ориентированное, но он (Джереми) никогда не видел ни одной статьи или кого-либо в отрасли, занимающегося увеличением данных с помощью структурированных данных и глубокого обучения. Он думает, что это можно сделать, но не видел, чтобы это было сделано. То, что делает выпавший из школы, - это сбрасывать половину активации тензора первого ранга. Что также относится к матрице вложения.

В чем обратная сторона? Практически никто этим не пользуется. Почему нет? По сути, ответ таков: никто в академических кругах не работает над этим, потому что это не то, что люди публикуют. В результате не было действительно хороших примеров, на которые люди могли бы взглянуть и сказать: «О, вот метод, который хорошо работает, давайте пусть наша компания внедрит его». Но, что, возможно, не менее важно, до сих пор с этой библиотекой Fast.ai не было никакого удобного способа сделать это. Если вы хотели реализовать одну из этих моделей, вам приходилось писать весь собственный код самостоятельно. Теперь это 6-ступенчатый процесс. Есть много больших коммерческих и научных возможностей использовать это и решать проблемы, которые ранее не решались очень хорошо.

Обработка естественного языка

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

Одна из вещей, которые вы обнаружите в НЛП, - это определенные проблемы, которые вы можете решить, и у них есть определенные названия. В НЛП существует особый вид проблемы, называемый «языковое моделирование» - это означает построение модели на основе нескольких слов предложения, чтобы предсказать, каким будет следующее слово.

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

Для этого упражнения мы загрузили документы за 18 месяцев с arXiv.org.

Данные:

<cat> - категория статьи. CSNI - это компьютерные науки и сети.

<summ> - автореферат статьи.

Давайте посмотрим на результат обученной языковой модели, которой мы передаем категорию, в данном случае csni (информатика и сети), и некоторый вводный текст:

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

Модель не только хорошо научилась писать по-английски, но и после того, как вы произнесете что-то вроде «сверточная нейронная сеть», она использует скобки для обозначения аббревиатуры «(CNN)».

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

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

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

Почему непосредственное выполнение того, что вы хотите, не работает лучше? Просто выяснилось, что эмпирически это не дает результатов. Причин несколько. Прежде всего, мы знаем, что тонкая настройка предварительно обученной сети действительно эффективна. Так что, если мы сможем сначала научить его некоторым связанным задачам, то мы сможем использовать всю эту информацию, чтобы попытаться помочь ему во второй задаче. Другая причина в том, что обзоры фильмов на IMDB содержат до 1000 слов. Итак, после прочтения 1000 слов (целых чисел), ничего не зная о структуре английского языка или концепции слова или пунктуации, все, что вы получаете, - это 1 или 0 (положительный или отрицательный). Пытаться выучить всю структуру английского языка, а затем то, как он выражает положительные и отрицательные настроения из одного числа, - слишком многого ожидать. Создавая языковую модель, мы сначала создаем нейронную сеть, которая понимает английский язык обзора фильмов, а затем мы надеемся, что полученные знания помогут решить, является ли отзыв положительным или отрицательным.

Это похоже на Char-RNN от Karpathy? Это несколько похоже на Char-RNN, который предсказывает следующую букву, учитывая количество предыдущих букв. Языковые модели обычно работают на уровне слов, но это не обязательно, и мы сосредоточимся на моделировании на уровне слов.

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

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

Примеры классификации текста:

  1. Хедж-фонд может выявлять в статьях или Твиттере вещи, которые в прошлом вызвали массовые падения рынка.
  2. Распознавание запросов в службу поддержки, которые, как правило, связаны с людьми, которые отменяют свои подписки в следующем месяце.
  3. Классификация документов на предмет того, являются ли они частью юридического открытия или нет.

IMDB

Импорт

torchtext Библиотека НЛП PyTorch.

Данные

Большой набор данных по просмотрам фильмов содержит коллекцию из 50 000 обзоров от IMDB. Набор данных содержит четное количество положительных и отрицательных отзывов. Авторы рассматривали только сильно поляризованные обзоры. Отрицательный отзыв имеет оценку ≤ 4 из 10, а положительный отзыв имеет балл ≥ 7 из 10. Нейтральные отзывы не включаются в набор данных. Набор данных разделен на обучающий и тестовый наборы. В обучающей выборке те же 25000 размеченных обзоров.

Задача классификации тональности состоит в прогнозировании полярности (положительной или отрицательной) данного текста.

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

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

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

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

Ознакомьтесь с примером обзора фильма:

Давайте проверим, сколько слов в наборе обучающих и тестовых данных соответственно:

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

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

Мы используем библиотеку torchtext Pytorch для предварительной обработки наших данных, сообщая ему использовать просторную библиотеку для обработки токенизации.

Создать поле

Сначала мы создаем поле torchtext field, в котором описывается, как предварительно обработать фрагмент текста - в этом случае мы говорим torchtext, чтобы он делал все в нижнем регистре и токенизировал его с пространством.

TEXT = data.Field(lower=True, tokenize="spacy")

lower=True - строчная буква текста

tokenize=spacy_tok - токенизировать с spacy_tok

Мы создаем объект ModelData для языкового моделирования, используя LanguageModelData, передавая ему наш объект поля torchtext и пути к нашим обучающим, тестовым и проверочным наборам. В этом случае у нас нет отдельного набора тестов, поэтому мы просто будем использовать VAL_PATH и для этого.

bs=64; bptt=70
FILES = dict(train=TRN_PATH, validation=VAL_PATH, test=VAL_PATH)
md = LanguageModelData.from_text_files(PATH, TEXT, **FILES, bs=bs, bptt=bptt, min_freq=10)

PATH где данные, куда сохранять модели и т. Д.

TEXT Определение поля torchtext для предварительной обработки текста.

**FILES список всех файлов, которые у нас есть: обучение, проверка и тестирование

bs размер партии

bptt Назад во времени. Это означает, сколько предложений мы будем держать на GPU сразу

min_freq=10: Через мгновение мы собираемся заменить слова целыми числами, то есть уникальным индексом для каждого слова. Если какие-то слова встречаются менее 10 раз, просто назовите их неизвестными.

После создания нашего объекта ModelData он автоматически заполняет объект TEXT очень важным атрибутом: TEXT.vocab. Это словарь, в котором хранится, какие слова (или токены) были замечены в тексте и как каждое слово будет сопоставлено с уникальным целочисленным идентификатором. Нам понадобится снова использовать эту информацию позже, поэтому мы ее сохраняем.

(Техническое примечание: стандартная Pickle библиотека python не может справиться с этим правильно, поэтому в верхней части этой записной книжки мы использовали библиотеку dill и импортировали ее как pickle).

Это начало преобразования целочисленных идентификаторов в уникальные токены:

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

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

При работе с естественным языком контекст не важен? Почему мы токенизируем и смотрим на отдельные слова? Нет, мы не рассматриваем отдельные слова - они пока в порядке. Просто потому, что мы заменили I на число 12, они все еще находятся в том же порядке.

Есть другой способ работы с естественным языком, называемый «мешком слов», который отбрасывает порядок и контекст. В курсе машинного обучения мы узнаем о работе с набором представлений слов, но они больше не являются полезными или близки к тому, чтобы стать бесполезными. Мы начинаем изучать, как использовать глубокое обучение для правильного использования контекста.

Размер партии и обратное продвижение по времени ( BPTT)

В языковой модели происходит то, что, несмотря на то, что у нас много обзоров фильмов, все они объединяются в один большой блок текста. Итак, мы предсказываем следующее слово в этой огромной длинной вещи, которая состоит из объединенных воедино всех обзоров фильмов IMDB.

Мы начинаем с большого блока текста, например, из 64 миллионов слов. Мы разбиваем составные обзоры на группы. В этом случае мы разделим его на 64 раздела. Затем мы перемещаем каждую секцию под предыдущую и транспонируем ее. В итоге мы получаем матрицу размером 1 миллион на 64. Затем мы захватываем небольшой кусок за раз, и длина этого фрагмента приблизительно равна BPTT (это меняется с каждой эпохой). Мы берем небольшой отрезок длиной 70, и это первое, что мы добавляем в наш графический процессор, то есть пакет.

Наш объект LanguageModelData создаст пакеты с 64 столбцами (это наш размер пакета) и различной длиной последовательности около 80 токенов (это наш параметр bptt - обратное распространение во времени).

Каждый пакет также содержит те же данные, что и метки, но на одно слово позже в тексте, поскольку мы всегда пытаемся предугадать следующее слово. Метки объединены в 1d-массив.

Мы получаем наш первый обучающий пакет, упаковывая загрузчик данных (md.trn_dl) в iter, а затем вызывая next

Мы возвращаем тензор 77 на 64, что составляет примерно 70 строк, но не совсем.

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

77 - это первые 77 слов первого обзора фильма.

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

Создание модели

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

4602 количество партий

34945 количество уникальных токенов в vocab (уникальные слова должны встречаться не менее 10 раз min_freq=10, иначе они будут заменены на Unk)

1 длина набора данных, то есть всего корпуса

20621966 количество слов в корпусе.

34945 используется для создания матрицы встраивания:

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

Нам нужно установить ряд параметров:

em_sz = 200  # size of each embedding vector
nh = 500     # number of hidden activations per layer
nl = 3       # number of layers

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

Обычно размер встраивания для слова составляет от 50 до 600.

Исследователи обнаружили, что большие количества импульса не работают с такими моделями RNN (рекуррентные нейронные сети), поэтому мы создаем версию модели Adam оптимизатор с меньшим импульсом, чем по умолчанию 0.9.

opt_fn = partial(optim.Adam, betas=(0.7, 0.99))

Fastai использует вариант современной языковой модели AWD LSTM, разработанный Стивеном Мерити. Ключевой особенностью этой модели является то, что она обеспечивает отличную регуляризацию посредством Dropout. Неизвестно (пока!) Простого способа найти наилучшие значения параметров отсева ниже - вам просто нужно поэкспериментировать ...

Однако другие параметры (alpha, beta и clip) обычно не нуждаются в настройке.

Если вы пытаетесь построить модель НЛП, и вы не подходите, то уменьшите все эти отсевы, если переобучаете, затем увеличьте все эти отсевы примерно в этом соотношении.

Есть и другие способы избежать переобучения. На данный момент learner.reg_fn = partial(seq2seq_reg, alpha=2, beta=1) работает надежно, поэтому всем вашим моделям НЛП, вероятно, нужна именно эта линия.

learner.clip=0.3 когда вы смотрите на свои градиенты, умножаете их на скорость обучения и решаете, на сколько обновлять свои веса, это не позволит им быть больше 0,3. Не дает нам делать слишком большие шаги (высокая скорость обучения).

Есть встраивание слов, например Word2vec или GloVe. Чем они отличаются от этого? И почему бы не инициализировать веса с ними изначально? Люди предварительно обучили эти матрицы внедрения перед выполнением различных других задач. Их не называют предварительно обученными моделями; это просто предварительно обученная матрица встраивания, которую вы можете скачать. Нет причин, по которым мы не могли их загрузить. Построение целой предварительно обученной модели таким образом, похоже, не принесло большой пользы, если вообще принесло пользу от использования предварительно обученных векторов слов; где еще использование целой предварительно обученной языковой модели имело гораздо большее значение. Может быть, мы сможем объединить и то, и другое, чтобы сделать их еще немного лучше.

Какова архитектура модели? Это рекуррентная нейронная сеть, использующая так называемый LSTM ( Долгосрочная краткосрочная память).

Примерка модели

learner.fit(3e-3, 4, wds=1e-6, cycle_len=1, cycle_mult=2)
learner.save_encoder('adam1_enc')
learner.load_encoder('adam1_enc')
learner.fit(3e-3, 1, wds=1e-6, cycle_len=10)

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

learner.save_encoder('adam3p=0.99 enc')
learner.load_encoder('adam3p=0.99 enc')

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

math.exp(4.165)
64.3926824434624
pickle.dump(TEXT, open(f'{PATH}models/TEXT.pkl','wb'))

Тестирование

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

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

Давайте посмотрим, какие 10 лучших прогнозов были для следующего слова после нашего короткого текста:

Посмотрим, сможет ли наша модель сама генерировать немного больше текста:

Анализ настроений

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

TEXT = pickle.load(open(f'{PATH}models/TEXT.pkl','rb'))

sequential=False сообщает torchtext, что текстовое поле должно быть токенизировано (в этом случае мы просто хотим сохранить «положительную» или «отрицательную» одиночную метку).

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

splits - это метод torchtext, который создает наборы для обучения, тестирования и проверки. Набор данных IMDB встроен в torchtext, поэтому мы можем воспользоваться этим. Взгляните на lang_model-arxiv.ipynb, чтобы узнать, как определять свои собственные наборы данных fastai / torchtext.

Разделение позволяет нам просматривать одну метку t.label и часть текста t.text

fastai может создать объект ModelData непосредственно из разбиений torchtext, которые мы можем тренировать на md2:

get_model дает нам нашего ученика, а затем мы можем загрузить в него предварительно обученную языковую модель m3.load_encoder(f’adam3_10_enc’).

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

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

В недавней статье Брэдбери и др. Изучение перевода: контекстуализированные векторы слов содержится удобное резюме последних академических исследований по решению этой проблемы анализа настроений IMDB. Многие из последних показанных алгоритмов настроены для решения этой конкретной проблемы.

Как видите, мы только что получили новый результат в области анализа настроений, уменьшив ошибку с 5,9% до 5,5%! Вы должны быть в состоянии получить аналогичные результаты мирового уровня по другим задачам классификации НЛП, используя те же основные шаги.

Есть много возможностей улучшить это:

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

Мы также можем комбинировать это с предварительно обученными векторами слов.

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

Совместная фильтрация

Данные:

Данные объектива фильма

Http://files.grouplens.org/datasets/movielens/ml-latest-small.zip

path='data/ml-latest-small/'

Он содержит userId фильм movieId rating и timestamp

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

Давайте также прочитаем названия фильмов:

Мы создадим (в следующем уроке) своего рода кросс-таблицу пользователей по фильмам:

Спасибо за чтение! подписывайтесь на @itsmuriuki.

Вернемся к обучению!