BERTとLUKEの感情分析の精度を比較してみた（既存のモデルvs自作のモデル）

こんにちにゃんです。
水色桜（みずいろさくら）です。
今回は[前回の記事](https://qiita.com/Mizuiro__sakura/items/2dd4430cdee689dc2ddc)で作成したLUKEでの感情分析モデルと[既存のモデル（BERT）](https://huggingface.co/daigo/bert-base-japanese-sentiment)の精度面の比較を行っていこうと思います。

# 結論

感情スコアベースの比較では、作成したモデルは既存のモデルより、高い正答率となり、誤差も小さかった。

```ruby:
BERTを用いた際の誤差は0.4051273187220645
BERTを用いた際の正答率は66.17647058823523%
LUKEを用いた際の誤差はtensor(0.2993, grad_fn=<AddBackward0>)
LUKEを用いた際の正答率は73.5294117647058%
```

作成した感情分析モデルを使用してみたいという方は下記の記事から使用してみてください。初心者でも簡単に使用できるようになっています。

https://qiita.com/Mizuiro__sakura/items/2dd4430cdee689dc2ddc

# LUKE

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/b99058df-c555-4748-a086-cec1d2976451.png)

2020年4月当時、5つのタスクで世界最高精度を達成した新しい言語モデル。
日本語バージョンのLUKEは執筆現在（2022年12月）も4つのタスクで最高スコアを有しています。RoBERTaを元として構成され、entity-aware self-attentionという独自のメカニズムを用いています。LUKEに関して詳しくは下記記事をご覧ください。

https://qiita.com/Mizuiro__sakura/items/9ccbd655501e78df5cc6

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/9c24ffb7-0664-36ce-9b0d-5c9b406c6484.png)



# 比較手法
下記のコードと文章群を用いて、それぞれのモデルについて正答率と誤差を算出しました。

<details><summary>analysis.py</summary>

```python:analysis.py
import torch
from transformers import MLukeTokenizer
from torch import nn 
import re
from transformers import pipeline, AutoModelForSequenceClassification, BertJapaneseTokenizer

with open('Sentiment_accuracy_analysis2.txt', encoding = 'utf-8') as file:
    text_pre = file.read()
    text = re.split('\n|　', text_pre)


model_bert = AutoModelForSequenceClassification.from_pretrained('daigo/bert-base-japanese-sentiment') 
tokenizer_bert = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
nlp = pipeline("sentiment-analysis",model=model_bert,tokenizer=tokenizer_bert)

num_bert = 0
num_luke = 0
acc_bert = 0
acc_luke = 0

for i in range(len(text)//2):
            result=nlp(text[2*i])
            num=re.findall(r'\d+',str(result))
            num0='0.'+num[1]
            value=float(num0)
            teacher = float(text[2*i+1])
            if value>0.95 and teacher>0.5:
                acc_bert += 2/(len(text))
            elif value <0.95 and teacher <0.5:
                acc_bert += 2/(len(text))
            num_bert+=(teacher - value)**2/(len(text)//2)

print('BERTを用いた際の誤差は' + str(num_bert))
print('BERTを用いた際の正答率は' + str(acc_bert*100) + '%')

tokenizer = MLukeTokenizer.from_pretrained('studio-ousia/luke-japanese-base-lite')
model = torch.load('My_luke_model_pn.pth')

for i in range(len(text)//2):
    encoded_dict = tokenizer.encode_plus(
                            text[2*i],                     
                            return_attention_mask = True,   # Attention maksの作成
                            return_tensors = 'pt',     #  Pytorch tensorsで返す
                    )

    pre = model(encoded_dict['input_ids'], token_type_ids=None, attention_mask=encoded_dict['attention_mask'])
    SOFTMAX=nn.Softmax(dim=0)
    num=SOFTMAX(pre.logits[0])
    teacher = float(text[2*i+1])
    if num[1] < 0.95 and teacher < 0.5:
        acc_luke += 2/(len(text))
    elif num[1] > 0.95 and teacher > 0.5:
        acc_luke += 2/(len(text))
    num_luke += (num[1] - teacher)**2/(len(text)//2)

print('LUKEを用いた際の誤差は' + str(num_luke))
print('LUKEを用いた際の正答率は' + str(acc_luke*100) + '%')
```

</details>

<details><summary>分析に用いた文章群</summary>
今日は楽しかった　１
おいしいスイーツを食べられて幸せだった　１
美玲さんの歌声は最高だ　１
なんか今日は調子が良い　１
この商品は使い心地がいい　１
お姉さんは優しい　１
あの人はハンサムだ　１
この紅茶は香りが上品だ　１
このクリームを使ってから肌がいい感じだ　１
この本はとても役に立った　１
学校で褒められてうれしかった　１
私は優香ちゃんのことが好きだ　１
先生は優しくて好きだ　１
この前のライブは最高だった　１
プレゼントをもらえてうれしかった　１
四つ葉のクローバーが見つかって幸せな気持ちになった　１
このクッキーはとてもおいしい　１
家でまったり過ごすのも悪くない　１
彼女は怒らないので好きだ　１
このピーマンは苦くないので、食べられる　１
サッカーをするのは楽しい　１
このはさみは様々な機能があって役に立つ　１
優しいあなたが好き　１
この商品は状態が良い　１
梱包も丁寧で素晴らしい　１
昨日家に来た人は感じが良かった　１
今日は遊園地に行って楽しかった　１
このコードは読みやすい　１
この講義は内容がわかりやすい　１
あなたのことを一生愛し続けると誓う　１
寝顔さえも愛おしい　１
この香りは好ましい　１
剣道の試合はやっぱり楽しい　１
お母さんに褒められてうれしかった　１
今日は雨が降って気分も落ち込む　０
テストで赤点をとってへこんだ　０
お母さんに怒られて最悪だった　０
すぐ壊れるなんてありえない　０
この芳香剤はにおいがきつくて苦手だ　０
図書館にいったのに騒がしい人がいて嫌だった　０
昨日部活で突き指をしてしまって痛かった　０
スマホを落とした時、画面が割れてしまった　０
いつも怒ってばかりいる人は嫌いだ　０
お菓子を食べようと思ったら鳥に取られてしまった　０
イメージと全く違う商品が届いて怒りしかない　０
お正月に食べ過ぎて太ってしまった　０
本音が言えなくて苦しい　０
今日友達と喧嘩をしてしまい最悪だった　０
単身赴任で寂しい　０
新しい学校で友達ができなくてつらい　０
思いっきり転んでしまってけがをしてしまった　０
こんなプレゼントは全く嬉しくない　０
こんな些細なミスでチャンスを台無しにしてしまうなんて笑えない　０
この競技は全く楽しくない　０
子供が独り立ちして寂しくなる　０
この紅茶は苦くて苦手だ　０
あの芸人は不細工だ　０
あの人の話し方は下品だ　０
こんなに努力してるのに評価されないのは不満だ　０
負けたのに負けを認めないのは醜い　０
テントが簡素すぎてひいた　０
財布を落としてしまうなんて最悪だ　０
命乞いをするなんて美しくない　０
声が小さい人をみるといらだつ　０
相手が格下だと思ってあなどる　０
おばあちゃんが亡くなった　０
最後の最後に負けてしまうなんて最悪だ　０
いかがわしいコンテンツが表示された　０
</details>

# 終わりに
今回作成したモデルは既存モデルより若干精度が良かったとはいえ、遠回しな言い回しなどに関してはまだ正確に判定できない部分もあります。
今後より精度の高いモデルを構築できるように微調整をしていこうと思います。
では、ばいにゃん～。

# 参考
著者である山田先生には感謝いたします

https://arxiv.org/abs/2010.01057