Автор: / Команда TensorFlow
Добро пожаловать во вторую часть серии статей, посвященных наборам данных и оценщикам TensorFlow (штамп части 1).здесь). Мы расскажем в этой статьеКолонка функций - Структура данных, описывающая характеристики, необходимые оценщику для обучения и вывода.Как вы увидите ниже, столбцы функций очень информативны и позволяют вам представлять различные данные.
существуетЧасть 1 (Введение в наборы данных и оценки TensorFlow), мы использовали заранее подготовленную оценку DNNClassifier для обучения модели прогнозированию различных типов радужной оболочки на основе наших входных данных. В этом примере создаются только столбцы числовых функций (типа tf.feature_column.numeric_column). Хотя этих столбцов признаков достаточно для моделирования длины лепестков и чашелистиков, наборы данных реального мира содержат множество нечисловых признаков. Например:
Рисунок 1. Нечисловые признаки.
Как мы можем представить нечисловые типы объектов? Это именно то, что мы собираемся обсудить в этой статье.
Вход в глубокую нейронную сеть
Первый вопрос: какие данные мы на самом деле вводим в глубокую нейронную сеть? Конечно, ответом является число (например, tf.float32). В конце концов, каждый нейрон в нейронной сети выполняет операции умножения и сложения с весами и входными данными. Однако реальные входные данные часто содержат нечисловые (категориальные) данные. Например, предположим, что имеется функция product_class со следующими тремя нечисловыми значениями:
-
кухонная утварь
-
электроника (электронные изделия)
-
спорт (спортивные товары)
Модели машинного обучения обычно представляют категориальные значения в виде простых векторов, где 1 означает, что значение существует, а 0 означает, что значение не существует. Например, если для product_class установлено значение sports, модели машинного обучения обычно представляют product_class как [0, 0, 1], что означает следующее:
-
0: посуда не существует
-
0: электроники не существует
-
1: спорт существует
Таким образом, хотя необработанные данные могут быть числовыми или категориальными, модель машинного обучения будет представлять все функции в виде чисел или векторов чисел.
Введение в столбцы функций
Как показано на рисунке 2, вы можете указать входные данные для модели с помощью параметра feature_columns оценщика (Iris — это DNNClassifier). Столбцы функций соединяют входные данные (возвращенные input_fn ) с вашей моделью.
Рисунок 2. Столбцы функций связывают необработанные данные с данными, которые нужны вашей модели.
Чтобы представить функции в виде столбцов функций, вызовите функции пакета tf.feature_column. В этом посте будут представлены девять функций этого пакета. Как показано на рисунке 3, все девять функций возвращают объект Categorical-Column или Dense-Column, за исключением Bucketized_column, который наследуется от обеих категорий:
Рисунок 3. Функции столбца функций можно разделить на две основные категории и одну смешанную категорию.
Рассмотрим эти функции подробно.
числовой столбец
Классификатор радужной оболочки вызывает tf.numeric_column() для всех входных функций: SepalLength, SepalWidth, PetalLength, PetalWidth. Хотя tf.numeric_column() предоставляет необязательные аргументы, вызов функции без каких-либо аргументов — это очень простой способ указать числовое значение с типом данных по умолчанию (tf.float32) в качестве входных данных для модели. Например:
# Defaults to a tf.float32 scalar. numeric_feature_column = tf.feature_column.numeric_column(key="SepalLength")
Используйте параметр dtype, чтобы указать числовой тип данных, отличный от используемого по умолчанию. Например:
# Represent a tf.float64 scalar.
numeric_feature_column = tf.feature_column.numeric_column(key="SepalLength",
dtype=tf.float64)
По умолчанию числовой столбец может создать одно значение (скалярное). Используйте параметр формы, чтобы указать другую форму. Например:
# Represent a 10-element vector in which each cell contains a tf.float32.
vector_feature_column = tf.feature_column.numeric_column(key="Bowling",
shape=10)
# Represent a 10x5 matrix in which each cell contains a tf.float32.
matrix_feature_column = tf.feature_column.numeric_column(key="MyMatrix",
shape=[10,5])
Ковшовая колонна
Часто вы не хотите напрямую передавать число в модель, а вместо этого разбиваете его значения на категории на основе диапазона значений. Для этого создайте столбец сегментации. Например, предположим, что есть необработанные данные, представляющие год постройки дома. Вместо того, чтобы представлять год в виде скалярного числового столбца, мы можем разделить год на следующие четыре сегмента:
Рисунок 4. Разделение годовых данных на четыре блока.
Модель будет представлять ведра следующими способами:
диапазон дат | Представление... |
[1, 0, 0, 0] | |
>= 1960 и | [0, 1, 0, 0] |
>= 1980 и | [0, 0, 1, 0] |
> 2000 | [0, 0, 0, 1] |
Поскольку числа являются очень эффективным входом в модель, зачем разбивать их на такие категориальные значения? Обратите внимание, что классификация может разбить входное число на четырехэлементный вектор. Таким образом, модель теперь может обучаться четырем отдельным весам вместо одного. Четыре веса могут создать более информативную модель, чем один вес. Что еще более важно, поскольку установлен только один элемент (1), а остальные три очищены (0), сегментация позволяет модели четко различать разные категории года. Если мы используем только одно число (год) в качестве входных данных, модель не может различать категории. Таким образом, сегментация может предоставить модели другую важную информацию, которую она может использовать для обучения.
Следующий код демонстрирует, как создать сегментированную функцию:
# A numeric column for the raw input.
numeric_feature_column = tf.feature_column.numeric_column("Year")
# Bucketize the numeric column on the years 1960, 1980, and 2000
bucketized_feature_column = tf.feature_column.bucketized_column(
source_column = numeric_feature_column,
boundaries = [1960, 1980, 2000])
Обратите внимание на следующее:
-
Перед созданием столбца сегментации мы создали числовой столбец для представления исходного года.
-
Мы передаем числовой столбец в качестве первого аргумента в tf.feature_column.bucketized_column().
-
Указание трехэлементного вектора границы создает четырехэлементный сегментированный вектор.
Категориальный столбец идентификации
Категориальный столбец идентификациипредставляет собой особую форму секционированного столбца хранения. В традиционном сегментированном столбце каждый сегмент представляет собой диапазон значений (например, с 1960 по 1979 год). В столбце категориального идентификатора каждое ведро представляет собой уникальное целое число. Например, допустим, вы хотите представить целочисленный диапазон [0, 4). (То есть вы хотите представить целые числа 0, 1, 2 или 3.) В этом случае категориальное отображение идентичности выглядит следующим образом:
Рисунок 5. Сопоставление столбца идентификации классификации. Обратите внимание, что это горячая кодировка, а не кодировка двоичных чисел.
Итак, зачем вам представлять значения в столбце категориального идентификатора? Используя сегментированные столбцы, модель может узнать отдельные веса для каждой категории в столбце категориального идентификатора. Например, вместо использования строки для product_class мы используем уникальное целочисленное значение для каждой категории. который:
-
0="kitchenware"
-
1="electronics"
-
2="sport"
Вызовите tf.feature_column.categorical_column_with_identity(), чтобы реализовать столбец категориального идентификатора. Например:
# Create a categorical output for input "feature_name_from_input_fn",
# which must be of integer type. Value is expected to be >= 0 and < num_buckets
identity_feature_column = tf.feature_column.categorical_column_with_identity(
key='feature_name_from_input_fn',
num_buckets=4) # Values [0, 4)
# The 'feature_name_from_input_fn' above needs to match an integer key that is
# returned from input_fn (see below). So for this case, 'Integer_1' or
# 'Integer_2' would be valid strings instead of 'feature_name_from_input_fn'.
# For more information, please check out Part 1 of this blog series.
def input_fn():
...<code>...
return ({ 'Integer_1':[values], ..<etc>.., 'Integer_2':[values] },
[Label_values])
Колонка категориального словаря
Мы не можем передавать строки непосредственно в модель. Вместо этого мы должны сначала преобразовать строки в числовые или категориальные значения. Столбец категориального словаря обеспечивает хороший способ представления строк в виде однократных векторов. Например:
Рисунок 6. Сопоставление строковых значений со столбцами словаря.
Как видите, столбец терминов таксономии является пронумерованной версией столбца идентификации таксономии. TensorFlow предоставляет две разные функции для создания столбцов категориального словаря:
-
tf.feature_column.categorical_column_with_vocabulary_list()
-
tf.feature_column.categorical_column_with_vocabulary_file()
Функция tf.feature_column.categorical_column_with_vocabulary_list() может отображать каждую строку в целое число на основе явного списка словарей. Например:
# Given input "feature_name_from_input_fn" which is a string,
# create a categorical feature to our model by mapping the input to one of
# the elements in the vocabulary list.
vocabulary_feature_column =
tf.feature_column.categorical_column_with_vocabulary_list(
key="feature_name_from_input_fn",
vocabulary_list=["kitchenware", "electronics", "sports"])
Предыдущая функция имеет один вопиющий недостаток: она требует много печатать, когда список словарей длинный. В этих случаях вместо этого вызовите tf.feature_column.categorical_column_with_vocabulary_file(), что позволит поместить словарь в отдельный файл. Например:
# Given input "feature_name_from_input_fn" which is a string,
# create a categorical feature to our model by mapping the input to one of
# the elements in the vocabulary file
vocabulary_feature_column =
tf.feature_column.categorical_column_with_vocabulary_file(
key="feature_name_from_input_fn",
vocabulary_file="product_class.txt",
vocabulary_size=3)
# product_class.txt should have one line for vocabulary element, in our case:
kitchenware
electronics
sports
Ограничение категорий с помощью хеш-багет
Пока что мы рассмотрели только несколько категорий. Например, в нашем примере product_class всего 3 категории. Однако количество категорий часто может быть настолько большим, что невозможно использовать отдельную категорию для каждого слова или целого числа, так как это потребовало бы большого объема памяти. В этих случаях мы можем перевернуть вопрос и спросить себя: «Сколько категорий я хочу использовать для ввода?» На самом деле, функция tf.feature_column.categorical_column_with_hash_buckets() позволяет указать количество категорий. Например, в следующем коде показано, как эта функция вычисляет хэш входных данных, а затем использует оператор по модулю, чтобы поместить его в В категории hash_bucket_size:
# Create categorical output for input "feature_name_from_input_fn".
# Category becomes: hash_value("feature_name_from_input_fn") % hash_bucket_size
hashed_feature_column =
tf.feature_column.categorical_column_with_hash_bucket(
key = "feature_name_from_input_fn",
hash_buckets_size = 100) # The number of categories
В этот момент вы можете подумать: «Это сумасшествие!» В конце концов, мы помещаем разные входные значения в меньший набор категорий. Это означает, что два входа, которые, вероятно, будут совершенно не связаны между собой, будут сопоставлены с одной и той же категорией, что является одинаковым для нейронных сетей. Рисунок 7 иллюстрирует загадку, показывающую, что и кухонной утвари, и спорту присвоена категория (ведро для мусора) 12:
Рисунок 7. Представление данных в хеш-контейнере.
Как и многие парадоксальные явления в машинном обучении, на практике хеширование обычно работает хорошо. Это связано с тем, что хэш-категория обеспечивает некоторое разделение модели. Модели могут использовать больше функций, чтобы еще больше отделить кухонную утварь от спортивной.
Характерные кресты
Последний категориальный столбец, который мы рассмотрим, позволяет нам объединить несколько входных функций в один. Объединение функций (более известное как пересечение функций) позволяет модели изучать отдельные веса специально для любого значения, которое представляет комбинация функций.
Чтобы быть более конкретным, предположим, что мы хотим, чтобы наша модель рассчитывала цены на недвижимость в Атланте, штат Джорджия. Цены на недвижимость в городе сильно различаются в зависимости от местоположения. Представление широты и долготы в виде отдельных признаков не очень полезно для определения корреляции местоположения недвижимости, однако объединение широты и долготы в один признак может определить местоположение. Предположим, мы представляем Атланту как сетку прямоугольных профилей 100x100, где 10 000 профилей определяются пересечением широты и долготы. Эта комбинация позволяет модели подбирать условия ценообразования, связанные с отдельными профилями, которые могут предоставить более важную информацию, чем только широта и долгота.
На рисунке 8 показан наш план этажа со значениями широты и долготы для четырех углов города:
Рисунок 8. Карта Атланты. Представьте, что эта карта состоит из 10 000 секций одинакового размера.
Чтобы решить эту проблему, мы используем некоторые из представленных ранее комбинаций функций и столбцов, а также функцию tf.feature_columns.crossed_column().
# In our input_fn, we convert input longitude and latitude to integer values
# in the range [0, 100)
def input_fn():
# Using Datasets, read the input values for longitude and latitude
latitude = ... # A tf.float32 value
longitude = ... # A tf.float32 value
# In our example we just return our lat_int, long_int features.
# The dictionary of a complete program would probably have more keys.
return { "latitude": latitude, "longitude": longitude, ...}, labels
# As can be see from the map, we want to split the latitude range
# [33.641336, 33.887157] into 100 buckets. To do this we use np.linspace
# to get a list of 99 numbers between min and max of this range.
# Using this list we can bucketize latitude into 100 buckets.
latitude_buckets = list(np.linspace(33.641336, 33.887157, 99))
latitude_fc = tf.feature_column.bucketized_column(
tf.feature_column.numeric_column('latitude'),
latitude_buckets)
# Do the same bucketization for longitude as done for latitude.
longitude_buckets = list(np.linspace(-84.558798, -84.287259, 99))
longitude_fc = tf.feature_column.bucketized_column(
tf.feature_column.numeric_column('longitude'), longitude_buckets)
# Create a feature cross of fc_longitude x fc_latitude.
fc_san_francisco_boxed = tf.feature_column.crossed_column(
keys=[latitude_fc, longitude_fc],
hash_bucket_size=1000) # No precise rule, maybe 1000 buckets will be good?
Вы можете создавать пересечения объектов на основе одной из следующих данных:
-
Имена функций, т. е. имена в словаре, возвращаемые из input_fn.
-
Любой категориальный столбец (см. рис. 3), кроме categorical_column_with_hash_bucket.
Когда столбцы функций latitude_fc и longitude_fc пересекаются, TensorFlow создаст 10 000 комбинаций (latitude_fc, longitude_fc), организованных следующим образом:
(0,0),(0,1)... (0,99)
(1,0),(1,1)... (1,99)
…, …, ...
(99,0),(99,1)...(99, 99)
Функция tf.feature_column.crossed_column выполнит вычисление хэша для этих комбинаций, а затем вставит результат в категории, выполнив операцию по модулю с помощью hash_bucket_size. Как обсуждалось ранее, выполнение хеш-функций и функций по модулю, скорее всего, приведет к коллизиям классов, т. е. в одном и том же хэш-сегменте появятся пересечения нескольких признаков (широта, долгота). На практике, однако, выполнение кроссовера функций все еще может обеспечить действительное значение способности модели к обучению.
Как это ни парадоксально, при создании пересечений объектов вам обычно нужно включать в модель исходные (непересекающиеся) объекты. Например, вместо того, чтобы просто указать пересечение объектов (широта, долгота), вам также необходимо указать широту и долготу как отдельные объекты. Отдельные функции широты и долготы помогут модели разделить содержимое хэш-сегментов, содержащих пересечения различных функций.
См. эту ссылку для полного примера кода:
https://github.com/tensorflow/models/blob/master/samples/outreach/blogs/housing_prices.ipynb
Кроме того, в разделе «Ресурсы» в конце этой статьи приведены дополнительные примеры пересечений объектов.
Индикатор и встраивание столбцов
Столбцы индикаторов и вложений никогда не работают напрямую с объектами, а используют в качестве входных данных столбцы категорий.
При использовании столбца индикатора мы говорим TensorFlow делать именно то, что мы видели в примере с классификацией product_class. который,индикаторная колонкаРассматривайте каждую категорию как элемент в одном горячем векторе, где соответствующая категория имеет значение 1, а остальные равны 0:
Рисунок 9. Представление данных в столбцах индикатора.
Вот как создать столбец индикатора:
categorical_column = ... # Create any type of categorical column, see Figure 3
# Represent the categorical column as an indicator column.
# This means creating a one-hot vector with one element for each category.
indicator_column = tf.feature_column.indicator_column(categorical_column)
Теперь, допустим, у нас есть 1 миллион вместо трех возможных классов. Или 1 млрд. По ряду причин (слишком технических, чтобы их здесь описывать) обучение нейронной сети с помощью индикаторных столбцов становится невозможным по мере увеличения количества классов.
Мы можем использовать встроенные столбцы, чтобы обойти это ограничение. Вместо того, чтобы представлять данные в виде однократных векторов со многими измерениями,Встроенная колонкаПредставляет данные в виде плоского вектора меньшей размерности, где каждая ячейка может содержать любое число, а не только 0 или 1. Допуская более богатые комбинации чисел для каждой ячейки, встроенные столбцы могут содержать гораздо меньше ячеек, чем столбцы индикаторов.
Давайте рассмотрим пример сравнения столбцов индикатора и встроенных столбцов. Предположим, наш входной пример содержит разные слова в конечной комбинации всего из 81 слова. Предположим далее, что набор данных предоставляет следующие входные слова в 4 отдельных примерах:
-
"dog"
-
"spoon"
-
"scissors"
-
"guitar"
В этом случае на рис. 10 показан путь обработки встроенных или индикаторных столбцов.
Рисунок 10. Внедренные столбцы хранят категориальные данные в векторе меньшей размерности, чем столбцы индикаторов. (Мы просто помещаем случайные числа в вектор встраивания; обучение определяет фактические числа.)
При обработке примера функция categorical_column_with... сопоставляет строки примеров с числовыми категориальными значениями. Например, функция сопоставит «ложку» с [32]. (32 исходит из нашего воображения — фактическое значение зависит от функции отображения.) Затем вы можете представить эти числовые категориальные значения одним из двух способов:
-
как индикаторная колонка. Функция преобразует каждое числовое категориальное значение в вектор из 81 элемента (поскольку наша комбинация содержит 81 слово), размещая 1 в индексах категориальных значений (0, 32, 79, 80) и 0 в других местах.
-
как встроенный столбец. Функция использует числовые категориальные значения (0, 32, 79, 80) в качестве индекса в таблице поиска. Каждая позиция отображения в таблице поиска содержит трехэлементный вектор.
Как волшебным образом присваиваются значения во встроенном векторе? Собственно, задание происходит во время обучения. То есть модель узнает, как лучше всего сопоставить ваши входные числовые категориальные значения с векторными значениями встраивания для решения вашей проблемы. Внедрение столбцов может повысить мощность вашей модели, поскольку встраивание векторов позволяет изучить новые отношения между категориями из обучающих данных.
Почему размер вектора в нашем примере 3? Следующие «формулы» предоставляют общие эмпирические правила относительно количества вложенных измерений:
embedding_dimensions = number_of_categories**0.25
То есть размерность вектора вложения должна быть равна корню четвертой степени из числа категорий. Поскольку размер словаря в этом примере равен 81, рекомендуемое количество измерений равно 3:
3 = 81**0.25
Обратите внимание, что это всего лишь общая рекомендация; вы можете установить столько размеров встраивания, сколько захотите.
Вызовите tf.feature_column.embedding_column, чтобы создать embedding_column. Размерность вектора встраивания зависит от рассматриваемой проблемы, представленной выше, но общие значения могут начинаться с 3 и доходить до 300 и более:
categorical_column = ... # Create any categorical column shown in Figure 3.
categorical_column = ... # Create any categorical column shown in Figure 3.
# Represent the categorical column as an embedding column.
# This means creating a one-hot vector with one element for each category.
embedding_column = tf.feature_column.embedding_column(
categorical_column=categorical_column,
dimension=dimension_of_embedding_vector)
Встраивания — большая тема в области машинного обучения. Эта информация предназначена для того, чтобы помочь вам начать использовать их в качестве столбцов функций. Дополнительную информацию смотрите в конце этой статьи.
Передайте столбцы признаков оценщикам
Вы все еще смотрите? Я надеюсь, что вы все еще смотрите, потому что вот-вот будут рассмотрены основы столбцов функций.
Как мы видим на рисунке 1, столбцы функций сопоставляют ваши входные данные (проиллюстрированные словарем функций, возвращенным из input_fn ) со значениями, которые необходимо предоставить модели. Укажите столбцы признаков в виде списка для параметра feature_columns оценщика. Обратите внимание, что параметр feature_columns зависит от оценщика:
LinearClassifier и LinearRegressor:
-
Принимаются все типы столбцов функций.
Классификатор DNN и регрессор DNN:
-
Допускаются только плотные столбцы, см. рис. 3. Как упоминалось ранее, другие типы столбцов должны быть заключены в индикаторную_колонку или встроенную_колонку.
DNNLinearCombinedClassifier и DNNLinearCombinedRegressor:
-
Параметр linear_feature_columns может принимать столбцы любого типа, такие как LinearClassifier и LinearRegressor выше.
-
Однако параметр dnn_feature_columns ограничен плотными столбцами, такими как DNNClassifier и DNNRegressor выше.
Причины вышеуказанных правил выходят за рамки этой вводной статьи, но мы обязательно рассмотрим их в следующих статьях.
Суммировать
Используйте столбцы функций, чтобы сопоставить ваши входные данные с представлением, которое вы предоставляете модели. Мы в этой сериичасть 1используется только в numeric_column, но вы можете легко создать другие столбцы характеристик, используя другие функции, описанные в этой статье.
Дополнительные сведения о столбцах характеристик см. в ресурсах ниже:
-
Видео о разработке функций от Джоша Гордона
-
Заметки Jupyter от того же автора
-
TensorFlow — широкое и глубокое руководство
-
Примеры DNN и линейных моделей с использованием столбцов признаков
Если вы хотите узнать больше о встраивании, см. следующие ресурсы:
-
Глубокое обучение, НЛП и представления (блог Колы)
-
См. Проектор для встраивания TensorFlow
Как обратиться? Пожалуйста, ответьте на этот официальный аккаунт"Ресурсы колонки функций" для ссылок на ресурсы.