11

Я занимаюсь своими мозгами за последние 2-3 недели по этой проблеме. У меня проблема с несколькими метками (не многоклассы), где каждый образец может принадлежать нескольким ярлыкам.Масштабируемые или онлайн-классические многоэлементные классификаторы

У меня около 4,5 миллионов текстовых документов в качестве данных для обучения и около 1 миллиона в качестве тестовых данных. Этикетки составляют около 35K.

Я использую scikit-learn. Для извлечения функций я ранее использовал TfidfVectorizer, который вообще не масштабировался, теперь я использую HashVectorizer, который лучше, но не настолько масштабируемый, учитывая количество документов, которые у меня есть.

vect = HashingVectorizer(strip_accents='ascii', analyzer='word', stop_words='english', n_features=(2 ** 10)) 

SKlearn предоставляет OneVsRestClassifier, в который я могу подавать любую оценку. Для multi-label я нашел LinearSVC & SGDClassifier только для правильной работы. В соответствии с моими показателями SGD превосходит LinearSVC как в памяти & времени. Итак, у меня есть что-то вроде этого

clf = OneVsRestClassifier(SGDClassifier(loss='log', penalty='l2', n_jobs=-1), n_jobs=-1) 

Но страдает от некоторых серьезных проблем:

  1. OneVsRest не метод partial_fit, что делает его невозможным вне-ядра обучения. Есть ли альтернативы для этого?
  2. HashingVectorizer/Tfidf работают на одном ядре и не имеют параметра n_jobs. Слишком много времени для хэширования документов. Любые альтернативы/предложения? Правильно ли значение n_features?
  3. Я проверил на 1 миллион документов. Хешинг занимает 15 минут, и когда дело доходит до clf.fit (X, y), я получаю MemoryError, потому что OvR внутренне использует LabelBinarizer и пытается выделить матрицу измерений (y x classes), которую довольно трудно выделить. Что мне делать?
  4. Любые другие библиотеки, которые имеют надежные масштабируемые алгоритмы с множеством меток &? Я знаю о гениальности & mahout, но у обоих из них нет ничего для многоэлементных ситуаций?
+2

Просто замечание, когда вы говорите «HashVectorizer, который лучше, но не то, что масштабируемый»: ' HashVectorizer' отлично масштабируется: если вы выбросите в два раза больше вычислительного ресурса, вы будете обрабатывать данные в два раза быстрее (вы можете разделить данные и запустить обработку параллельно, благодаря ее безгражданству и ограниченному использованию памяти). Это точное определение масштабируемости. Я согласен с тем, что «HashVectorizer», вероятно, может быть более оптимизирован для более быстрой работы на одних и тех же вычислительных ресурсах, но это не имеет ничего общего с проблемой масштабируемости. – ogrisel

+0

Спасибо за разъяснение. Я согласен с тем, что HV действительно выгодно по сравнению с Tfidf, я не был уверен в части разделения данных. Теперь я сделал небольшой POC для разделения данных и запуска HV на частях отдельно, а затем объединить результаты позже. Первоначально я имел в виду, что работа над частью алгоритма - большое достижение, но все же его можно сделать более масштабируемым, как вы предложили разделить и запустить параллельно. (После того, как я это сделал, я отправлю PR, чтобы HV также имел параметр n_jobs) –

+0

К сожалению, в текущей реализации joblib, используемой в scikit-learn, мы используем многопроцессорность, поэтому входные данные должны быть скопированы для отправки к подпроцессам. Таким образом, такой параметр n_jobs добавит существенные накладные расходы и может быть не совсем полезен. Если у вас действительно есть большой набор данных, лучше обрабатывать множество параллельных сквозных циклов, которые имеют дело с доступом к данным (диск, БД, сеть ...), чтобы избежать копирования любой копии. Однако такой код котловой плиты, вероятно, никогда не будет включен в scikit-learn как слишком конкретный проект/каркас. – ogrisel

ответ

7

Я бы сделал многомаркетную часть вручную. OneVsRestClassifier рассматривает их как независимые проблемы. Вы можете просто создать n_labels много классификаторов, а затем вызвать partial_fit на них. Вы не можете использовать конвейер, если хотите только хэш-код (который я бы посоветовал). Не уверен, что ускоритель хеширования вектора. Вы должны спросить @Larsmans и @ogrisel для этого;)

Имея partial_fit на OneVsRestClassifier, было бы неплохим дополнением, и на самом деле я не вижу в нем конкретной проблемы. Вы также можете попытаться реализовать это самостоятельно и отправить PR.

+0

Я просто печатал :) –

+0

Я не удивлен;) –

+0

Спасибо, если бы я должен был ввести OvR вручную, какую оценку вы бы порекомендовали для этой проблемы? Также, скажем, я запускаю 35 тыс. Оценок (n_labels) и индивидуально вписываю их в данные обучения. Как я могу вычислить эти метки? Эти оценки с индивидуальным представлением_proba> 0,5 будут иметь свои метки, связанные с этим образцом. Будет ли этот подход работать? (извините, мне всего 3 недели в ML & sklearn) –

8
  1. Алгоритм, который OneVsRestClassifier реализует очень прост: он просто подходит K бинарных классификаторов, когда есть K классы. Вы можете сделать это в своем собственном коде вместо того, чтобы полагаться на OneVsRestClassifier. Вы также можете сделать это не более K ядра параллельно: просто запустите K процессов. Если у вас больше классов, чем процессоров на вашем компьютере, вы можете запланировать обучение с помощью такого инструмента, как GNU parallel.
  2. Многоядерная поддержка в scikit-learn - это незавершенная работа; мелкомасштабное параллельное программирование в Python довольно сложно. Существуют потенциальные оптимизации для HashingVectorizer, но я (один из авторов хеширующего кода) еще не пришел к нему.
  3. Если вы следуете моим советам (и Андреасу), чтобы сделать свой собственный однополярный отдых, это больше не должно быть проблемой.
  4. Трюк в (1.) применяется к любому алгоритму классификации.

Что касается количества функций, это зависит от проблемы, но для крупномасштабной классификации текста 2^10 = 1024 кажется очень мало. Я бы попробовал что-то около 2^18 - 2^22. Если вы тренируете модель со штрафом L1, вы можете позвонить sparsify на обученной модели, чтобы преобразовать ее весовую матрицу в более компактный формат.

+0

Спасибо, я попытаюсь реализовать OvR вручную и попытаюсь обойти проблемы масштабируемости. Я забыл упомянуть, что длина каждого документа очень маленькая (200 слов или около того). Итак, я понял, что 1024 функций должно быть достаточно, потому что 2^18 давали мне много проблем с памятью. Я даже дошел до того, что выпустил экземпляр AWS объемом 30 ГБ, но это тоже не сработало. –

+2

Если у вас есть 35K двоичные классификаторы с 2 ** 18 функциями, вам потребуется 73GB только для хранения агрегатной модели. Возможно, будет возможно разрешить модели после того, как весы будут извлечены, чтобы освободить память во время прогнозирования, но AFAIK это еще не реализовано в scikit-learn. Вы можете реализовать 'decision_function' вручную с помощью' safe_sparse_dot' для этого. – ogrisel

+1

Чтобы обучить модели с большим количеством нулевых весов, что приведет к улучшению использования памяти, как только атрибут 'coef_' будет храниться как матрица' scipy.sparse', вы должны использовать 'SGDClassifier' с' штрафом = "elasticnet" или ' l1" '. – ogrisel

0

Метод partial_fit() был recently добавлен в sklearn, так что, надеюсь, он должен быть доступен в предстоящем выпуске (он уже находится в ведущей ветке).

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

1

Моим аргументом в пользу масштабируемости является то, что вместо использования OneVsRest, который является простейшим из простейших базовых линий, вы должны использовать более совершенный ансамбль методов преобразования проблем. В моем paper я предоставляю схему разделения пространства меток на подпространства и преобразования подзадач в одноклассовые классификации с несколькими классами с использованием Label Powerset. Для того, чтобы попробовать это, просто используйте следующий код, который использует библиотеку мульти-лейбл, построенный на вершине scikit учиться - scikit-multilearn:

from skmultilearn.ensemble import LabelSpacePartitioningClassifier 
from skmultilearn.cluster import IGraphLabelCooccurenceClusterer 
from skmultilearn.problem_transform import LabelPowerset 

from sklearn.linear_model import SGDClassifier 

# base multi-class classifier SGD 
base_classifier = SGDClassifier(loss='log', penalty='l2', n_jobs=-1) 

# problem transformation from multi-label to single-label multi-class 
transformation_classifier = LabelPowerset(base_classifier) 

# clusterer dividing the label space using fast greedy modularity maximizing scheme 
clusterer = IGraphLabelCooccurenceClusterer('fastgreedy', weighted=True, include_self_edges=True) 

# ensemble 
clf = LabelSpacePartitioningClassifier(transformation_classifier, clusterer) 

clf.fit(x_train, y_train) 
prediction = clf.predict(x_test) 

 Смежные вопросы

  • Нет связанных вопросов^_^