1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laya Multilingual と Open-Jev-DeBERTa-v3-large を RTX 5080 Laptop で日本語感情分類してみた

1
Posted at

先に結論

Laya Multilingual と Open-Jev-DeBERTa-v3-large を、公開されている日本語感情分類データセットで比較しました。

今回の条件では、精度は Open-Jev-DeBERTa-v3-large が上でした。
一方で、推論速度は Laya Multilingual がかなり速いです。

モデル Accuracy Macro F1 Brier ECE(15) 平均処理時間/件 Throughput
Open-Jev-DeBERTa-v3-large 95.92% 95.61% 0.0334 0.0420 18.32 ms 54.58/s
Laya Multilingual 92.36% 91.94% 0.0673 0.0526 3.09 ms 323.50/s

ざっくり言うと、こうです。

  • 精度優先なら Open-Jev-DeBERTa-v3-large
  • 速度・多言語・軽さ優先なら Laya Multilingual
  • どちらもテキスト生成モデルではなく、選択肢に対する確率分布を返す decision model
  • 日本語で使うなら、モデルカードの説明だけではなく、自分のタスクで実測した方がよい

特に今回面白かったのは、Open-Jev-DeBERTa-v3-large はモデルカード上では English model なのに、日本語レビュー感情分類ではかなり強かったことです。
もちろん、これをもって「日本語汎用に強い」とは言えません。
ただ、binary sentiment のような比較的単純なタスクでは、DeBERTa-v3-large の表現力と sentiment 系の学習データが効いている可能性があります。

今回やったこと

やったことは単純です。

  1. Laya Multilingual をローカルにロードする
  2. Open-Jev-DeBERTa-v3-large をローカルにロードする
  3. 同じ日本語レビューを渡す
  4. 同じ negative / positive の二択で答えさせる
  5. Accuracy、Macro F1、Brier、ECE、速度を比較する

評価データは Hugging Face の sbintuitions/JMTEB に含まれる japanese_sentiment_classification の test split を使いました。
JMTEB のデータセットカードでは、この Japanese Sentiment Classification は train 9,831 / dev 1,677 / test 2,552 件とされています。

今回使った test split は次の分布でした。

label 件数
negative 934
positive 1,618
合計 2,552

モデルの位置づけ

Laya Multilingual

Laya Multilingual は、非自己回帰型の System 1 decision model です。

通常の LLM のように文章を生成するのではなく、

  • state
  • typed question
  • options / criteria

を渡すと、選択肢ごとの確率を返します。

モデルカードでは、100+ languages を対象にした checkpoint と説明されています。
Laya family の中では、英語以外の入力には convaiinnovations/laya-multilingual を使う、という位置づけです。

今回のような二値分類なら、Laya には次のように渡します。

import laya

agent = laya.load("convaiinnovations/laya-multilingual", device="cuda")

state = "毎回使って居て綺麗に仕上がるし、値段も安く買えてお得です。"

questions = {
    "sentiment": {
        "type": "choice",
        "instructions": (
            "この日本語レビューを感情分類してください。"
            "選択肢: negative = 否定的、不満、低評価。"
            "positive = 肯定的、満足、高評価。"
        ),
        "criteria": ["negative", "positive"],
    }
}

result = agent.predict(state, questions)
print(result["answers"]["sentiment"])

出力はだいたいこういう形です。

{
    "type": "choice",
    "choice": "positive",
    "probabilities": {
        "negative": 0.0008,
        "positive": 0.9992,
    },
    "confidence": 0.9909,
}

ここで大事なのは、生成結果をパースしているのではないことです。
最初から choice と確率分布が返ります。

Open-Jev-DeBERTa-v3-large

Open-Jev-DeBERTa-v3-large も、Jev-shaped typed-decision model です。

こちらも文章生成ではなく、

  • choice
  • score
  • noul

という typed question に対して、選択肢ごとの確率分布を返します。

モデルカードによると、backbone は DeBERTa-v3-large で、choice は最大 255 options、score は 2〜10 ordered levels、noul は yes/no を扱います。

最小コードは次です。

from typed_decisions.open_jev import OpenJev

model = OpenJev.from_pretrained(
    "com-kotobalabs/open-jev-deberta-v3-large",
    device="cuda",
)

state = "毎回使って居て綺麗に仕上がるし、値段も安く買えてお得です。"

questions = [
    {
        "type": "choice",
        "instructions": (
            "この日本語レビューを感情分類してください。"
            "選択肢: negative = 否定的、不満、低評価。"
            "positive = 肯定的、満足、高評価。"
        ),
        "options": ["negative", "positive"],
    }
]

result = model.decide(state, questions)
print(result[0])

出力例です。

{
    "choice": "positive",
    "probabilities": {
        "negative": 0.0077,
        "positive": 0.9923,
    },
    "confidence": 0.9923,
}

こちらも同じく、自由生成ではありません。
業務システムから見ると、これはかなり扱いやすいです。

検証環境

今回の実行環境です。

項目 内容
GPU NVIDIA GeForce RTX 5080 Laptop GPU
PyTorch 2.14.0+cu130
CUDA 13.0
Python 3.13.2
transformers 4.57.6
datasets 5.0.1
laya 0.3.4
typed-decisions GitHub 版
評価データ sbintuitions/JMTEB / japanese_sentiment_classification / test
評価件数 2,552
batch size 16

RTX 50 系はまだ環境差が出やすいので、古い PyTorch を使うと CUDA が見えない、またはカーネル周りで落ちる可能性があります。
今回は uv の --torch-backend cu130 で CUDA 13.0 対応の PyTorch を入れました。

セットアップ

uv で環境を作る

まず仮想環境を作ります。

mkdir laya-openjev-ja-bench
cd laya-openjev-ja-bench

env UV_CACHE_DIR="$PWD/.uv-cache" uv venv .venv

依存関係を入れます。

env UV_CACHE_DIR="$PWD/.uv-cache" \
  uv pip install -p .venv/bin/python --torch-backend cu130 \
  torch torchvision datasets laya \
  git+https://github.com/kotoba-lang/typed-decisions

手元では torchvision も明示的に入れました。
理由は、transformers が内部で vision 系の import を踏むことがあり、環境によってはシステム側の torchvision と PyTorch の組み合わせがずれて落ちるからです。

Hugging Face のキャッシュを固定する

WSL、Docker、社内環境、Kaggle などでは、デフォルトのキャッシュディレクトリに書けないことがあります。
そのため、最初から作業ディレクトリ配下に固定しておく方が安全です。

export USE_TF=0
export HF_HOME="$PWD/.hf-cache"
export HF_HUB_CACHE="$PWD/.hf-cache/hub"
export HF_DATASETS_CACHE="$PWD/.hf-cache/datasets"

USE_TF=0 も入れています。
Laya のモデルカードにも注意がありますが、TensorFlow が入っている環境で transformers の import が余計な経路を踏むことがあります。
今回の用途では TensorFlow は不要なので、切っておくのが無難です。

Kaggle で動かす場合

Kaggle Notebook なら、最初のセルはだいたいこうです。

!pip install -U torch torchvision datasets laya
!pip install git+https://github.com/kotoba-lang/typed-decisions

Python 側では、キャッシュと TensorFlow 無効化を先に入れます。

import os

os.environ["USE_TF"] = "0"
os.environ["HF_HOME"] = "/kaggle/working/.hf-cache"
os.environ["HF_HUB_CACHE"] = "/kaggle/working/.hf-cache/hub"
os.environ["HF_DATASETS_CACHE"] = "/kaggle/working/.hf-cache/datasets"

Kaggle は GPU の種類が毎回同じとは限らないので、最初に確認します。

import torch

print(torch.__version__)
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "no cuda")

評価コードの要点

データセットはこれで読めます。

from datasets import load_dataset

ds = load_dataset(
    "sbintuitions/JMTEB",
    "japanese_sentiment_classification",
    split="test",
)

print(ds)
print(ds[0])

ラベルは今回のデータでは次のように扱いました。

LABELS = {
    0: "negative",
    1: "positive",
}

両モデルに渡した質問文は同じです。

QUESTION = (
    "この日本語レビューを感情分類してください。"
    "選択肢: negative = 否定的、不満、低評価。"
    "positive = 肯定的、満足、高評価。"
)

ここは意外と重要です。

モデルの比較でよくある罠は、片方だけに丁寧なプロンプトを渡してしまうことです。
今回は、Laya 側は criteria、Open-Jev 側は options という API 差分はありますが、ラベル名と説明は揃えました。

結果

改めて結果です。

モデル Accuracy Macro F1 Positive F1 Negative F1 Brier Log loss ECE(15)
Open-Jev-DeBERTa-v3-large 95.92% 95.61% 96.78% 94.44% 0.0334 0.1345 0.0420
Laya Multilingual 92.36% 91.94% 93.78% 90.10% 0.0673 0.3124 0.0526

混同行列は次です。

モデル TP TN FP FN
Open-Jev-DeBERTa-v3-large 1564 884 50 54
Laya Multilingual 1470 887 47 148

Open-Jev は false negative がかなり少ないです。
今回の test set は positive が多いので、ここが Accuracy と Macro F1 の差に効いています。

一方で速度は Laya が圧倒的です。

モデル 推論時間 平均処理時間/件 Throughput
Laya Multilingual 7.89 sec 3.09 ms 323.50/s
Open-Jev-DeBERTa-v3-large 46.76 sec 18.32 ms 54.58/s

ここでの平均処理時間/件は、batch size 16 のバッチ処理時間を件数で割った値です。
API の単発リクエストの p95 latency とは別物です。
オンライン API 的に使うなら、batch size 1 でも測った方がよいです。

食い違いを少し見る

両モデルの正誤関係はこうでした。

パターン 件数
両方正解 2,306
両方不正解 53
Open-Jev のみ正解 142
Laya のみ正解 51
予測ラベルが食い違い 193

Open-Jev のみ正解だった例には、短くて少し婉曲な positive review が多めに見えました。

例:

ちょうど旅行に行ったのでこれくらいないと印刷ができない。いっぱい入ってておとくです

gold は positive ですが、Laya は negative、Open-Jev は positive でした。

Laya のみ正解だった例もあります。

安かったかどうか良くわかりませんが、まあこんなもんでしょうね。印刷問題なしです。

これは gold positive で、Laya は positive、Open-Jev は negative でした。

このあたりを見ると、単純な正解率だけではなく、自分のドメインに多い文体で見る必要があります。
EC レビュー、問い合わせ、社内チケット、監査コメントでは、同じ sentiment でも表現がかなり違います。

踏みやすい地雷

1. RTX 50 系では PyTorch のバージョンを疑う

RTX 5080 Laptop は新しい GPU なので、古い PyTorch だと CUDA が見えないことがあります。
まずこれを確認します。

import torch

print(torch.__version__)
print(torch.version.cuda)
print(torch.cuda.is_available())
print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "no cuda")

torch.cuda.is_available() が False のままなら、モデル比較以前の問題です。

2. Hugging Face の cache path は固定した方がいい

今回、デフォルトの cache path が root 配下になり、通常実行では lock file を作れずに落ちました。

最初からこうしておくのが安全です。

export HF_HOME="$PWD/.hf-cache"
export HF_HUB_CACHE="$PWD/.hf-cache/hub"
export HF_DATASETS_CACHE="$PWD/.hf-cache/datasets"

Docker や CI でも同じです。
「一度ダウンロードしたのに、次の実行でなぜか落ちる」という事故を避けられます。

3. Laya は USE_TF=0 を入れておく

TensorFlow が入っている環境では、transformers が不要な TensorFlow 側の probe を踏むことがあります。
今回のタスクでは使わないので、切っておく方が安全です。

export USE_TF=0

4. torchvision の不整合で落ちることがある

手元では Laya ロード時に torchvision::nms 周りのエラーが出ました。
原因は、venv 側の PyTorch と、システム側の torchvision の組み合わせがずれていたことです。

venv 内に対応する torchvision を入れると解消しました。

uv pip install -p .venv/bin/python --torch-backend cu130 torchvision

モデルの問題に見えて、実は import 経路の問題というやつです。

5. 確率はそのまま信用しすぎない

Laya のモデルカードにも calibration の注意があります。
Open-Jev も Brier / ECE は悪くありませんでしたが、それでも本番で確率を閾値制御に使うなら、自分のデータで calibration を見た方がよいです。

分類ラベルだけを見るのか。
確率を使って human review に回すのか。
ここで必要な評価指標が変わります。

どちらを使うべきか

今回の結果だけで判断するなら、次のようになります。

Open-Jev-DeBERTa-v3-large が向いているケース

  • 日本語感情分類で精度を優先したい
  • 多少遅くてもよい
  • 二択、多択、score、yes/no を同じ API で扱いたい
  • 確率分布つきの structured output が欲しい
  • DeBERTa-v3-large クラスの重さを許容できる

今回の benchmark では、精度、Macro F1、Brier、ECE のすべてで Open-Jev が上でした。

Laya Multilingual が向いているケース

  • 多言語入力を扱う
  • throughput を重視する
  • 1 GPU に軽く載せたい
  • 大量の問い合わせやチケットを高速に振り分けたい
  • 多少の精度差より処理量が重要

Laya は速いです。
今回の条件では Open-Jev の約 6 倍の throughput が出ました。

日本語・英語・その他言語が混ざる業務で、まず高速に route したいなら Laya はかなり扱いやすい候補です。

最小の評価スクリプト

記事用に短くすると、評価ループはこういう形になります。

from datasets import load_dataset

ds = load_dataset(
    "sbintuitions/JMTEB",
    "japanese_sentiment_classification",
    split="test",
)

correct = 0

for row in ds:
    text = row["text"]
    gold = "positive" if row["label"] == 1 else "negative"

    pred, probs = predict_one(text)  # Laya または Open-Jev の wrapper

    if pred == gold:
        correct += 1

print(correct / len(ds))

実際には、次も保存した方がよいです。

  • gold label
  • predicted label
  • prob_negative
  • prob_positive
  • latency
  • text

あとから「どちらだけが間違えたのか」を見られるからです。
モデル比較で一番おいしいのは、平均値ではなく disagreement の中身です。

まとめ

今回の日本語感情分類では、Open-Jev-DeBERTa-v3-large が精度面で勝ちました。

ただし、Laya Multilingual はかなり速いです。
精度で 3.6 points ほど負けていますが、throughput は約 6 倍でした。

なので、結論は単純な「どちらが上か」ではありません。

  • 精度重視: Open-Jev-DeBERTa-v3-large
  • 速度・多言語・軽量運用重視: Laya Multilingual
  • 本番投入前: 必ず自分の文体、自分のラベル、自分の閾値で再評価

特に decision model は、生成 AI と違って出力形式が安定しています。
これは業務システムに組み込みやすいです。

一方で、確率が返るからといって、その確率がそのまま業務上の信頼度になるとは限りません。
分類の正解率、Brier、ECE、そして disagreement の実例まで見て、使う場所を決めるのが良いと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?