Используйте встраивание документов в BigQuery для задач схожести документов и кластеризации

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

Затем скопируйте и вставьте запросы из моей записной книжки в GitHub. Вы можете опробовать запросы в консоли BigQuery или в блокноте AI Platform Jupyter.

Данные отчетов о шторме

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

SELECT 
  EXTRACT(DAYOFYEAR from timestamp) AS julian_day,
  ST_GeogPoint(longitude, latitude) AS location,
  comments
FROM `bigquery-public-data.noaa_preliminary_severe_storms.wind_reports`
WHERE EXTRACT(YEAR from timestamp) = 2019
LIMIT 10

Результат выглядит так:

Допустим, мы хотим создать SQL-запрос для поиска комментариев, которые выглядят как «отключение линии электропередачи в доме».

Шаги:

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

Загрузка модели встраивания текста в BigQuery

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

Для этой демонстрации я буду использовать вложение Swivel, которое было обучено в Новостях Google и имеет 20 измерений (то есть довольно грубо). Этого достаточно для того, что нам нужно сделать.

Слой встраивания Swivel уже доступен в формате TensorFlow SavedModel, поэтому нам просто нужно его загрузить, извлечь из tar-архива, сжатого gzip-файла и загрузить в Google Cloud Storage:

FILE=swivel.tar.gz
wget --quiet -O tmp/swivel.tar.gz  https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1?tf-hub-format=compressed
cd tmp
tar xvfz swivel.tar.gz
cd ..
mv tmp swivel
gsutil -m cp -R swivel gs://${BUCKET}/swivel

После того, как файлы модели находятся в GCS, мы можем загрузить их в BigQuery как модель машинного обучения:

CREATE OR REPLACE MODEL advdata.swivel_text_embed
OPTIONS(model_type='tensorflow', model_path='gs://BUCKET/swivel/*')

Попробуйте встраивание модели в BigQuery

Чтобы опробовать модель в BigQuery, нам нужно знать ее схему ввода и вывода. Это будут имена слоев Keras при экспорте. Мы можем получить их, перейдя в консоль BigQuery и просмотрев вкладку «Схема» модели:

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

SELECT output_0 FROM
ML.PREDICT(MODEL advdata.swivel_text_embed,(
SELECT "Long years ago, we made a tryst with destiny; and now the time comes when we shall redeem our pledge, not wholly or in full measure, but very substantially." AS sentences))

В результате, как и ожидалось, 20 чисел, первые несколько из которых показаны ниже:

Поиск сходства документов

Определите функцию для вычисления евклидова квадрата расстояния между парой вложений:

CREATE TEMPORARY FUNCTION td(a ARRAY<FLOAT64>, b ARRAY<FLOAT64>, idx INT64) AS (
   (a[OFFSET(idx)] - b[OFFSET(idx)]) * (a[OFFSET(idx)] - b[OFFSET(idx)])
);
CREATE TEMPORARY FUNCTION term_distance(a ARRAY<FLOAT64>, b ARRAY<FLOAT64>) AS ((
   SELECT SQRT(SUM( td(a, b, idx))) FROM UNNEST(GENERATE_ARRAY(0, 19)) idx
));

Затем вычислите вложение для нашего поискового запроса:

WITH search_term AS (
  SELECT output_0 AS term_embedding FROM ML.PREDICT(MODEL advdata.swivel_text_embed,(SELECT "power line down on a home" AS sentences))
)

и вычислим расстояние между встраиванием каждого комментария и term_embedding поискового запроса (см. выше):

SELECT
  term_distance(term_embedding, output_0) AS termdist,
  comments
FROM ML.PREDICT(MODEL advdata.swivel_text_embed,(
  SELECT comments, LOWER(comments) AS sentences
  FROM `bigquery-public-data.noaa_preliminary_severe_storms.wind_reports`
  WHERE EXTRACT(YEAR from timestamp) = 2019
)), search_term
ORDER By termdist ASC
LIMIT 10

Результат:

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

Кластеризация документов

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

CREATE OR REPLACE MODEL advdata.storm_reports_clustering
OPTIONS(model_type='kmeans', NUM_CLUSTERS=10) AS
SELECT
  arr_to_input_20(output_0) AS comments_embed,
  EXTRACT(DAYOFYEAR from timestamp) AS julian_day,
  longitude, latitude
FROM ML.PREDICT(MODEL advdata.swivel_text_embed,(
  SELECT timestamp, longitude, latitude, LOWER(comments) AS sentences
  FROM `bigquery-public-data.noaa_preliminary_severe_storms.wind_reports`
  WHERE EXTRACT(YEAR from timestamp) = 2019
))

Встраивание (output_0) представляет собой массив, но BigQuery ML в настоящее время требует именованных входов. Обходной путь - преобразовать массив в структуру:

CREATE TEMPORARY FUNCTION arr_to_input_20(arr ARRAY<FLOAT64>)
RETURNS 
STRUCT<p1 FLOAT64, p2 FLOAT64, p3 FLOAT64, p4 FLOAT64,
       p5 FLOAT64, p6 FLOAT64, p7 FLOAT64, p8 FLOAT64, 
       p9 FLOAT64, p10 FLOAT64, p11 FLOAT64, p12 FLOAT64, 
       p13 FLOAT64, p14 FLOAT64, p15 FLOAT64, p16 FLOAT64,
       p17 FLOAT64, p18 FLOAT64, p19 FLOAT64, p20 FLOAT64>
AS (
STRUCT(
    arr[OFFSET(0)]
    , arr[OFFSET(1)]
    , arr[OFFSET(2)]
    , arr[OFFSET(3)]
    , arr[OFFSET(4)]
    , arr[OFFSET(5)]
    , arr[OFFSET(6)]
    , arr[OFFSET(7)]
    , arr[OFFSET(8)]
    , arr[OFFSET(9)]
    , arr[OFFSET(10)]
    , arr[OFFSET(11)]
    , arr[OFFSET(12)]
    , arr[OFFSET(13)]
    , arr[OFFSET(14)]
    , arr[OFFSET(15)]
    , arr[OFFSET(16)]
    , arr[OFFSET(17)]
    , arr[OFFSET(18)]
    , arr[OFFSET(19)]    
));

Полученные десять кластеров можно визуализировать в консоли BigQuery:

Как выглядят комментарии в кластере №1? Запрос:

SELECT sentences 
FROM ML.PREDICT(MODEL `ai-analytics-solutions.advdata.storm_reports_clustering`, 
(
SELECT
  sentences,
  arr_to_input_20(output_0) AS comments_embed,
  EXTRACT(DAYOFYEAR from timestamp) AS julian_day,
  longitude, latitude
FROM ML.PREDICT(MODEL advdata.swivel_text_embed,(
  SELECT timestamp, longitude, latitude, LOWER(comments) AS sentences
  FROM `bigquery-public-data.noaa_preliminary_severe_storms.wind_reports`
  WHERE EXTRACT(YEAR from timestamp) = 2019
))))
WHERE centroid_id = 1

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

Как насчет кластера №3? Большинство этих отчетов, кажется, как-то связано с проверкой радаром !!!

Наслаждаться!

Ссылки

TensorFlow Hub имеет несколько моделей встраивания текста. Вам не обязательно использовать Swivel, хотя Swivel - хороший универсальный выбор.

Полные запросы находятся в моей записной книжке на GitHub. Вы можете опробовать запросы в консоли BigQuery или в блокноте AI Platform Jupyter.