Масштабируемые или интерактивные многоядерные классификаторы

Я задул свои мозги за последние 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)

Но это связано с серьезными проблемами:

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

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

Моим аргументом для масштабируемости является то, что вместо использования OneVsRest, который является просто простейшим базовым уровнем, вы должны использовать более совершенный ансамбль методов преобразования проблем. В моей статье я предлагаю схему разделения пространства меток на подпространства и преобразования подзадач в одноклассовые классификации с несколькими классами с использованием Label Powerset. Чтобы попробовать это, просто используйте следующий код, который использует библиотеку с несколькими метками, созданную поверх scikit-learn - 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)

Ответ 4

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

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