В машинном обучении существует несколько способов реализовать комплексное решение для одного и того же типа проблемы. Тип проблемы означает контролируемую или неконтролируемую обучающую задачу. В рамках задачи обучения с учителем это может быть линейная или логистическая регрессия для определения непрерывных данных для нашей целевой метки или категории для нашей целевой метки. Существуют и другие типы обучения с учителем, но об этом мы поговорим в другой раз. В этой статье мы исследуем один из способов решения проблемы регрессии от начала до конца. Предположим, что у нас есть данные, загруженные в корзину облачного хранилища Google, и из этих данных впоследствии созданы таблицы, которые можно запрашивать через BigQuery. Теперь давайте продолжим шаг за шагом после того, как запустим нашу записную книжку Jupyter (локально или в облаке). Обратите внимание, что приведенные ниже шаги являются объяснением только одного подхода. Он написан таким образом, что его можно применять к нескольким наборам данных. Запросы и методы написаны в обобщенном виде и, возможно, служат шаблоном регрессии для наборов данных на основе больших запросов. Обобщенный шаблон блокнота можно найти здесь.

Шаг 1:

Импорт библиотек

из облака google импортировать bigquery

импортировать панд как pd

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

Шаг 2:

export PROJECT = $(проект списка конфигураций gcloud — формат «value(core.project)»)

Приведенная выше команда извлекает идентификатор проекта из корзины облачного хранилища Google.

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

bq = bigquery.Client (проект = ПРОЕКТ)

Шаг 3:

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

Есть и другие способы сделать это, и выбор числа может быть изменен в соответствии с желаемым разделением данных. Мы вернемся к вышеупомянутым ведрам позже в этой статье. Значения в том виде, в каком они определены прямо сейчас, теоретически разделят наши данные на 80 % для обучения, 10 % для оценки и 10 % для нашего тестового набора.

Шаг 4:

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

get_df_head(…) по умолчанию отображает первые 10 строк фрейма данных.

Теперь идет некоторая очистка данных и подготовка данных. Следующие несколько шагов являются одними из самых строгих шагов перед построением модели. Мы определяем последовательность операторов SQL (большие запросы). Мы делаем это таким образом, что эти утверждения возвращаются и объединяются в один консолидированный запрос, который в результате будет информировать нас о точности, с которой мы разделили наши данные.

Шаг 5:

Определите столбцы признаков и какие строки мы будем игнорировать или включать в наш набор данных:

Шаг 6:

Выберите объекты для объединения и хеширования с помощью FARM_FINGERPRINT(…)

CONCAT сочетает в себе функции, которые мы выбираем для CAST, а затем хешируем. Мы определили cleanup_query на предыдущих шагах. Приведенный выше запрос создает хеш из результата выполнения cleanup_query. Таким образом, мы можем видеть каскадное наращивание нашего запроса настройки данных монстра. Обратите внимание, что в приведенном выше примере это действительно «состояние», а не дата, как можно было бы интуитивно заметить. Это должно продемонстрировать, что значения времени, отличные от даты, также могут быть включены в вычисление хэша.

Шаг 7:

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

Печать хэшей и связанных с ними счетчиков записей через get_df_head(…) выглядит следующим образом:

Шаг 8:

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

Результат (получение заголовка фрейма данных) приведенного выше (каскадного) запроса дает:

Из-за значений формулы, которые мы выбрали на шаге 3, мы получаем около 100 сегментов для распределения данных.

Шаг 9:

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

Печать заголовка результирующего фрейма данных показывает нам, как данные разделены в процентах:

Примерно 1% на индекс ведра. Неплохо.

Шаг 10:

Мы объединяем ведра пропорционально и разделяем на обучающие, оценочные и тестовые наборы. Эти запросы приведены ниже:

Вывод вышеизложенного будет выглядеть следующим образом. Если мы заметим номера корзин (индексы) для десяти напечатанных строк, мы увидим, что индексы корзин, кажется, находятся между 0 и 79, как определено предложением where и значениями, выбранными на шаге 3.

Оценочный запрос ниже. Результат будет выглядеть аналогично с индексами корзины в диапазоне от 80 до 89, как определено нашими значениями на шаге 3 и предложением where запроса ниже. Это опущено для краткости

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

Шаг 11:

Union all объединяет результаты трех запросов на предыдущем шаге. Мы делаем это, чтобы иметь возможность сортировать dataset_id в запросе, после чего получаем процент данных, соответствующих обучающему, оценочному и тестовому наборам соответственно. Здесь наш раскол наиболее четко выражен.

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

Мы должны получить более или менее желаемое разделение, используя значения на шаге 3. Если это не так, нам придется настроить его, чтобы получить желаемое разделение 80–10–10 (более или менее). Шаги с 6 по 11 должны гарантировать, что выбранные нами параметры на шаге 3 приводят к точному разбиению.

Шаг 12:

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

Множитель подвыборки будет меняться в зависимости от общего количества строк в наборе данных. Обратите внимание, как вызывается метод create_data_split_sample(…) и какие параметры передаются для обучения, оценки (валидации) и тестирования. Для примера, который был доступен в облаке Google, оператор печати дал:

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

Основываясь на нашем выборе значения на шаге 3, оператор ABS(MOD…) будет выглядеть следующим образом, когда он разрешится: ABS(MOD(hash_values, 1000 * 100)) поэтому хэш-значения, которые мы сгенерировали с помощью FARM_FINGERPRINT, будут по модулю 100 КБ согласно приведенному выше заявление. Итак, если, например, у нас всего 10 миллионов записей, 100k X 100 равняется 10M. 100k / 100 — это 1000. Нам нужна операция модуля, чтобы разделить на 100 сегментов. Вот почему 100 так важно здесь. Итак, если мы выберем 1000 как кратное и сделаем это -> ABS(MOD(hash_values, 1000 * 100)) ›= 0 и ABS(MOD(hash_values, 1000 * 100)) ‹ 80, мы выберем примерно 1 из каждых 1000 записи. Это также будет продолжать масштабироваться за пределы 10 миллионов записей. Если мы приблизимся к 100 млн, мы просто увеличим множитель, чтобы, возможно, выбрать одну из каждых 10000 записей для обучающего набора.

ABS(MOD(hash_values, 1000 * 100)) ›= 80 и ABS(MOD(hash_values, 1000 * 100)) ‹ 90 даст нам наш оценочный набор.

Наконец, ABS(MOD(hash_values, 1000 * 100)) ›= 90 и ABS(MOD(hash_values, 1000 * 100)) ‹ 100 для тестового набора.

Общее количество записей в образце набора данных, используемом для этой статьи, составляет 33 011 359. Математика примерно работает. Запрос, построенный в совокупности после выборки, должен выглядеть примерно так:

Для обучения:

Для оценки:

Запрос будет таким же, за исключением предложения WHERE в конце, которое будет выглядеть так:

ГДЕ ABS(MOD(значения_хэша, 1000*100)) ›= 80 и ABS(MOD(значения_хэша, 1000*100)) ‹ 90

И для тестового набора

ГДЕ ABS(MOD(значения_хэша, 1000*100)) ›= 90 и ABS(MOD(значения_хэша, 1000*100)) ‹ 100

Шаг 13:

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

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

train_df = предварительная обработка (train_df)

eval_df = предварительная обработка (eval_df)

test_df = предварительная обработка (test_df)

train_df, eval_df и test_df были определены на шаге 12.

Шаг 14:

Вызовите train_df.head(), train_df.tail() и train_df.describe(), чтобы сделать базовую проверку правильности предварительной обработки. На этом этапе также было бы хорошо повторно визуализировать обработанные данные с помощью pyplot или любого другого инструмента визуализации.

Шаг 15:

В окончательных версиях мы хотим читать из файлов, а не из фреймов данных Pandas. Итак, мы записываем кадры данных Pandas в виде файлов csv. Использование CSV-файлов дает нам преимущество перетасовки во время чтения. Это важно для распределенного обучения, поскольку некоторые рабочие процессы могут быть медленнее других, а перетасовка данных помогает предотвратить назначение одних и тех же данных медленным рабочим процессам.

Шаг 16:

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

туалет -l *.csv

Пример вывода для приведенной выше команды:

2000 eval.csv

1000 тестов.csv

10000 train.csv

Кроме того, мы печатаем несколько строк в этих файлах с помощью команд head и tail:

голова *.csv

хвост *.csv

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

Шаг 17:

Далее мы пишем несколько вспомогательных методов. Первый из них — загрузка данных в память.

Шаг 18:

Затем мы определяем метод create_input_layers() для глубокой нейронной сети (DNN), которую мы впоследствии построим:

Обратите внимание, как входные данные определяются на основе типа данных (dtype)

Шаг 19:

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

Шаг 20:

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

Шаг 21:

Определите помощника, который использует tf.keras.layers.Dense(…) для создания скрытых слоев, а также выходного слоя нашей глубокой нейронной сети с соответствующим количеством единиц на каждом слое. Это меняется от проблемы к проблеме

Шаг 22:

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

Шаг 23:

Мы вызываем все помощники, которые мы тщательно определили в предыдущих шагах, в упорядоченном порядке, используя метод, который мы определили как build_dnn_model().

Чтобы визуализировать глубокую нейронную сеть:

DenseFeatures и Dense отличаются в библиотеке keras.layers. Мы используем DenseFeatures для определения нашего входного векторного слоя, передавая подготовленные входные объекты.

Шаг 24:

Теперь, когда мы построили модель. Нам нужно обучить и оценить только что созданную модель. Мы вызываем созданный ранее помощник load_dataset(…) и передаем TRAIN_BATCH_SIZE в режиме обучения и EVAL_BATCH_SIZE для размера пакета при оценке. Значения этих констант приведены для иллюстративных целей и будут меняться в зависимости от данных.

Обратные вызовы Tensorboard могут быть определены для визуализации обучения на инструменте Tensorboard.

Шаг 25:

Далее следует визуализировать кривую потерь с помощью pyplot или любого другого инструмента визуализации.

Вывод выглядит примерно так:

Шаг 26:

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

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

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