Повысьте производительность модели Transformer с помощью маркировки данных с помощью Active Learning

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

ActiveLab значительно снижает затраты на маркировку и время, затрачиваемое на достижение заданной производительности модели, по сравнению со стандартной аннотацией данных. В экспериментах, показанных в этой статье, ActiveLab достигает точности модели 90 % при затратах всего 35 % лейбла на стандартное обучение.

Что такое активное обучение?

Активное обучение помогает определить приоритет данных для маркировки, чтобы максимизировать производительность контролируемой модели машинного обучения, обученной на маркированных данных. Этот процесс обычно происходит итеративно — в каждом раунде активное обучение сообщает нам, для каких примеров мы должны собрать дополнительные аннотации, чтобы максимально улучшить нашу текущую модель при ограниченном бюджете на маркировку.

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

Что такое АктивЛаб?

ActiveLab — ​​это алгоритм активного обучения, который особенно полезен, когда аннотаторы зашумлены, потому что он помогает решить, когда нам следует собрать еще одну аннотацию для ранее аннотированного примера (чья метка кажется подозрительной) или для еще не аннотированного примера. После сбора этих новых аннотаций для пакета данных, чтобы увеличить наш набор обучающих данных, мы повторно обучаем нашу модель и оцениваем ее точность теста.

CROWDLAB — это метод оценки нашей уверенности в согласованной метке на основе данных с несколькими аннотаторами, который дает точные оценки с помощью взвешенного ансамбля вероятностного прогноза любой обученной модели p_M​ и отдельные метки, назначенные каждым комментатором j. ActiveLab формирует аналогичную взвешенную ансамблевую оценку, рассматривая выбор каждого аннотатора как вероятностное решениеp_j, выдаваемое другим предиктором:

ActiveLab решает перемаркировать данные, когда вероятность текущей согласованной метки для ранее аннотированной точки данных падает ниже нашей (исключительно основанной на модели) уверенности в предсказанной метке для неаннотированной точки данных.

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

Мотивация

Недавно я присоединился к Cleanlab в качестве Data Scientist и рад поделиться тем, как ActiveLab (часть нашей библиотеки с открытым исходным кодом, бесплатно доступная по лицензии AGPL-v3) можно использовать в различных рабочих процессах для улучшения наборов данных.

Здесь я рассматриваю задачу классификации бинарного текста: предсказать, является ли конкретная фраза вежливой или невежливой. По сравнению со случайным выбором примеров, для которых нужно собрать дополнительную аннотацию, активное обучение с помощью ActiveLab постоянно дает гораздо лучшие модели Transformer на каждом этапе (около 50% частоты ошибок), независимо от общей маркировки. бюджет!

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

Классификация вежливости текста

Набор данных, который я здесь рассматриваю, представляет собой вариант Стэнфордского корпуса вежливости. Он структурирован как задача классификации двоичного текста, чтобы определить, является ли каждая фраза вежливой или невежливой. Людям-аннотаторам дается выбранная текстовая фраза, и они дают (несовершенную) аннотацию относительно ее вежливости: 0 для невежливости и 1 для вежливости.

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

Что касается обучающих данных, то мы имеем:

  • X_labeled_full: наш начальный обучающий набор с небольшим набором из 100 текстовых примеров, помеченных двумя аннотациями для каждого примера.
  • X_unlabeled: большой набор из 1900 немаркированных текстовых примеров, которые мы можем рассмотреть с помощью аннотаторов.

Вот несколько примеров из X_labeled_full:

  1. Привет, хорошая статья. Что подразумевается под «спекулятивными таунхаусами»? Те, которые были созданы для потенциальных арендаторов, а не для постоянных покупателей
  • Аннотация (автор комментатора №61): вежливый
  • Аннотация (автор комментатора №99): вежливый

2. Поздравляю или пожелать удачи?

  • Аннотация (автор комментатора №16): вежливый
  • Аннотация (автор комментатора №22): невежливо

3. 4,5 миллиона обращений в Google показывают кампусы за пределами Колумбии. О чем ты говоришь?

  • Аннотация (автор комментатора №22): невежливо
  • Аннотация (автор комментатора №61): невежливо

Методология

Для каждого раунда активного обучения мы:

  1. Вычислите согласованные метки ActiveLab для каждого обучающего примера, полученные из всех аннотаций, собранных на данный момент.
  2. Обучите нашу модель классификации Transformer на текущем обучающем наборе, используя эти консенсусные метки.
  3. Оцените точность теста на тестовом наборе (который имеет высококачественные метки истинности).
  4. Запустите перекрестную проверку, чтобы получить предсказанные вероятности класса за пределами выборки из нашей модели для всего обучающего набора и немаркированного набора.
  5. Получите баллы активного обучения ActiveLab для каждого примера в обучающем наборе и немаркированном наборе. Эти баллы оценивают, насколько информативно было бы собрать еще одну аннотацию для каждого примера.
  6. Выберите подмножество (n = batch_size) примеров с наименьшими баллами за активное обучение.
  7. Соберите по одной дополнительной аннотации для каждого из n выбранных примеров.
  8. Добавьте новые аннотации (и новые ранее неаннотированные примеры, если они выбраны) в наш обучающий набор для следующей итерации.

Впоследствии я сравниваю модели, обученные на данных, помеченных с помощью активного обучения, с данными, помеченными с помощью случайного выбора. Для каждого раунда случайного выбора я использую консенсус большинства голосов вместо консенсуса ActiveLab (на шаге 1), а затем просто случайным образом выбираю n примеров для получения дополнительной метки вместо использования оценок ActiveLab (на шаге 6). ).

Обучение и оценка модели

Вот код, который мы используем для обучения и оценки модели, используя Библиотеку Hugging Face, которая предлагает множество современных сетей Transformer.

# Helper method to get accuracy and pred_probs from Trainer.
def compute_metrics(p):   
    logits, labels = p
    pred = np.argmax(logits, axis=1)
    pred_probs = softmax(logits, axis=1)
    accuracy = accuracy_score(y_true=labels, y_pred=pred)
    return {"logits":logits, "pred_probs":pred_probs, "accuracy": accuracy}

# Helper method to initiate a new Trainer with given train and test sets.
def get_trainer(train_set, test_set):
    
    # Model params.
    model_name = "distilbert-base-uncased"
    model_folder = "model_training"
    max_training_steps = 300
    num_classes = 2
    
    # Set training args.
    # We time-seed to ensure randomness between different benchmarking runs.
    training_args = TrainingArguments(
        max_steps=max_training_steps, 
        output_dir=model_folder,
        seed = int(datetime.now().timestamp())
    )
    
    # Tokenize train/test set.
    dataset_train = tokenize_data(train_set)
    dataset_test = tokenize_data(test_set)
    
    # Initiate a pre-trained model.
    model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=num_classes)
    trainer = Trainer(
        model=model,
        args=training_args,
        compute_metrics = compute_metrics,
        train_dataset = train_tokenized_dataset,
        eval_dataset = test_tokenized_dataset,
    )
    return trainer

Сначала я размечаю свои тестовые и обучающие наборы, а затем инициализирую предварительно обученную модель DistilBert Transformer. Точная настройка DistilBert с 300 шагами обучения дала хороший баланс между точностью и временем обучения для моих данных. Этот классификатор выводит прогнозируемые вероятности классов, которые я конвертирую в прогнозы классов перед оценкой их точности.

Используйте баллы активного обучения, чтобы решить, что маркировать дальше

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

from cleanlab.multiannotator import get_active_learning_scores

pred_probs, pred_probs_unlabeled = get_pred_probs(train_set, X_unlabeled)

# Compute active learning scores.
active_learning_scores, active_learning_scores_unlabeled = get_active_learning_scores(
    multiannotator_labels, pred_probs, pred_probs_unlabeled
)
# Get the indices of examples to collect more labels for.
chosen_examples_labeled, chosen_examples_unlabeled = get_idx_to_label(
    X_labeled_full,
    X_unlabeled,
    extra_annotations,
    batch_size_to_label,
    active_learning_scores,
    active_learning_scores_unlabeled,
)

Во время каждого раунда активного обучения мы подгоняем нашу модель Transformer с помощью 3-кратной перекрестной проверки на текущем обучающем наборе. Это позволяет нам получать прогнозируемые вероятности класса вне выборки для каждого примера в обучающем наборе, и мы также можем использовать обученный преобразователь, чтобы получать прогнозируемые вероятности класса вне выборки для каждого примера в немаркированном пуле. Все это внутренне реализовано во вспомогательном методе get_pred_probs. Использование прогнозов вне выборки помогает нам избежать систематической ошибки из-за возможного переобучения.

Получив эти вероятностные прогнозы, я передаю их в метод get_active_learning_scores из пакета cleanlab с открытым исходным кодом, который реализует алгоритм ActiveLab. Этот метод предоставляет нам оценки для всех наших размеченных и неразмеченных данных. Более низкие оценки указывают точки данных, для которых сбор одной дополнительной метки должен быть наиболее информативным для нашей текущей модели (оценки непосредственно сопоставимы между помеченными и неразмеченными данными).

Я формирую партию примеров с наименьшими оценками в качестве примеров для сбора аннотации (с помощью метода get_idx_to_label). Здесь я всегда собираю одинаковое количество аннотаций в каждом раунде (как при активном обучении, так и при случайном выборе). Для этого приложения я ограничиваю максимальное количество аннотаций на пример до 5 (не хочу тратить усилия на маркировку одного и того же примера снова и снова).

Добавление новых аннотаций

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

# Combine ids of labeled and unlabeled chosen examples.
chosen_example_ids = np.concatenate([X_labeled_full.iloc[chosen_examples_labeled].index.values, X_unlabeled.iloc[chosen_examples_unlabeled].index.values])

# Collect annotations for the selected examples.
for example_id in chosen_example_ids:
  # Collect new annotation and who it's coming from.
    new_annotation = get_annotation(example_id, chosen_annotator)
    
  # New annotator has been selected.
    if chosen_annotator not in X_labeled_full.columns.values:
        empty_col = np.full((len(X_labeled_full),), np.nan)
        X_labeled_full[chosen_annotator] = empty_col
    
    # Add selected annotation to the training set.
    X_labeled_full.at[example_id, chosen_annotator] = new_annotation

combined_example_ids — это идентификаторы текстовых примеров, для которых мы хотим собрать аннотацию. Для каждого из них мы используем вспомогательный метод get_annotation для получения новой аннотации от аннотатора. Здесь мы отдаем приоритет выбору аннотаций от аннотаторов, которые уже аннотировали другой пример. Если ни один из аннотаторов для данного примера не существует в обучающем наборе, мы выбираем его случайным образом. В этом случае мы добавляем новый столбец в наш обучающий набор, который представляет новый аннотатор. Наконец, мы добавляем только что собранную аннотацию в обучающий набор. Если соответствующий пример ранее не был аннотирован, мы также добавляем его в обучающую выборку и удаляем из немаркированной коллекции.

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

Полученные результаты

Я провел 25 раундов активного обучения (маркировка пакетов данных и переобучение модели Transformer), собирая 25 аннотаций в каждом раунде. Я повторил все это, в следующий раз используя случайный отбор, чтобы выбрать, какие примеры аннотировать в каждом раунде — в качестве базового сравнения. Перед аннотированием дополнительных данных оба подхода начинают с одного и того же начального обучающего набора из 100 примеров (таким образом достигается примерно одинаковая точность Transformer в первом раунде). Из-за присущей обучению Transformers стохастичности я запускал весь этот процесс пять раз (для каждой стратегии маркировки данных) и сообщал стандартное отклонение (заштрихованная область) и среднее значение (сплошная линия) точности теста для пяти повторных запусков.

Вывод. ActiveLab значительно сокращает время и затраты на маркировку для достижения заданной производительности модели по сравнению со стандартной аннотацией данных. Например, ActiveLab достигает точности модели 90 % при затратах всего 35 % от затрат лейбла на стандартное обучение.

Мы видим, что выбор того, какие данные аннотировать следующими, сильно влияет на производительность модели. Активное обучение с использованием ActiveLab постоянно превосходит случайный выбор со значительным отрывом в каждом раунде. Например, в раунде 4 с 275 аннотациями в тренировочном наборе мы получаем точность 91% благодаря активному обучению по сравнению с точностью всего 76% без умной стратегии выбора того, что аннотировать. В целом полученные модели Transformer, соответствующие набору данных, созданному с помощью активного обучения, имеют около 50% частоты ошибок, независимо от общего бюджета на маркировку.

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

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

Все изображения, если не указано иное, принадлежат автору.