Как использовать многоклассовую реализацию трубки для создания нескольких этикеток

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

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

Мотивация

Мотивация использовать трубку для создания нескольких этикеток проста. Snorkel позволяет нам использовать простые эвристики или ключевые слова для создания контролируемого набора данных. Использование его в качестве алгоритма маркировки дает определенный уровень ясности, когда нам нужно понять, почему образцу был присвоен определенный класс. Вы также можете подумать о сценарии, в котором вы создали эвристический алгоритм множественных меток, который назначает небольшое количество множественных меток; когда ваш продукт или функция требует большого количества мультиэтикеток, чтобы повысить ценность ваших клиентов.

Трубка

Стоит отметить, что на протяжении всего процесса мы фактически создаем два классификатора, первый из которых использует MajorityLabelVoter или LabelModel, первый дает нам большинство голосов в качестве базового, а первый Последний дает нам модель секретного соуса, которой славится Snorkel, а последняя предназначена для обучения алгоритму машинного или глубокого обучения (MLDL), потому что мы не хотим полагаться на созданные нами функции маркировки. Мы хотим обучить классификатор, который не ограничен нашими ключевыми словами, регулярными выражениями и т. Д. Нам нужен классификатор, который обобщает помимо того, что мы ему дали. В идеале он найдет корреляции, например, между токенами, которые мы не учли в процессе маркировки, с нашими окончательными метками.

Использование трубки для мультиклассов

Во-первых, нам нужно понять, как пользоваться Snorkel. Рассмотрим задачу классификации настроений и следующие предложения: 1. «торт был очень плохим на вкус», 2. «крем действительно хорош» и 3. «эта еда нормальная». Эти предложения являются ОТРИЦАТЕЛЬНЫМ, ПОЛОЖИТЕЛЬНЫМ и НЕЙТРАЛЬНЫМ соответственно. Поэтому мы создадим несколько LF, которым будет присвоена соответствующая метка.

from snorkel.labeling import labeling_function

@labeling_function()
def lf_keyword_good(x):
    return POSITIVE if "good" in x.text.lower() else ABSTAIN

@labeling_function()
def lf_keyword_bad(x):
    return NEGATIVE if "bad" in x.text.lower() else ABSTAIN
@labeling_function()
def lf_keyword_fair(x):
    return NEUTRAL if "fair" in x.text.lower() else ABSTAIN

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

from snorkel.labeling import LabelModel, PandasLFApplier

# Define the set of labeling functions (LFs)
lfs = [lf_keyword_bad, lf_keyword_good, lf_keyword_fair]

# Apply the LFs to the unlabeled training data
applier = PandasLFApplier(lfs)
L_train = applier.apply(df_train)

# Train the label model and compute the training labels
label_model = LabelModel(cardinality=3, verbose=True)
label_model.fit(L_train, n_epochs=500, log_freq=50)
df_train["label"] = label_model.predict(L=L_train, tie_break_policy="abstain")

df_train [«label»] также будет содержать ярлыки ABSTAIN, поэтому для дальнейшего обучения нашего вторичного классификатора нам придется их отфильтровать.

df_train = df_train[df_train.label != ABSTAIN]

Опять же, цель обучения вторичного классификатора (случайный лес в этом примере) на отфильтрованном наборе данных - «сделать обобщение за пределами охвата функций маркировки и LabelModel. — snorkel.org"

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
clf.fit(df_train.drop(['label'],axis=1), df_train["label"])

Использование трубки для нескольких этикеток

Шноркель можно использовать только в готовом виде в качестве этикетировщика для разных классов. Чтобы использовать его для Multi-label, вы можете использовать один из следующих трех методов:

  1. Используйте MajorityLabelVoter pred_proba () и назначьте все классы, у которых «вероятность» ≥ 0, то есть первый и последний [0,5, 0, 0,5]. Мы можем думать об этом как об образце, который находится в двух кластерах или двух ключевых словах из двух классов, что позволяет образцу иметь несколько меток. Например, «Гамбургер был хороший и плохой».
  2. Используйте LabelModel pred_proba и назначьте все классы, в которых вероятность выше "колена". Вы можете использовать Колени, чтобы разобраться. по сути, наши вероятности softmax, и только горстка получит высокие значения. Обратите внимание, что согласно моим эмпирическим тестам, существует высокая корреляция между значениями вероятности MajorityLabelVoter и LabelModel, то есть первое - это жесткий softmax, а второе - то, что вы ожидаете от softmax. то есть [0,5, 0, 0,5] против [0,45, 0,06, 0,49] соответственно.
  3. Обучите модели «один против всех» для каждого класса с помощью MajorityLabelVoter или LabelModel и назначьте мульти-метку в соответствии с прогнозом. Обратите внимание, что вам нужно продумать стратегию при рассмотрении ярлыков ABSTAIN.

Мульти-лейбл на практике

Поскольку «1» и «2» давали аналогичные результаты, а вычисление для получения нескольких меток из «1» было проще, я решил назначить несколько меток на основе 1.

Обратите внимание, что когда модель присваивает ярлык «ВОЗДЕРЖАЛСЯ», она не может решить, кто станет победителем. Мы наблюдаем такое поведение в выводе pred_proba (). Например, рассмотрим следующий вектор вероятности: [1.0, 0, 0], победитель здесь - первый класс. Теперь рассмотрим следующий вектор: [0.5,0, 0.5], мы видим, что это не явный победитель, поэтому Snorkel присвоит метку ABSTAIN.

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

В следующих кодах используется классификатор MajorityLabelVoter и присваиваются метки в соответствии со всеми классами, имеющими более высокий балл, чем ноль. Все очень просто :).

from snorkel.labeling import MajorityLabelVoter
from sklearn.preprocessing import MultiLabelBinarizer
Y = [['POSITIVE', 'NEGATIVE', 'NEUTRAL']]
# fit a MultiLabelBinarizer
mlb = MultiLabelBinarizer()
mlb.fit_transform(Y)
# create a majority vote model and predict
majority_model = MajorityLabelVoter(cardinality=3)
predictions = majority_model.predict_proba(L=L_test)
df_multilabel = pd.DataFrame()
df_multilabel['predict_proba'] = predictions.tolist()
# get all the non zero indices which are the multi labels
df_multilabel['multi_labels'] = df_multilabel['predict_proba'].apply(lambda x: np.nonzero(x)[0])
    
#transform to mlb for classification report
df_multilabel['mlb_pred'] = df_multilabel['multi_labels'].apply(lambda x: mlb.transform([x])[0])
print(df_multilabel.head())
#convert to str in order to see how many multi labels did we gain
multi_label_string = df_multilabel.multi_labels.apply(lambda x: ", ".join(le.inverse_transform(x)))
print(multi_label_string.value_counts()[:50])
# print some metrics using classification report 
y_pred = df_multilabel.mlb_pred.apply(lambda x: list(x)).to_numpy().tolist()
y_true = mlb.transform(Y.values).tolist()
print(classification_report(y_true, y_pred, target_names = mlb.classes_))

Вот и все, вы создали несколько этикеток для каждого образца. Пожалуйста, имейте в виду, что из-за этой методологии использования Snorkel, которая очень жадна с точки зрения стратегии маркировки, вы можете получить очень ВОСПОМИНОВАННУЮ модель. Ваш опыт будет отличаться.

Доктор Ори Коэн имеет докторскую степень. в области компьютерных наук с упором на машинное обучение. Он является ведущим специалистом по обработке данных в New Relic TLV, занимается исследованиями машинного и глубокого обучения в области AIOps.