Конвейер Dataflow ML: Words -> (Spacy + Sklearn) -> Кластеры

В моем предыдущем блоге мы исследовали кластеризацию предложений с помощью SpaCy, Dataflow ML и BigQuery ML. В этом блоге стратегии векторизации и обработки моделей, основанные на Spacy и Dataflow ML, также остаются в некоторой степени схожими.

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

Итак, в чем разница? На этот раз ядром, выбранным для ноутбука Vertex AI Workbench, является Apache Beam 2.46.0, а не сам Python 3 (ipykernel). Таким образом, это упростит программную загрузку выходных файлов в корзину GCS (Google Cloud Storage) и конвейерный экспорт в виде задания потока данных. Кроме того, мы увидим, что слова сгруппированы, а не предложения в том же конвейере Dataflow ML, и это тоже с использованием другого инструмента и алгоритма кластеризации.

Наш новый гость — Scikit-learn (Sklearn), библиотека, которая давным-давно положила начало моим путешествиям по машинному обучению и НЛП. Мы будем полагаться на кластеризацию Sklearn Birch вместо кластеризации BigQuery ML k-Means, что указывает на переход от метода разделения на иерархический метод кластеризации. Предполагается, что это также упростит демонстрацию последовательного RunInference.

Существуют различные шаблоны обработки моделей, в частности «Последовательность» и «Ветвление». Мы увидим две модели, которые обрабатываются в шаблоне последовательности с помощью «Beam RunInference API» для SpaCy, а также Scikit-Learn. В соответствии с приведенной ниже понятной архитектурной диаграммой мы будем последовательно использовать модели Spacy и Sklearn.

Итак, в конвейере луча захваченные слова CSV-файла векторизируются с помощью SpaCy. Затем эти векторы группируются с использованием кластеризации Sklearn Birch, после чего сообщаются и визуализируются окончательные результаты. Наконец, мы запустим задание потока данных из этого конвейера, созданного в блокноте.

Важность кластеризации слов

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

  1. Улучшена точность поисковой системы
  2. Упрощение анализа текста документа
  3. Более быстрый поиск важной информации

Битва кластеров: Birch против K-Means

Ранее мы обсуждали, чем k-means отличается от своего младшего брата, k-means++. Давайте подробно рассмотрим различия между BIRCH и кластеризацией методом k-средних.

BIRCH (Bсбалансированная Iтеративная Rвыводка и Cлюстрация с использованием Hиерархий) создает иерархию кластеров, начиная с одного кластера, содержащего все точки данных. Затем кластеры многократно разбиваются до тех пор, пока каждый кластер не будет содержать только одну точку данных. С помощью сводки он быстро определяет, какие точки данных, вероятно, принадлежат одному и тому же кластеру. Он быстро определяет, какие точки данных могут принадлежать одному и тому же кластеру, используя сводку.

K-means — один из самых известных алгоритмов машинного обучения, часто называемый «королем кластеризации». Он является секционированным и разделяет точки данных на заранее определенное количество кластеров. Он работает путем многократного распределения точек данных по кластерам, а затем пересчета центров кластеров до тех пор, пока они не изменятся.

Ждать! Хватит жаргона — почему стоит выбрать BIRCH?

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

Практическая реализация

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

1. Предпосылки

Перво-наперво! Сначала выполните эти шаги, прежде чем переходить к построению и выполнению конвейера Dataflow ML:

1.1. Создайте нужный блокнот

Во-первых, мы создадим рабочий стол Apache Beam Vertex AI. Для этого посетите раздел «Поток данных» в консоли GCP. Нажмите «Рабочий стол», а затем «Записные книжки, управляемые пользователями». Теперь, чтобы создать новый блокнот, нажмите знак «+», а затем «Apache Beam» и «Без графических процессоров». Не требующая пояснений процедура также описана визуально ниже.

Указав имя, регион и сеть, нажмите «СОЗДАТЬ», как показано на изображении ниже.

Подождите 2–3 минуты, пока не появится опция «ОТКРЫТЬ JUPYTERLAB».

Нажмите на него, когда он включен, и выберите «Apache Beam 2.46.0 для Python 3» справа. Вы готовы двигаться дальше!

1.2. Установите необходимые пакеты

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

# This is an Apache Beam kernel notebook, not a Python kernel one!
# Apache Beam is pre-installed; Sklearn is not!

%pip install -U spacy
%pip install scikit-learn

# %pip install --quiet apache-beam[gcp,interactive,dataframe]

Необязательно: проверьте, успешно ли установлены пакеты, и если да, проверьте их версию.

! python -m spacy validate # 'Validate' is provided by SpaCy

1.3. Включите соответствующие API

Включите все соответствующие API, такие как облачное хранилище, поток данных и блокнот. Это можно сделать программно или через консоль GCP.

Программный.Gcloud CLI предоставляет интерфейс командной строки на основе терминала для доступа к тем же службам Google Cloud, которыми можно управлять с помощью облачной консоли. Прежде чем использовать это для включения API в коде, сначала проверьте список доступных сервисов.

!gcloud services list

Затем выполните следующие команды, чтобы включить необходимые API.

!gcloud services enable dataflow
!gcloud services enable notebooks.googleapis.com
!gcloud services enable storage-component.googleapis.com

Консоль GCP. После просмотра соответствующих API в консоли GCP нажмите «Включить», как показано ниже для API Notebooks слева.

Повторите шаги для потока данных, а также для API облачного хранилища. Вы должны получить «API Enabled» для всех них, как показано на рисунке выше справа.

1.4. Загрузите необходимые файлы CSV

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

import pandas as pd
train_file = 'Final_Test_Data.csv' # Place 'Final_Train_Data.csv' also.
pd.read_csv(train_file, header=None, names=['Word'])

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

2. Поиграем с моделями

В этом разделе мы начнем работать с моделями SpaCy и Sklearn.

2.1. Загрузите предварительно обученную модель SpaCy

Используется самая большая английская модель SpaCy, имеющая большую таблицу векторов слов (≈ 500 тыс. записей). На этот раз из-за другого ядра модель можно легко установить с помощью интерфейса командной строки SpaCy. Чтобы векторизовать слова, загрузите модель ‘nlp’ следующим образом:

# Remember, the kernel is 'Apache Beam',
# So, install the large English model as follows:

import spacy.cli
spacy.cli.download("en_core_web_lg")
nlp = spacy.load("en_core_web_lg")

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

2.2. Обучение и оценка модели кластеризации Sklearn

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

import csv 

docs = []

with open('Final_Train_Data.csv', mode ='r') as file:
    csvFile = csv.reader(file)
    for word in csvFile:
        docs.append(nlp(word[0]))
print(len(docs))

Модель кластеризации Sklearn обучена w.r.t. эти 111 векторов относятся к четырем категориям: дикая природа, продукты питания, медицина и технологии.

import numpy as np

final_data = []

for i, d in enumerate(docs):
    arr = np.array(list(d.vector))
    clusterarray_vectorized = arr.reshape(1, len(arr))
    clusterarray_vectorized_mean = list(np.mean(clusterarray_vectorized, axis=0))
    temp_row = np.asarray(clusterarray_vectorized_mean)
    final_data.append(temp_row)

Для этого вектор, созданный для каждого слова, преобразуется в массив numpy, и таким образом для кластеризации создается двумерная матрица final_data размером 111 x 300.

from sklearn.cluster import Birch

X = np.asarray(final_data)

brc = Birch(n_clusters=4)
brc.fit(X)

brc.predict(X)

Результаты прогнозирования для обучающего набора данных показывают, что такие слова, как "Животные", "Среда обитания" и "Биоразнообразие", относятся к кластеру 0 для Дикая природа, за которыми следуют 'Шоколад', 'Фрукты', 'Овощи'назначили кластер 3 для Еда, "Эпидемия", "Лихорадка", "Грипп" назначены кластеру 1 для Медицина и, наконец, 'Компьютер', 'Смартфон', 'Планшет' назначаются кластеру 2 для Технологии.

3. Работа с Beam RunInference API

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

3.1. Реализовать обработчик модели SpaCy

Давайте снова определим класс обработчика модели с именем ‘SpacyInfer’, чтобы использовать spaCy для логического вывода. В функции «run_inference» вектор выводится для каждого слова и сохраняется в списке «infers».

import apache_beam
from apache_beam.ml.inference.base import RunInference
from apache_beam.ml.inference.base import ModelHandler
from apache_beam.ml.inference.base import PredictionResult
from apache_beam.runners.interactive.interactive_runner import InteractiveRunner

class SpacyInfer(ModelHandler[str, spacy.Language, PredictionResult]):

      def __init__(self, model_name):
          self._model_name = model_name
      
      def load_model(self):
          return spacy.load(self._model_name)
      
      def run_inference(self, sents, model, inference_args):
          infers = []
          for sent in sents:
              doc = model(sent)
              infers.append(doc.vector)
          return infers

3.2. Реализуйте обработчик модели Scikit-learn

Здесь все необходимые библиотеки импортируются для модели Sklearn для обработки массивов Numpy. Объект модели сохраняется (или «маринуется») путем передачи его в функцию dump() Pickle для сериализации и преобразования в «поток байтов». Файл model.pkl далее вводится в обработчик модели в качестве URI модели.

import pickle
from apache_beam.ml.inference.sklearn_inference import ModelFileType
from apache_beam.ml.inference.sklearn_inference import SklearnModelHandlerNumpy

clustering_file = 'sklearn_birch_clustering_model_final.pkl'

with open(clustering_file, 'wb') as f:
    pickle.dump(brc, f)
    
sklearn_model_handler = SklearnModelHandlerNumpy(model_uri=clustering_file)

4. Запустите конвейер Apache Beam

Пришло время построить и выполнить весь конвейер кластеризации слов. Ура!

4.1. Создайте конвейер

Здесь мы будем полагаться на InteractiveRunner() для итеративной разработки и проверки конвейеров.

pipeline = apache_beam.Pipeline(InteractiveRunner())

4.2. Запустить конвейер

В конвейере первые слова извлекаются из CSV-файла и векторизируются с помощью обработчика модели SpaCy NLP. Затем эти векторы группируются с помощью обработчика модели Sklearn и, наконец, визуализируются.

with pipeline as p:
    spacy_df = p | "FetchWords" >> apache_beam.io.ReadFromText(train_file) 
    spacy_df1 = spacy_df | "RunInferenceSpacy" >> RunInference(SpacyInfer("en_core_web_lg")) 
    sklearn_df = spacy_df1 | "RunInferenceSklearn" >> RunInference(model_handler=sklearn_model_handler)
    sklearn_df1 = sklearn_df | "PrintClusters" >> apache_beam.Map(print)

4.3. Назначение слова кластеру

Результирующее сопоставление слова-кластера можно легко визуализировать, объединив выходные данные Pcollection 'spacy_df' (слова) и 'sklearn_df' (векторы и кластеры).

word_cluster_pd = pd.concat([ib.collect(spacy_df), ib.collect(sklearn_df)], axis=1)
word_cluster_pd.set_axis(['Word', 'Vector', 'Cluster', 'Model_ID'], axis='columns', copy=False)
word_cluster_pd.style

5. Визуализируйте коллекцию PCollection

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

Точно так же выходные данные ‘spacy_df’ и ‘spacy_df1’ можно визуализировать в виде слов и векторов. Также фиксируются все статистические параметры векторов, такие как среднее, медиана, стандартное отклонение и т. д. Не забудьте установить флажок, соответствующий «Визуализировать в аспектах».

Мы можем увидеть, сколько из 196 слов отнесено к кластеру 0, 1, 2 или 3.

Эта визуализация показывает сопоставление слова с кластером. Например, выделенное слово «Google» относится к кластеру 2 для Технологии.

Примечание.С помощью модуля «apache_beam.runners.interactive.interactive_beam» можно получить приведенные выше результаты. Мы стремимся сгенерировать все это с помощью вкладки Interactive Beam, чтобы продемонстрировать ее простоту по сравнению с программным подходом.

6. Запустите задание потока данных

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

from apache_beam.options import pipeline_options
from apache_beam.options.pipeline_options import GoogleCloudOptions
from apache_beam.runners import DataflowRunner
import google.auth

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

options = pipeline_options.PipelineOptions(flags={})
_, options.view_as(GoogleCloudOptions).project = google.auth.default()
options.view_as(GoogleCloudOptions).region = 'us-central1'
!gsutil mb gs://demo-bucket-aa-demo-dataflow

gcs_path = 'gs://demo-bucket-aa-demo-dataflow/DataflowML'
options.view_as(GoogleCloudOptions).staging_location = '%s/staging' % gcs_path
options.view_as(GoogleCloudOptions).temp_location = '%s/temp' % gcs_path

Затем мы можем указать каталог для хранения выходных файлов задания.

output_path = '%s/output' % gcs_path
(sklearn_df | 'Writing clusters to Cloud Storage' 
 >> apache_beam.io.WriteToText(output_path + '/clusters.txt'))

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

from IPython.display import display, HTML

cluster_pipeline = DataflowRunner().run_pipeline(p, options=options)

url = ('https://console.cloud.google.com/dataflow/jobs/%s/%s?project=%s' % 
      (cluster_pipeline._job.location, cluster_pipeline._job.id, cluster_pipeline._job.projectId))
display(HTML('To visualize your Dataflow job, please click <a href="%s" target="_new">here</a>. Enjoy!' % url))

cluster_pipeline.wait_until_finish()

Приложение gsutil на основе Python обеспечивает доступ к GCS из командной строки. Вы можете проверить каталог и содержимое файла, выполнив следующие команды:

!gsutil ls {gcs_path}
!gsutil ls {output_path}
!gsutil cat {output_path}/clusters.txt-00000-of-00001

На следующих снимках экрана показаны виды заданий и показатели:

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

Наблюдение и результаты

Из 196 слов мы можем ясно видеть, что 40, 57, 41 и 58 слов попадают в кластеры 0 ('Дикая природа'), 1 ('Медицина'), 2 ('Технологии') и 3 ('Еда') соответственно. Для такого небольшого набора данных нигде нет ни ложноположительных, ни ложноотрицательных результатов, благодаря чему показатели кластеризации, такие как точность и полнота, поддерживаются на уровне 100%. Конечно, по мере того, как принимаются во внимание большие наборы данных, начинается перетягивание каната между точностью и полнотой, и 100% точность больше не гарантируется.

Проблемы

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

  1. Вирус -> Дикая природа, Технический
  2. Мясо, Рыба, Курица -> Дикая природа, Еда
  3. Рентген -> Технический, Медицинский
  4. Духовка -> Пищевая, Техническая
  5. Таблетка -> Медицинская, Техническая (Еда тоже, как минимум, съедобная :)

Есть и другие проблемы. Чтобы слово было точно помещено в правильный кластер, оно должно быть правильно векторизовано и кластеризовано. Нельзя ожидать, что любая предварительно обученная модель, даже самая большая англоязычная модель SpaCy, будет выводить правильный семантический вектор для каждого слова буквально. Вдобавок к этому, модель Sklearn также будет давать ложноотрицательные и положительные результаты со своего конца. Таким образом, обе эти мощные библиотеки Python будут участвовать в поддержании окончательной точности кластеризации.

Краткое содержание

В этом блоге мы еще раз познакомились с ключевыми функциями Dataflow ML, который определяет следующее поколение своего аналога Dataflow. Мы наблюдали, как модели NLP и ML обрабатывались последовательно, а SpaCy и Sklearn сотрудничали для создания кластеризации векторов слов. Наконец, мы визуализировали все данные конвейера в виде задания потока данных после указания местоположения GCS.

Оставайтесь любопытными, адиос, и до скорой встречи в другом блоге!

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

Ссылка на Google Таблицы:
Набор данных для обучения: https://docs.google.com/spreadsheets/d/1CrB_IpxShZoMe0QzynHsKP7Cix6sDwscvdXJ-trGQ8A/edit?usp=sharing

Набор тестовых данных:
https://docs.google.com/spreadsheets/d/1m7YfjeK3vk6Haq5se9R2HzT406wHT_Gw62sSToK-NeI/edit#gid=1288188311