Recruit Data Blog

  • はてなブックマーク

目次

はじめに

こんにちは。新卒2年目の中間です。業務では主にレコメンドシステムの改善に取り組んでいます。

今回は、2022年12月に終了したNishika社主催の「ヘイトスピーチ検出」という自然言語データを扱うコンペで準優勝することができたので、取り組みなどを紹介しようと思います。

コンペについて

参加しようと思ったきっかけ

私は、自然言語データを扱うコンペに何度か参加したことがありますが、その中でも日本語を扱うコンペにはあまり参加したことがありませんでした。そこで今回は、日本語を扱うコンペに参加することで、日本語に対する自然言語処理の知見を深めたいと思い、参加しました。

タスク

今回のコンペのタスクは、「掲示板に書き込まれた表現についてヘイトスピーチであるかどうかを判定する」というものでした。

提供されたデータ

今回のコンペで提供されたデータは、 おーぷん2ちゃんねる対話コーパス を使って運営側でラベル付けしたものでした。

評価指標

評価指標には、 F1 score が用いられました。

解法の紹介

こちら が私の解法です。 精度向上に大きく寄与した以下の要素について紹介します。

  • 外部データ
  • データの前処理
  • LUKE Japanese
  • Pretraining
  • Fixed epochs
  • Multi-sample dropout
  • Layer re-initialization
  • GRU layer after transformer output

外部データ

前述した通り、今回のコンペで提供されたデータは、 おーぷん2ちゃんねる対話コーパス を使って運営側でラベル付けしたものであったため、一部のラベル付けされていないデータは外部データとして利用することができました。今回は、外部データを用いてPretrainingとPseudo labeling1を行い、Pseudo labelingはあまり効果がありませんでしたが、Pretrainingは効果がありました。Pretrainingについては後ほど説明します。

1 学習時に用いてないデータに対する予測値を疑似的に目的変数として扱い、学習に利用する手法

データの前処理

外部データを使用する際には、コンペで提供されたデータとの整合性を保つ必要があります。今回、コンペで提供されたデータはテキストに一定の前処理がなされていたようで、外部データのテキストとの完全一致を確認できないものが存在しました。そこで、目検しつつどのような差分があるのかを確認し、同様の前処理がなされた状態となるように、以下のようなデータの前処理を行いました。このデータの前処理による精度の向上幅はわざわざ確認していませんが、不安要素は取り除いておくに越したことはないでしょう。

def clean_text(text):
    return text.replace(' ', '').replace(' ', '').replace('__BR__', '\n').replace('\xa0', '').replace('\r', '').lstrip('\n')

# コンペデータ
train['text'] = train['text'].apply(clean_text)
test['text'] = test['text'].apply(clean_text)

def replace_br(line):
    # 各文の先頭の改行記号は削除
    tmp = ""
    for l in line.split("\t"):
        tmp += re.sub(r'^( )+(__BR__ )+', '', l) + "\t"
    line = re.sub(r'\t$', "", tmp)
    # 置換
    line = clean_text(line)
    return line

def preprocess(input_file):
    texts = []
    with open(input_file) as f:
        for l in tqdm(f):
            l = l.strip()
            for text in replace_br(l).split('\t'):
                texts.append(text)
    return texts

# 外部データ
newsplus = preprocess(input_file=INPUT_DIR+'corpus/corpus/newsplus.tsv')
news4vip = preprocess(input_file=INPUT_DIR+'corpus/corpus/news4vip.tsv')
livejupiter = preprocess(input_file=INPUT_DIR+'corpus/corpus/livejupiter.tsv')
# of original_texts: 16069192  # of train_texts: 5256  # of train_common: 5256
# of original_texts: 16069192  # of test_texts: 3223  # of test_common: 3223

LUKE Japanese

LUKE Japanese は、2022年11月17日に公開された「 LUKE 」の日本語モデルです。コンペ締め切りの約2週間前に公開されたこともあり、参加者の中にはLUKE Japaneseを試していなかったという方も見受けられましたが、コンペ期間中に新しいモデルが公開されるということは珍しいことではないので、コンペ終盤でも情報収集は怠らないように気をつける必要があります。 このLUKE Japaneseという日本語モデルですが、BERTやRoBERTaの日本語モデルよりも優れた性能を獲得しており、実際にコンペで使ってみたところ、BERTやRoBERTaよりも優れた結果を得ることができました。今後、日本語の自然言語データを扱うコンペでは初手LUKE Japaneseが当たり前になるかもしれませんね。 また、今回のコンペ期間中には公開されていませんでしたが、2023年1月には DeBERTa V2の日本語モデル も公開されており、こちらも日本語の自然言語データを扱うコンペでは必ず試した方が良さそうです。

Pretraining

Don’t Stop Pretraining: Adapt Language Models to Domains and Tasks 」という論文があるように、あるドメインに対する精度を向上させるためには、Pretrainingが役に立ちます。 今回のコンペで扱うデータは おーぷん2ちゃんねる対話コーパス であり、掲示板特有の自然言語が数多く登場するため、そのようなドメインに対する精度を向上させるために、Pretrainingを行いました。具体的には、MLM(Masked Language Model)のPretrainingを行うことで、精度の向上につながりました。MLMのPretrainingを行うことによる精度向上は、過去の自然言語を扱うコンペでも報告されており、もはや試すのが当たり前となっているように感じます2

2 例: https://blog.recruit.co.jp/data/articles/kaggle-nbme-score-clinical-patient-notes/

Fixed epochs

今回のコンペで提供されたデータは、サンプルサイズが豊富ではなかったため、手元のスコアと暫定スコアの相関が取りにくい状況でした。私は普段validationデータでのスコアを参照しながら、ベストスコアを達成したepochのモデルの重みを保存するようにしているのですが、今回のコンペの場合は、スコアのぶれが激しくいわゆる「CVにoverfit」したスコアが頻出していたため、モデルの重みを保存するepoch数を固定して手元のスコアを見立てるようにしました。この手元のスコアをもとにして、最終スコアでもそこそこ良いスコアが出ているものを選択することができました。ただ、手元のスコアは低いにも関わらず、最終スコアで良いスコアが出ているようなものも存在し、やはりデータ量の問題は大きそうでした。

Multi-sample dropout

Multi-sample dropoutは、 Multi-Sample Dropout for Accelerated Training and Better Generalization という論文で紹介されている手法です。Kaggleの自然言語処理コンペでも実績のある手法で、BERTの出力に対して複数の異なるdropoutを適用してfully connected layerを通し、その平均を最終的な出力として学習を行います。Kaggleの自然言語処理コンペでは Google QUEST Q&A Labeling というコンペで使用され始め、そこから広く使われるようになった印象があります3

3 https://www.kaggle.com/competitions/google-quest-challenge/discussion/129840

Layer re-initialization

Layer re-initializationは、 Revisiting Few-sample BERT Fine-tuning という論文で紹介されているBERTのFine-tuning手法です。Kaggleの自然言語処理コンペでも実績のある手法で、特にサンプルサイズの少ないデータに対してBERTのFine-tuningをするときに効くことがあります。今回のコンペの場合、ラベル付けされたデータはサンプルサイズが少なかったため、この手法が効果的でした。Kaggleの自然言語処理コンペでは CommonLit Readability Prize というコンペで使用され始め、そこから広く使われるようになった印象があります4

4 https://www.kaggle.com/competitions/commonlitreadabilityprize/discussion/239770

GRU layer after transformer output

GRUまたはLSTMをBERTの出力の後に使用する手法はいつからかKaggleの自然言語処理コンペでよく使用されるようになりました。私は Feedback Prize - Predicting Effective Arguments というコンペでこの手法を適用して実際に精度が向上した経験があり、今回のコンペでも適用してみたところ、手元の精度が向上しました。

おわりに

最後まで読んでいただきありがとうございました。 結果としては、準優勝することができ、また日本語に対する自然言語処理の知見も深まり良かったです。

一緒に働きませんか?

リクルートというと、あまりKaggleのイメージはないかもしれませんが、多くのKagglerが在籍しています。2021年からKaggle部という部活も立ち上がり、月に一度LT会を開催し、知見を共有し合っています。自分が参加していないコンペの話など聞くことができ、非常に勉強になる場だと感じています。

当社では、様々な職種のエンジニアを新卒・中途ともに募集しております。ご興味のある方は、以下の採用ページをご覧ください。

中間康文

レコメンドシステムの改善を担当

中間康文

Kaggle Competitions & Notebooks Grandmaster。