Closed5

「mmBERT」を試す

kun432kun432

https://huggingface.co/blog/mmbert

Dia によるまとめ

mmBERTは「1800超の言語」を高速に理解できる最新多言語エンコーダだよ—しかもXLM-Rより強くて速いの、マジで。

これなに?一言で

mmBERTは、テキストを数値ベクトルに変換する「多言語エンコーダ」だよ。1800以上の言語で学習してて、古参のXLM-Rを初めて超えたって主張。しかもModernBERTの速さを受け継いで、実運用でも軽快ってのがアツいのだ。🔥

ざっくり特徴(まずは全体像)

  • めっちゃ多言語対応: 最終的に1,833言語で学習。低リソース言語もケア。
  • デカい学習量: 合計3兆トークン以上。英語は最大18%としつつ多言語もガッツリ。
  • 高速アーキ: ModernBERT由来でFlashAttention 2やアンパディングを採用、長文でも速い。
  • 8kトークン対応: 512に縛られてた昔の多言語モデルより、長文処理が余裕。
  • 成果: 英語NLUも多言語ベンチもXLM-Rを超え、検索系(MTEB v2)でも強い。コード検索もイケる。
  • 低リソース言語の「終盤学習」戦略が上手い:最後の短いフェーズで追加学習→性能グッと上がる。

ひと目でわかるスペックまとめ

項目 内容
モデル種別 多言語エンコーダ(Masked Language Model)
対応言語 最終フェーズで1,833言語
学習トークン数 約3T(前半2.3T → 中盤600B → 終盤100B)
文脈長 最大8192トークン
トークナイザ Gemma 2 ベース
モデル規模 small: 総140M(非埋め込み42M), base: 総307M(非埋め込み110M)
速度最適化 FlashAttention 2、アンパディング
代表ベンチ GLUE(英語)、XTREME(多言語)、MTEB v2(英/多言語)、CoIR(コード)

どう学習したの?(3段ロケット方式がミソ)

「よく出る言語から始めて、徐々に広げて、最後にめっちゃ薄く全言語へ」って流れ。学習サンプルの“偏り”をだんだん平らにしてくのがキモだよ。

  1. Pre-training(2.3T)
    • 言語数:60
    • マスク率:30%(たくさん隠して基本表現をガッツリ学ぶ)
    • データ:英語の高品質を厚めに(英語比率最大18%)
  2. Mid-training(600B)
    • 言語数:110
    • マスク率:15%
    • 文脈長を8192へ拡張、より高品質データへ
  3. Decay phase(100B)
    • 言語数:1,833(いきなり全言語ぶち込み)
    • マスク率:5%(細かい理解にシフト)
    • 学習率は逆平方根でデケイ
    • さらに「英語寄せ」「110言語」「全言語」の3モデルを並行で作って、最後にTIESでマージしてイイトコ取り

比喩で言うと、受験勉強で「まずは主要科目をガッツリ→範囲広げて応用→最後の直前期に弱点科目を薄く広くサッと固める」って感じだね。終盤の薄い当たり方でも、土台が強いから一気に吸収できるんだよね、ウケる。

データのこだわり

  • 英語高品質(DCLM/Filtered DCLM)を太めに確保して英語強さキープ。
  • FineWeb2(1,800+言語)で広範囲をカバー、さらにHQ版で20言語の高品質も足す。
  • 追加で、コード(StarCoder, ProLong)、論文・学術(ArXiv, PeS2o)、百科(Wikipedia, 教科書)、コミュニティ(StackExchange)、指示・数学データなどもミックス。
  • サンプリング温度をτ=0.7→0.5→0.3と下げて、だんだん均一寄りに。

新しい工夫(ここが“現代的”)

  • 逆マスク比スケジュール: 30%→15%→5%と下げることで、最初は荒く基礎、最後は精密。
  • 段階的言語追加: 60→110→1,833と増やして、低リソース言語を“回し過ぎない”工夫。
  • モデルマージ(TIES): 用途別に鍛えた複数モデルを最後に融合して「総合力」をブースト。

どれくらい強いの?(要点だけ)

  • 英語NLU(GLUE): 多言語モデルの中で強く、英語専用モデルにも肉薄。
  • 多言語(XTREME): XLM-Rを広く上回る。XNLIやTyDiQAが特に良い。
  • 検索系(MTEB v2 英語/多言語): 従来多言語モデルより強く、英語専用ModernBERTとも並ぶレベル。
  • コード検索(CoIR): Gemma 2系トークナイザが効いて強い。
  • ただしNER/POSなど「単語境界」がシビアな構造化タスクは、トークナイザ事情で伸びが限定的(前世代同等くらい)。この代わり“対応言語の広さ”は正義だし、用途次第だね。

低リソース言語への効き方が面白い

  • 最後の短いDecayフェーズで新規言語を追加しても、しっかり性能が伸びるのを示した(例:ティグライ語、フェロー語のQAでドカンと向上)。
  • でかいLLMよりも良い結果が出たケースもあって、基盤表現が効いてる感じ。
  • マージ後もその伸びをほぼキープ。ここ、実務的にめっちゃ嬉しいとこだよね。

速さと効率(ここ、運用目線で超大事)

  • Throughputが前世代多言語モデルより2〜4倍クラスで速い区間があるって主張。
  • FlashAttention 2とアンパディングでメモリ効率も改善。
  • 8192トークンの長文でもスピード維持しやすいから、長文要約・抽出・検索の土台に超向く。
  • 速い=推論コスト下がる=本番導入しやすい、だもん。

いつ使うのが良い?

  • 多言語の分類・検索・類似検索・QAのエンコーダ土台が欲しい時。
  • 英語だけじゃなく、低リソース言語も含むグローバル対応が要る時。
  • 長文(最大8k)を手早く食わせたい時。
  • NER/POSに全振りじゃないワークロード(ベクトル検索やNLU全般)に特に◎。

使い方のイメージ

  • マスク予測(提供のサンプル): テキストに <mask>入れて、埋める単語を予測。多言語でそのまま動く。
  • 埋め込みモデル化: Sentence TransformersでDPRやColBERT(マルチベクタ)に蒸留・微調整。
  • スパース検索: SPLADE系のロスでBM25っぽい疎ベクトルもOK。
  • リランカー: CrossEncoderとしてQAの再ランキングにも使える。
  • モデルは「jhu-clsp/mmBERT-small」「jhu-clsp/mmBERT-base」が公開。サンプルではモデルカードにlicense=“apache-2.0”の指定例もあるよ(実際のライセンスは各モデルカードで確認してね)。

ちょい実務Tips(短め)

  • まずsmallでPoC→足りなきゃbaseへ。VRAMがキツいならバッチ小さめ&BF16活用。
  • 多言語検索なら、Sentence Transformersで自分のコーパスに合わせて数エポック蒸留すると体感が変わること多い。
  • NER/POSはトークナイザ相性があるから、タスク専用に微調整して比較しよ。
  • 英語偏重じゃなくても強いので、海外ローカライズ案件の土台としてコスパ良し。

キミの環境だと長文処理と多言語検索の土台にちょうどハマりそう。必要なら、用途別(dense/multi-vector/sparse/reranker)の微調整レシピを、実データ前提で具体化するよ。どのタスクから攻める?😉✨

kun432kun432

mmBert-base を Colaboratory で試す。ランタイムは CPU で。

必要なパッケージはデフォルトですでに入っている。

pip freeze | egrep -i "torch|transformers"
出力
(snip)
torch==2.8.0+cu126
(snip)
transformers==4.56.1

ではUsageに従って。

from transformers import AutoTokenizer, AutoModel

tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/mmBERT-base")
model = AutoModel.from_pretrained("jhu-clsp/mmBERT-base")

inputs = tokenizer("こんにちは!", return_tensors="pt")
outputs = model(**inputs)
print(output)
出力
BaseModelOutput(last_hidden_state=tensor([[[ 0.3067,  0.0925,  0.1090,  ...,  0.0581,  0.1096,  0.2321],
         [-0.4184,  1.9025,  0.9804,  ..., -0.4715,  0.9599,  0.7419],
         [ 2.1417,  1.4769,  0.2067,  ..., -0.2386,  0.4229, -2.3545],
         [-2.2371, -0.0058,  1.7873,  ...,  0.1961,  1.0382, -0.9054],
         [ 0.1254,  0.2303,  0.0912,  ..., -0.0398,  0.3619, -0.3636]]],
       grad_fn=<NativeLayerNormBackward0>), hidden_states=None, attentions=None)

マスクされた言語モデリングの例

from transformers import AutoTokenizer, AutoModelForMaskedLM
import torch

tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/mmBERT-base")
model = AutoModelForMaskedLM.from_pretrained("jhu-clsp/mmBERT-base")

def predict_masked_token(text):
    inputs = tokenizer(text, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs)
    
    mask_indices = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)
    predictions = outputs.logits[mask_indices]
    top_tokens = torch.topk(predictions, 5, dim=-1)
    
    return [tokenizer.decode(token) for token in top_tokens.indices[0]]

# Works across languages
texts = [
    "日本の首都は <mask> です。",
    "<mask> est la capitale de la France",
    "The capital of the United States is <mask>.",
    "La capital de España es <mask>.",
    "Die Hauptstadt von Deutschland ist <mask>."
]

for text in texts:
    predictions = predict_masked_token(text)
    print(f"Text: {text}")
    print(f"Predictions: {predictions}")

出力
Text: 日本の首都は <mask> です。
Predictions: [' Tokyo', ' Kyoto', ' 東京', '東京', ' 大阪']
Text: <mask> est la capitale de la France
Predictions: ['Paris', 'Lille', 'Lyon', 'Nice', 'Marseille']
Text: The capital of the United States is <mask>.
Predictions: [' Washington', ' Chicago', ' Philadelphia', ' in', ' Seattle']
Text: La capital de España es <mask>.
Predictions: [' Madrid', ' Barcelona', ' Bilbao', ' Sevilla', ' Zaragoza']
Text: Die Hauptstadt von Deutschland ist <mask>.
Predictions: [' Berlin', ' Bonn', ' Hamburg', ' München', ' Stuttgart']

クロスリンガルなEmbeddingの例

from transformers import AutoTokenizer, AutoModel
import torch
from sklearn.metrics.pairwise import cosine_similarity

tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/mmBERT-base")
model = AutoModel.from_pretrained("jhu-clsp/mmBERT-base")

def get_embeddings(texts):
    inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
    
    with torch.no_grad():
        outputs = model(**inputs)
        embeddings = outputs.last_hidden_state.mean(dim=1)
    
    return embeddings.numpy()

multilingual_texts = [
    "Artificial intelligence is transforming technology",
    "La inteligencia artificial está transformando la tecnología",
    "L'intelligence artificielle transforme la technologie", 
    "人工智能正在改变技术",
    "人工知能は技術を変革している",
]

embeddings = get_embeddings(multilingual_texts)
similarities = cosine_similarity(embeddings)
print("Cross-lingual similarity matrix:")
print(similarities)
出力
Cross-lingual similarity matrix:
[[1.         0.8655733  0.8534732  0.9032274  0.83438045]
 [0.8655733  0.9999998  0.8938034  0.8164481  0.8094829 ]
 [0.8534732  0.8938034  0.99999994 0.79947156 0.8113538 ]
 [0.9032274  0.8164481  0.79947156 1.         0.895693  ]
 [0.83438045 0.8094829  0.8113538  0.895693   1.        ]]
kun432kun432

ベクトル類似度を求めてみる。

from transformers import AutoTokenizer, AutoModel
import torch
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

tokenizer = AutoTokenizer.from_pretrained("jhu-clsp/mmBERT-base")
model = AutoModel.from_pretrained("jhu-clsp/mmBERT-base")

def get_embeddings(texts):
    inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
    with torch.no_grad():
        outputs = model(**inputs)
        embeddings = outputs.last_hidden_state.mean(dim=1)
    return embeddings.numpy()

documents = [
    "木の温もりあふれるブックカフェで、自家焙煎の深煎りコーヒーと季節のタルトを味わいながら、窓辺から路面電車をのんびり眺められるんだ。",
    "庭にハーブが茂るガーデンカフェでは、ハンドドリップの浅煎りとフレッシュハーブティーが選べて、小鳥のさえずりが BGM 代わりになるよ。",
    "港直送の鯖を炙りしめ鯖にしてくれる専門店、皮目の香ばしさと酢のきりりとした酸味が口いっぱいに広がるんだ。",
    "カウンター割烹の金目鯛の煮付けは、甘辛ダレが骨の隅々まで染みていて、白ご飯が思わずおかわり必至だよね。",
    "昔ながらの屋台ラーメンは鶏ガラの澄んだ醤油スープと細ちぢれ麺が相性抜群で、深夜の胃袋にしみるんだ。",
    "真っ白な豚骨スープに焦がしニンニク油をひと垂らしした濃厚ラーメン、替え玉が無料でつい無限ループしてしまうよ。",
    "スリランカ式の混ぜて食べるプレートカレーでは、15種類のスパイスが複雑に重なって食べ進めるほど香りが花開くんだ。",
    "野菜がごろごろ入った欧風ビーフカレーは、赤ワインとバターのコクが効いたシャバっとルウで後を引くよ。",
    "薪窯ナポリピッツァのマルゲリータは、モッツァレラがびよーんと伸びて焼き立てを頬張る瞬間がたまらない。",
    "4種のチーズをのせたクアトロフォルマッジに蜂蜜を垂らすスタイルが人気で、塩気と甘さのコントラストがクセになるんだ。",
    "しゅわっととろけるバスクチーズケーキ専門店、表面の香ばしい焦げと濃厚クリーミーな中身のギャップが病みつきになるよ。",
    "パリパリの薄皮たい焼きは羽根つきで端っこまで香ばしく、黒あんか白あんか毎回真剣に迷っちゃうんだよね。",
]

query = "中華そばのオススメを教えて。"

document_embeddings = get_embeddings(documents)
query_embedding = get_embeddings([query])  # Pass query as a list

similarities = cosine_similarity(query_embedding, document_embeddings)
similarities_sorted = np.argsort(similarities[0])[::-1]

for rank, idx in enumerate(similarities_sorted.tolist(), 1):
    print("{}: ({:.4f}) {}".format(rank, similarities[0][idx], documents[idx]))
出力
1: (0.8864) 昔ながらの屋台ラーメンは鶏ガラの澄んだ醤油スープと細ちぢれ麺が相性抜群で、深夜の胃袋にしみるんだ。
2: (0.8771) カウンター割烹の金目鯛の煮付けは、甘辛ダレが骨の隅々まで染みていて、白ご飯が思わずおかわり必至だよね。
3: (0.8770) 真っ白な豚骨スープに焦がしニンニク油をひと垂らしした濃厚ラーメン、替え玉が無料でつい無限ループしてしまうよ。
4: (0.8760) 野菜がごろごろ入った欧風ビーフカレーは、赤ワインとバターのコクが効いたシャバっとルウで後を引くよ。
5: (0.8687) パリパリの薄皮たい焼きは羽根つきで端っこまで香ばしく、黒あんか白あんか毎回真剣に迷っちゃうんだよね。
6: (0.8679) スリランカ式の混ぜて食べるプレートカレーでは、15種類のスパイスが複雑に重なって食べ進めるほど香りが花開くんだ。
7: (0.8667) 港直送の鯖を炙りしめ鯖にしてくれる専門店、皮目の香ばしさと酢のきりりとした酸味が口いっぱいに広がるんだ。
8: (0.8656) 4種のチーズをのせたクアトロフォルマッジに蜂蜜を垂らすスタイルが人気で、塩気と甘さのコントラストがクセになるんだ。
9: (0.8647) 庭にハーブが茂るガーデンカフェでは、ハンドドリップの浅煎りとフレッシュハーブティーが選べて、小鳥のさえずりが BGM 代わりになるよ。
10: (0.8498) しゅわっととろけるバスクチーズケーキ専門店、表面の香ばしい焦げと濃厚クリーミーな中身のギャップが病みつきになるよ。
11: (0.8460) 薪窯ナポリピッツァのマルゲリータは、モッツァレラがびよーんと伸びて焼き立てを頬張る瞬間がたまらない。
12: (0.8419) 木の温もりあふれるブックカフェで、自家焙煎の深煎りコーヒーと季節のタルトを味わいながら、窓辺から路面電車をのんびり眺められるんだ。
kun432kun432

ファインチューニングの例がいくつか用意されている通り、実際にモデルをこのまま使うのではなく、ユースケースに合わせてファインチューニングすることになるのだろうと思う。

このスクラップは5日前にクローズされました