Авторы: Вибху Джава, Ник Беккер, Дэвид Вендт и Рэнди Гельхаузен

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

Поддержка строк в RAPIDS довольно нова: она появилась чуть более 6 месяцев назад. С тех пор мы сделали реализацию open-source и начали первые фазы интеграции cuDF. С nvtext module мы теперь занимаемся более крупными и сложными строительными блоками обработки текста, которые обеспечивают работу NLP с ускорением на GPU. Хотя мы уже некоторое время можем проводить базовый подсчет слов, полезный анализ реальных текстовых данных включает в себя предварительную обработку, которую мы хотели выполнить прямо перед публикацией примеров.

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

К концу этой публикации вы сможете очистить набор текстовых данных из 19 миллионов строк в 2.3 seconds на одном NVIDIA GV-100 и использовать его для поиска похожих авторов на основе их написания.

Ускоренная обработка текста с помощью графических процессоров

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

  1. Удаление знаков препинания
  2. Нижний или верхний кожух
  3. Удаление стоп-слов
  4. И различные другие задачи, в зависимости от набора данных и приложения.

В нашем примере данные представляют собой коллекцию из 3 036 английских книг от 142 авторов, что является более чистым подмножеством корпуса Project Gutenberg. Каждая книга представляет собой текстовый файл на диске. Чтение 3000 относительно небольших файлов - не идеальный вариант загрузки данных. Что еще хуже, содержимое файла не содержит метаданных названия книги или автора. Таким образом, мы считываем содержимое в список, добавляя имя файла к началу, а затем передаем его графическому процессору в cuDF DataFrame. В то время как read_csv Dask DataFrame поддерживает включение таких метаданных в качестве столбца, cuDF пока не может поддерживать это.

Имея данные в памяти, мы готовы начать предварительную обработку. В зависимости от размера набора данных эти задачи могут занять много времени даже на мощных компьютерах с большим количеством ядер ЦП. И скажите, что вы хотите ускорить этот процесс и перенести свою работу на графический процессор. До появления RAPIDS вам пришлось бы писать много кода CUDA C ++ для обработки этих задач на графическом процессоре. Благодаря cuStrings и его интеграции в cuDF, RAPIDS предоставляет простой и высокоуровневый Python API, знакомый инженерам по данным, специалистам по данным и практикам НЛП. Продемонстрируем это на примере.

Удаление знаков препинания и нижней части корпуса

Рассмотрим строки «эй», «эй!» И «эй». Все они в основном состоят из слова «эй». Независимо от регистра и прикрепленных знаков препинания, вы обычно хотите считать их одним словом.

Сначала удалим знаки препинания. nvtext предоставляет функцию multi string replace, чтобы сделать эту операцию быстрой и простой. Мы даже можем связать это вместе с функцией lower.

Удаление стоп-слов

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

Другие задачи: удаление пробелов переменной длины

Иногда после удаления слов мы можем получить последовательные символы пробелов, которые мы хотим стандартизировать, чтобы не повлиять на наш анализ. Удаление пробелов все еще немного сложнее, чем в идеале. Скоро мы сделаем это лучше с nvtext.normalize_spaces, но пока мы можем использовать регулярное выражение.

Собираем все вместе

Уф, мы закончили с очисткой данных. Выше было много кода, но насколько быстро работает вся эта логика, когда вы все это объединяете? Сравним GV100 с 2- 16-ядерными CPU (64 виртуальных ядра).

Завершая этапы предварительной обработки для всего набора данных из 19 миллионов строк, мы очистили его за 2,31 секунды на одном NVIDIA GV-100. Это в 6 раз быстрее, чем реализация двухъядерного 16-ядерного процессора (64 виртуальных ядра). Хотите попробовать сами? Щелкните здесь, чтобы поэкспериментировать.

Серьезно, покажите мне количество слов!

Перед подсчетом слов нам нужно разбить строки на отдельные токены. Учитывая, что некоторые строки во многих наборах данных длинные (т. Е. Содержат много токенов), можно столкнуться с ситуацией нехватки памяти. Чтобы справиться с этим эффективно, мы создали метод tokenize в nvtext. Он генерирует один столбец всех токенов, используемых во входных строках, что значительно сокращает использование памяти. Он прост в использовании и работает следующим образом:

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

Теперь давайте посчитаем и сравним количество слов у Альберта Эйнштейна и Чарльза Диккенса, чтобы увидеть, найдем ли мы какие-нибудь интересные закономерности.

Эйнштейн говорит о relativity, theory, и body. Диккенс относительно больше заинтересован в том, чтобы рассказывать читателям хорошие истории: once, upon, time и one.

Никого не удивишь.

Поиск похожих авторов с помощью UMAP и KNN

Хорошо, графические процессоры могут быстро обрабатывать текст и считать слова. И что?

В качестве воодушевляющего примера я в старшей школе любил читать детективные рассказы Рэймонда Чендлера «нуар». Несколько лет назад я наткнулся на его статью в Википедии и узнал о его современнике и друге Дэшилле Хэммете. Я быстро прочитал все рассказы Хэммета, которые попадались мне в руки.

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

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

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

Создание векторных кодированных слов

Нам нужно преобразовать ряды подсчета слов непосредственно в векторы подсчета. В конце концов, nvtext будет поддерживать это напрямую, но пока мы покажем, как реализовать это вручную, используя nvcategory и ядро ​​Numba с ускорением на GPU. Мы считаем, что это будет полезно практикующим НЛП, экспериментирующим с пользовательской логикой предварительной обработки, которые не хотят тратить время на Cythonizing или иным образом написание ориентированных на производительность собственных расширений Python.

Мы делаем это в три этапа. Сначала мы подсчитываем количество слов для всех авторов.

Затем мы кодируем серии counts, используя 20 000 наиболее часто встречающихся слов в наборе данных, который мы вычислили ранее. Мы используем nvcategory для этого кодирования.

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

Авторы кластеризации с использованием K-ближайших соседей:

Один из простейших подходов к кластеризации - это K-Nearest Neighbours, и он хорошо работает с только что созданными векторами подсчета. Давайте поместим модель k-ближайших соседей в массив кодирования count и найдем похожего автора:

Давайте найдем ближайших соседей Альберта Эйнштейна

Давайте найдем ближайших соседей к "Чарльзу Диккенсу".

Ближайший сосед «Альберта Эйнштейна» - «Томас Карлайл», который был математиком, но, похоже, ближайший к «Чарльзу Диккенсу» - «Уинстон Черчилль», что не кажется правильным, давайте попробуем это исправить.

Уменьшение размерности с помощью UMAP

Мы находимся в многомерном пространстве с 20,000 измерениями, поэтому ближайший сосед на основе euclidian distance - не лучший путь вперед, как в многомерных пространствах. Давайте попробуем исправить это, уменьшив размерность с помощью Однородной аппроксимации и проекции многообразия (UMAP), которая будет использовать сопоставление наших векторов счета до 3 измерений с использованием cuml.umap.

Давайте поместим модель KNN в набор данных с уменьшенной размерностью

Теперь посмотрим на соседей по этому коллектору.

Соседи Альберта Эйнштейна:

Чарльз Диккенс Соседи:

Итак, в этом скрытом пространстве «Чарльз Диккенс» и «Агата Кристи» - соседи, оба любили писать рассказы.

Заключение

Наша первая запись в блоге о строках была озаглавлена ​​«У реальных данных есть строки, теперь и у графических процессоров». Так было тогда и сейчас. Что изменилось, так это то, что сегодня у нас есть более глубокая поддержка строк, интегрированная в cuDF, что означает, что вы можете смешивать и сопоставлять операции преобразования строк с традиционными табличными сгруппированными агрегатами. У нас также есть модуль nvtext, который обеспечивает более оптимизированную предварительную обработку строк в стиле NLP на графических процессорах, и мы поддерживаем передачу очищенных данных непосредственно в алгоритмы ускорения графического процессора cuML.

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

В этом наборе данных мы увидели ускорение в 24 раза по сравнению с ЦП с 12 виртуальными ядрами и в 6 раз по сравнению с ЦП с 64 виртуальными ядрами при предварительной обработке текста.

Подобные ускорения позволяют специалистам по обработке данных и инженерам тратить больше времени на итерацию разработки функций и больше времени на поиск лучших параметров и гиперпараметров для своих моделей машинного обучения. НЛП - это огромный мир. Зайдите на сайт cuStrings на GitHub и сообщите нам, какие его части вы хотели бы видеть быстрее!

Хотите начать работу с RAPIDS? Загляните в cuDF на Github и поделитесь с нами своим мнением! Вы можете скачать готовые контейнеры Docker для нашей версии 0.8 из NGC или Dockerhub, чтобы начать работу, или установить их самостоятельно через Conda. Нужно что-то еще проще? Вы можете быстро начать работу с RAPIDS в Google Colab и опробовать все новые функции, которые мы добавили, одним нажатием кнопки.

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

Ссылка на блокнот