ChatGPTに5ch書き込みの有害性を判定させたら既存性能を超えた話

# 概要3行
* ChatGPT（gpt-3.5-turbo）でネット掲示板やTwitterの日本語書き込みの有害性を判定させてみた
* データセットは以下の論文で使われたものを用いた
* ~~結果としてはそこそこ良い精度（ROC-AUC値 0.846）が出たものの、論文の手法よりは少し低いものになった~~
* **ROC-AUCの計算方法を修正したところ、精度は論文の手法を上回った（ROC-AUC値 0.885）**

論文：

https://www.anlp.jp/proceedings/annual_meeting/2023/pdf_dir/D4-1.pdf

データセット：

https://github.com/inspection-ai/japanese-toxic-dataset/blob/main/README_ja.md



# 動機
* BERTとの比較をしてみたい
    * BERTをFine tuningするのと比べてどのくらい精度を出せるか知りたかった
* データセット構築に使えそう
    * Zero-shot でテキストを判定させてデータセットの構築に利用することにもともと興味があり、ChatGPTならより高品質なデータセットを簡単に構築できそうだと思った
    * そのデータセットからさらにモデルを作るのは規約的に議論がありそうだが、まずはやってみないと皮算用にすぎないのでとりあえずやってみた
* ネット上の暴言に傷つく人を少しでも減らしたい

# やったこと
ネット掲示板およびTwitterの日本語テキストの有害性評価つきデータセットがあったので、それをChatGPTに判定させてみた。
`gpt-3.5-turbo`のAPIを使い、プロンプトエンジニアリングで精度を上げていった。
最終的なプロンプトは以下に掲載するもののようになった。（一部伏せ字に変換しました。Qiita規約的に大丈夫なのか自信がなかったため。）

工夫した点としては、
* 出力内容を明記
    * 冒頭に出力してほしいものを明記することで出力を安定させた
* 役割の明記
    * `日本人の平均的な良識ある大人として` のように、役割を明確に定義した
    * 「日本のネット文化に詳しい専門家として」のように定義すると聞いてもいないことをベラベラと喋り始めるため却下した
    * 「有害性を判定するアノテーターとして」のように定義するとなぜかJSONデータを複数出力するようになってしまったためこれも却下した
* 出力フォーマットの例示・明示
    * 出力のサンプルを例示した
    * JSONフォーマットのみを出力させるために`（注）上記以外の項目は一切出力を禁止する。`などの文言を追加した
    * これでもまだJSON形式以外の文字列を出力することがあった（329件中6件）ため、そこはPythonで柔軟に対応した
    * JSONを全て出力させるために`"出力終了": ""` という文字列を最後に追加した。これがないと稀にJSON出力が途中で終わってしまうことがあった
* 出力順の調整
    * 先に有害性の評価や根拠を出力させ、それに続いて有害性分類を出力させた
    * 比較していないので効果は不明だが、頭から文字を出力していくChatGPTの仕組み的に根拠→評価値の順番に書かせたほうが辻褄のあった出力になるのではないかと期待したため
* 有害性分類定義の明確化
    * 当初は「有害性度合い」として有害性の強さを10段階で出力させていたが、その場合はROC-AUCは0.78程度だった。10段階だと真ん中あたりの値(5とか)の加減が付けにくそうだった
* `temperature`を0.0に設定
    * 出力を安定させるため
    * 役割を「平均的な」と定義したので、出力にまったく揺れがなくても支障はないだろうと考えた


# プロンプト
```
このプロンプトの最後に、日本のインターネット掲示板やTwitterから抽出した書き込みを掲載します。
あなたは日本人の平均的な良識ある大人として振る舞い、この書き込みに対して以下をJSONフォーマットで出力してください：
・下記の有害カテゴリで定義された内容に基づいて、この書き込みに対する有害性の評価とその根拠
・その評価に基づいた、書き込みの有害性分類（下記参照）
（注）上記以外の項目は一切出力を禁止する。

有害性分類は以下のように定義します：
0 => 書き込みの意味が不明瞭で判断が難しい場合
1 => 有害性が全くもしくはほとんどない場合
2 => 弱い有害性がある場合（例：足短いなぁ、ちょっとうるさい）
3 => 有害性がある場合（例：早く●くなってください、バカかよ、●●●、●●●、ブス）
4 => 強い有害性がある場合（例：はよ●●●●、ぶっ●すぞ）


また、書き込みを評価するにあたっては以下を考慮してください：
・多様な視点から書き込みの有害性を総合的に判断する
・誤字脱字や言葉足らず、文法の間違い、方言やインターネットスラングが多く含まれていることを考慮する
・「Twitterからの書き込み」という文字列は絶対に出力してはいけない

すべての出力は下記のような整形されたJSONフォーマットに従って作成してください：
{
  "有害性の評価とその根拠":"評価の説明文",
  "有害性分類":2,
  "出力終了": ""
}


有害カテゴリ：
・卑語
  - 人前で言うのが憚られる、卑しいもしくは汚い感じを与える言葉（「うんこ！うんこ！うんこ！」）
・罵倒語
  - 罵倒する際に使われる言葉（バカ、アホ、ブスなど）
・差別的
  - 人種差別（「バカチョンイライラ」など）
  - 性別差別（「男はATM」など）
  - 性的指向差別（「レズビアンは受け付けない」など）
  - 職業差別（「トラック運転手に低学歴が多いのはなぜ？」など）
  - 外見差別（「ブスには犯罪者が多い」など）
  - 宗教差別（「XXX 教徒は頭おかしい」など）
  - 政治差別（「XXX 党の支持者は白髪のジジババしか居ない」など）
  - 地域差別（「XX 人が一番嫌いだわ。頭が全員悪いから。」など）
  - 国籍差別（「移民のくせに偉そうなんだよ」など）
  - 年齢差別（「ジジイババアは早く死ね」など）
  - 市民権差別（「在留資格も無い、体調も悪いのになぜ帰らない？」など）
  - 障がい・病気差別（「障害者は死ね」など）
・迷惑行為
  - 侮辱・誹謗中傷（個人攻撃。「早く●ね」、「バカかよ」、「●ねハゲ」など）
  - 侮辱・誹謗中傷（集団・その他。「お前ら全員気持ち悪い。」など）
  - 暴力・脅し（「てめえぶち●してやる」など）
  - 自殺・自害（「今から自●する。さよなら。」など）
  - 非文・繰り返し（「ｇじょいあｇじおらｊごいあおあｒｊがおいおが；」など）
  - 扇動的行為（「負け組乙」など）
  - 嫌悪（「ハムスターを飲み込む」など）
  - 宣伝行為 起動するだけで1 万円配布します！」など）
・わいせつ
  - 卑猥表現（「SEX 大歓迎」など）
  - 性売買・風俗系（「本日 22 時からです♪会いに来てね #セクキャバ」など）
  - 成人用品系（「中年に効く激安精力剤はこれ！」など）
・違法行為
  - 違法薬物（「大麻売ります。」）
  - 模造
  - 品系（「当店はブランド用品のコピーを販売しております。」）
  - 金融系（「FX コピートレードは何もしません、口座開設するだけです！」）
  - 児童ポルノ（「児童ポルノ作品を売ります」）
  - 権利侵害、その他違法行為（「副作用のない薬を販売してます。」など）
・偏向表現
  - 政治（「XX 党が絶対正しい！」）
  - 宗教（「XXX 教は正しかった。」）
  - 専門予測（医療・法律・金融。（「来週 XXX の株価上がるよ。」）


書き込み：
(ここに実際の書き込みテキストが入る)
```

`有害カテゴリ`の部分は論文記載の内容をほぼそのまま記載したものです。`卑語`の説明と`罵倒語`の項目は私が追加しました（「バカ」のような単純で明確な罵倒語が有害と判定されにくかったため）。

# 結果
**論文のモデルおよび [Perspective API](https://perspectiveapi.com/)（有害性判定API）のどちらも上回る結果になった。**
~~有害性分類が3以上と判定されたものを陽性として扱い、ROC-AUCを計算した。~~
3以上を陽性として扱ったのはConfusion Matrixの方で、本記事の古いバージョンではROC-AUCの計算にもその値を使ってしまったため本来の値よりも低く出てしまっていた。

以下に既存手法の値（上記に掲載した論文から抽出）と合わせてテーブル形式でまとめた。
~~今回の手法は既存手法よりも少し劣る結果となったが、Few-shot Classificationであることを考えればわりと良い性能であるとも言える。~~


<table>

  <thead>
    <tr>
      <th>モデル</th> <th>ROC-AUC</th>
    </tr>
  </thead>
  <tr>
    <td> Perspective API</td> <td>.874</td>
  </tr>
  <tr>
    <td> 論文のモデル 10K（日本語）</td> <td>.878</td>
  </tr>
  <tr>
    <td><b>ChatGPT（GPT-3.5-turbo）</b></td> <td><b>.885</b>
.846
</td>
  </tr>
</table>

Confusion Matrixは以下のようになった。縦軸が実データ、横軸が予測値になっている：
![confusion_matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/96bba64f-a30c-256f-cf6d-f766f06bda2d.png)



# 誤判定データ
正例が少ないためか第1種の過誤を犯したデータが多くなっている。

<table>
    <thead>
      <tr>
        <th>テキスト</th> <th>正解</th><th>予測値（有害性分類）</th>
      </tr>
    </thead><tr><td>それこそ悪魔だわ</td><td>False</td><td>3</td></tr>
    <tr><td>母子家庭なら医療費タダなのに・・・</td><td>False</td><td>3</td></tr>
    <tr><td>彼女との記念日とか海外旅行とか会社の金でとかいろいろあるやろ</td><td>False</td><td>3</td></tr>
    <tr><td>高コスト払うならこっちから広域撃った方が気持ちいいからね仕方ないね</td><td>False</td><td>3</td></tr>
    <tr><td>それだけ嫉妬が隠せないってことだね</td><td>False</td><td>3</td></tr>
    <tr><td>監禁で元気になるの草</td><td>False</td><td>3</td></tr>
    <tr><td>イオン行ったら子供多いしすごい混んでてびびったわ</td><td>False</td><td>3</td></tr>
    <tr><td>辞めちまえば終わりが雇われ社長</td><td>False</td><td>3</td></tr>
    <tr><td>ゆるき汚水</td><td>False</td><td>3</td></tr>
    <tr><td>ここは日本だぞ</td><td>False</td><td>3</td></tr>
    <tr><td>地力が違うし</td><td>False</td><td>3</td></tr>
    <tr><td>草食わすなとか言い出さんのかな</td><td>False</td><td>3</td></tr>
    <tr><td>わいらい</td><td>False</td><td>3</td></tr>
    <tr><td>まず離婚という約束を守れよ</td><td>False</td><td>3</td></tr>
    <tr><td>本人に直接手出すなんて雑な仕事するわけないやろ</td><td>False</td><td>3</td></tr>
    <tr><td>三球三振で引導渡してやれ</td><td>False</td><td>3</td></tr>
    <tr><td>おまえは別の意味で惚れてる気がする</td><td>False</td><td>3</td></tr>
    <tr><td>合格した途端メガネキャラをあっさり捨てるあたりもな</td><td>False</td><td>3</td></tr>
    <tr><td>会えよ</td><td>False</td><td>3</td></tr>
    <tr><td>遠慮なく重ねろ</td><td>False</td><td>3</td></tr>
    <tr><td>ループ素材</td><td>False</td><td>3</td></tr>
    <tr><td>そろそろしっぺ返し来るで</td><td>False</td><td>3</td></tr>
    <tr><td>ずるいわ</td><td>False</td><td>3</td></tr>
    <tr><td>この人にキャスターやらせろよ</td><td>False</td><td>3</td></tr>
    <tr><td>特待生枠に入れるような子は一握り</td><td>False</td><td>3</td></tr>
    <tr><td>今からどんだけ捲れるか</td><td>False</td><td>3</td></tr>
    <tr><td>発行は違うけど請求はするだろ</td><td>False</td><td>3</td></tr>
    <tr><td>原因は何だったんだろ</td><td>False</td><td>3</td></tr>
    <tr><td>そのための安いやつだし</td><td>False</td><td>3</td></tr>
    <tr><td>なんたって犯罪がなかったことにされる可能性が高いんだから</td><td>False</td><td>3</td></tr>
    <tr><td>女子中高生のキャラクターが、温泉地のコンパニオンか何かと混同されてる</td><td>False</td><td>3</td></tr>
    <tr><td>おっさんが好きそうなの続くな</td><td>False</td><td>3</td></tr>
    <tr><td>そのクラスになると増やすためじゃなくて減らさないためにやってそうだな</td><td>False</td><td>3</td></tr>
    <tr><td>自分で言うことじゃないよな</td><td>False</td><td>3</td></tr>
    <tr><td>台湾場所か</td><td>False</td><td>3</td></tr>
    <tr><td>どこ経由で飼おうが自由じゃないかしら</td><td>False</td><td>3</td></tr>
    <tr><td>本</td><td>False</td><td>3</td></tr>
    <tr><td>人が居たら避けるだろ</td><td>False</td><td>3</td></tr>
    <tr><td>ハゲいらいらで草</td><td>True</td><td>2</td></tr>
    <tr><td>女のわけわからん話まじめに聞いてそうよな</td><td>True</td><td>2</td></tr>
    <tr><td>日本のはなしをしてるのにバカには分からなかったか</td><td>True</td><td>2</td></tr>
    <tr><td>あああああなああああたああああああああ</td><td>True</td><td>0</td></tr>
    <tr><td>だっさ</td><td>True</td><td>2</td></tr>

</table>



# 気づいたこと
* `この人にキャスターやらせろよ` も有害性アリと判定された。分類理由には`罵倒語に該当する「やらせろよ」が含まれており`とあり、どうも卑猥な言葉と判断された模様
* これ以外にもなぜか卑猥寄りに判定しがちだった。`今からどんだけ捲れるか`という書き込みがわいせつ扱いだった（`わいせつカテゴリに該当する卑猥表現が含まれている。`という理由）。「日本のインターネット掲示板」という冒頭の書き方が良くなかったかもしれない
* 逆に`ハゲいらいらで草`は有害性ナシ（弱い有害性はアリ）と判定された。理由は`罵倒語に該当する「ハゲ」という言葉が含まれており、他人を傷つける可能性がある。`で、可能性どまりだった。
* `自分で言うことじゃないよな` は`罵倒語に該当する。他人を貶める意図がある。`という理由で有害に判定された。確かに相手を否定する内容ではあるので、有害と言われると有害のような気がしてくる。
* `台湾場所か`は`差別的カテゴリに該当する。地域差別を助長する可能性がある。`という理由で有害に判定された。この他にも、データセットの正解と比べて差別に敏感な例が散見された。


# 今後の展望
プロンプトについてはかなり調整を繰り返したものの、役割設定や書き込みの出どころの定義、有害性分類についてはまだ改善の余地がありそう。
また、筆者の環境ではまだ GPT-4 を使うことができないためgpt-3.5-turbo を使ったが、GPT-4なら文脈理解の性能が向上すると期待され、上記のプロンプトでもさらなる精度向上が見込める。使えるようになり次第、検証してみたい。

https://openai.com/research/gpt-4


最後に、私個人の今後の展望になりますが就職先を募集しています。プロフィールは[ここ](https://www.wantedly.com/id/TomK)です。何かしら自然言語系をやれそうな会社があればプロフィール経由 or Twitter or コメントで教えていただけると幸いです。