Машинное обучение с разреженными, многомерными и большими наборами данных
Многомерные наборы данных возникают в самых разных областях, от вычислительной рекламы до обработки естественного языка. Обучение в таких больших измерениях может быть ограничено с точки зрения вычислений и/или памяти. С этой целью методы уменьшения размерности, такие как (линейный/нелинейный) анализ основных компонентов или многообразное обучение, используются для преобразования в пространстве с меньшими размерностями. Однако эти методы уменьшения размерности иногда неприменимы, например, в разреженных наборах данных, которые имеют независимые признаки, а данные лежат в нескольких многообразиях более низкой размерности.
В этой статье мы обсуждаем и реализуем подход к обучению на таких разреженных многомерных наборах данных. Размерность данных и размер данных являются двумя аспектами этих проблем. Чтобы уменьшить размерность данных, хэширование функций предлагает масштабируемое и эффективное с вычислительной точки зрения представление функций. Большой набор данных может по-прежнему создавать ограничения по вычислительным ресурсам и памяти на персональном компьютере. С этой целью мы используем мини-пакетный градиентный спуск для итеративного обучения модели.
В посте мы используем инструменты из Python, такие как Pandas, Numpy и Scikit-Learn, для использования хэширования функций и мини-пакетного обучения с разреженными, многомерными и большими наборами данных. Фрагменты кода с подробными комментариями включены для практической реализации в среде обработки данных Python.
Создание и хранение данных
Мы демонстрируем практическое использование хеширования признаков и мини-пакетного обучения с использованием задачи бинарной классификации. Для этой задачи создается поддельный набор данных, содержащий 1,0 миллиона точек данных. Каждая точка данных в наборе данных содержит пакет буквенно-цифровых токенов вместе с меткой. При создании набора данных мы сначала создали 65464 буквенно-цифровых объекта путем случайной выборки из набора алфавитов и 10 цифр. Во-вторых, мы сгенерировали данные для каждого из двух классов (0 и 1) отдельно, используя половину числа признаков, то есть исключительно 32732. Чтобы создать разреженность, ни одна из функций не назначается более чем 0,3% данных. Обратите внимание, что наше создание данных приводит к идеально разделяемым классам.
Мини-пакетное обучение с хешированием признаков
Следующий код демонстрирует практическую реализацию итеративного обучения с хешированием признаков. Функция train(model, lines) обновляет модель в течение 1 эпохи, используя мини-пакетное обучение. Набор обучающих данных хранится в строках в виде списка строк, где каждая строка является записью. Это общая функция, которая является приложением к любому классу модели в sklearn, который поддерживает метод partial_fit(). Популярными моделями классификации, поддерживающими partial_fit(), являются логистическая регрессия, машины опорных векторов и искусственные нейронные сети. Эта функция поддерживает мини-обучение; каждая партия размером 1000 образцов. На каждой итерации функция строит кадр данных pandas из 1000 выборок из строк, вычисляет хеширование признаков в соответствии с предварительно определенными размерами признаков и обновляет модель.
Вторая функция hash_representation(df) используется функцией train(). Он вычисляет хеширование признаков для входных строк, которые хранятся в виде столбца во входном файле df. Вычисленное представление объекта объединяется с DataFrame df и возвращается.
Смотрите подробные комментарии внутри функций для лучшего понимания.
def hash_representation(df):
def vectorize(line):
''' This function transforms a line comprising bag to words to its hash representation.
Input to this function is a line that comprises , separated words.
output is a numpy array which is the hash representation of line according to a hash
template (global object).
'''
# Construct a dictionary comprising each word in the line as keys and 1 as its value.
D = [{key:1 for key in line.split('\n')[0].split(',')}]
# tranform D to a numpy array according to a hash template h.
return h.transform(D).toarray()[0]
# Obtain hash represntation of input strings.
s = df['inputs'].apply(vectorize)
# Giving non-numeric names to the resulting data frame.
columns = ['col_'+str(i) for i in range(len(s.values[0]))]
new_df = pd.DataFrame.from_items(zip(s.index, s.values), orient="index", columns=columns)
new_df['labels'] = df['labels']
# Returning dataframe that has hash representation of inputs as features along with class labels.
return new_df
def train(model, lines):
''' This function takes updates the model over 1 epoch of training data.
Inputs to this function are:
model ~ An sklearn model object over which partial_fit() method is valid.
lines ~ a list of strings and each string is a record, example or a measurement.
Output of this function is
model ~ an updated model.
'''
''' We construct a pandas DataFrame out of these lines and use its str
functionality to create new columns; one for input strings and the other for
output labels. '''
df = pd.DataFrame(lines, columns=['raw_data'])
df['labels'] = df['raw_data'].str.split(',').apply(lambda x:x[0]).astype(int) #%[0][0]
df['inputs'] = df['raw_data'].str.split(',').apply(lambda x:x[1]) #%[0][0]
del df['raw_data']
''' We shuffle the data to ensure randomness to avoid any cycles in training. '''
df = shuffle(df)
''' We specify the batch size that specifies the data size over which model update is based in one iteration. '''
batch_size = 1000
"total number of batches"
total_batches = math.ceil(df.shape[0] / batch_size)
# Iterating over each batch.
for batch_numb in range(total_batches):
st = batch_numb * batch_size # starting index (inclusive) of the batch.
en = (1+batch_numb) * batch_size # End index (exclusive) of the batch.
''' Last batch may comprise data points less than the batch_size.
Under such a scenario, the batch_size comprises remaining elements
that are less than the batch_size and we modify the End index to
be the size of the lines.
'''
en = min(en, df.shape[0])
'''For the subset of lines comprising current batch,
we construct a new data frame that comprises hash representation of the
inputs along with outputs.
'''
tmp_df = hash_representation(df.iloc[st:en])
tmp_labels = tmp_df['labels'].copy()
del tmp_df['labels']
# model update using current batch.
model.partial_fit(np.array(tmp_df), np.array(tmp_labels), classes=[0,1])
# returning model after updating with 1 epoch.
return model
Выбор модели и гиперпараметры
Чтобы продемонстрировать эффективность нашего Мини-пакетное обучение с хешированием признаков подход, мы разделили наш набор данных на 80% обучения, 10% проверки и 10% тестирования. следует отметить, что 10% тестовых данных содержат 100 000 образцов, что достаточно для оценки производительности. Мы оценили логистическую регрессию, метод опорных векторов и искусственные нейронные сети с несколькими вариантами архитектуры. Было обнаружено, что искусственные нейронные сети дают наилучшие результаты проверки. В то время как производительность более глубоких архитектур немного лучше, ИНС с 1 скрытым слоем, состоящим из 100 нейронов, дает производительность проверки; достаточно хорошо, чтобы продемонстрировать наши идеи. Мы также обнаружили, что производительность проверки незначительно меняется после первой эпохи; предлагая производительность проверки с 1 эпохой, чтобы представить производительность модели. В наших последующих экспериментах мы использовали ИНС с 1 скрытым слоем, состоящим из 100 нейронов, поскольку наша модель и обучение проводились всего за 1 эпоху.
Оптимальная размерность хеширования
Хеширование функций может привести к хэш-коллизия который относится к двум разным точкам данных, дающим одно и то же хеш-представление. Столкновение образцов одного класса с образцами другого ухудшает точность классификации. По мере увеличения размерности хеширования все меньшие и меньшие различия во входных данных приводят к различным представлениям хеширования; следовательно, количество столкновений уменьшается. Недостатки в обучении, возможное смещение модели и коллизии хеширования являются важными источниками шума в этой проблеме бинарной классификации. Хотя недостатки в обучении и возможное смещение модели можно исследовать, мы стремимся продемонстрировать влияние измерений хеширования на производительность классификации. Более высокая размерность хеширования, вероятно, повышает точность классификации; хотя и за счет вычислений и памяти.
Ниже приведен шаблон хеширования функций из sklearn.feature_extraction с параметром хеширования в качестве параметра.
h = FeatureHasher(n_features=hashing_dimension)
Мы провели численные эксперименты с различными размерностями хеширования и получили следующие точности проверки.
Измерение хеширования | Точность проверки |
---|---|
1600 | 73,9% |
3200 | 80,4% |
6400 | 86,8% |
12800 | 91,6% |
19200 | 93,5% |
25600 | 94,8% |
Обратите внимание на таблицу, что производительность проверки улучшается с размером хеширования, однако при уменьшении отдачи. Более высокие размерности хеширования приводят к более дорогостоящему обучению в вычислительном отношении и требуют большего объема памяти или меньшего размера пакета. Следовательно, оптимальный выбор размерности хеширования зависит от вычислительных ресурсов и точки, после которой отдача незначительна. Для нашего случая мы выбрали размерность хеширования 12800 и оценили производительность теста, которая составила 91,4%.
Выводы
Мы представили хеширование признаков; масштабируемый и надежный метод уменьшения размерности, который может быть единственным вариантом уменьшения размерности в определенных задачах и может обеспечить более высокую производительность по сравнению с популярным PCA или многообразным обучением. Комплексная структура для хэширования функций с мини-пакетным обучением также демонстрируется в рамках sklearn. Наши численные эксперименты продемонстрировали эффективность нашего подхода и реализации.