Appleのsage-ft-mixtral-8x7b：Mixture-of-ExpertsアーキテクチャのLLM

# はじめに

しゅんです。  
いつも見てくれてありがとうございます。  

今回は、Apple が新たなモデル `sage-ft-mixtral-8x7b` を Hugging Face に push したのをたまたまリアルタイムで発見し、そこで GPT と一緒に考察した記事となります。2025/3/14 13:20、約七時間前に push された新たなモデルですが、この記事を書いている現時点ではモデル本体と config ファイルしか公開されていません。Readme には何も説明がなく、正式な発表を待つのが普通かもしれませんが、こういう状況で GPT と一緒に考察することで、技術面や実践的な実験のポイントを学べると感じたので、記録を兼ねて記事にまとめました。ぜひ最後まで見ていただけると嬉しいです。よろしくお願いします。

公式リンク：

https://huggingface.co/apple/sage-ft-mixtral-8x7b

:::note warn
公式readme何も載ってないので以下の技術に関わる内容（パラメータなど）はあくまで個人とconfigファイルからのGPTの推測と考察になってるので、公式の発表を待つのが普通です。
:::
---

# モデル概要と Config ファイルの考察

今回の `sage-ft-mixtral-8x7b` は、名前から推察すると Mixtral 系の因果言語モデル（Causal LM）であり、Apple チームによってファインチューニング（FT）が施されたモデルです。以下、公開されている諸々のconfigファイルをGPTに投げて分析させてもらいました。特徴をまとめます。

## モデルアーキテクチャ

- **architectures:** `"MixtralForCausalLM"`  
  → これは、因果言語モデルとして設計されていることを示します。

- **大規模な構造:**  
  - `hidden_size`: 4096  
  - `num_hidden_layers`: 32  
  - `num_attention_heads`: 32  
  - `max_position_embeddings`: 32768  
  → これらのパラメータから、非常に大規模なモデルであることがわかります。

- **Mixture-of-Experts (MoE):**  
  - `num_experts_per_tok`: 2  
  - `num_local_experts`: 8  
  → 各トークンごとに複数の専門家ネットワークを用いる MoE 構造が採用されており、柔軟な表現力を実現しつつも、計算オーバーヘッドが大きいことが予想されます。

## トークナイザーと生成設定

- **トークナイザー:**  
  `tokenizer_class` は `"LlamaTokenizer"` が指定されており、特殊トークン（BOS, EOS, UNK）が正しく定義されています。これにより、入力テキストの前処理と生成後のデコードが適切に行われることが期待されます。

- **生成時の設定:**  
  generation_config.json では、BOS/EOS トークン ID が定義されているため、生成時に `pad_token_id` が設定されなかった場合、自動的に EOS トークン ID（ここでは 2）に設定される挙動となります。

---

# 推論速度と量子化の効果

## 非量子化時の問題点

元の状態（非量子化）では、例えば `max_new_tokens=1` であっても A100 GPU 上で 1 トークン生成に約 5 分かかっていました。これは以下の理由が考えられます。


- **MoE 構造のオーバーヘッド:**  
  各層で専門家のルーティング処理が行われるため、通常の密な Transformer に比べて計算負荷が高く、キャッシュの活用も難しくなっています。

## 4-bit 量子化による改善

BitsAndBytes ライブラリを用いた 4-bit 量子化を導入することで、モデルのメモリ使用量および計算量が大幅に削減され、同じ条件下での推論速度が劇的に向上しました。実際、以下の実験結果が得られています。

- **非量子化時:**  
  - 1 トークン生成に約 5 分  
- **量子化時:**  
  - `max_new_tokens=50` の生成が約 20 秒で完了

この結果から、実運用や実験で大規模な MoE モデルを扱う場合、量子化は必須の手法であることが示唆されます。ただし、量子化方式にはいくつかの選択肢があり、  
- **FP4**（Floating Point 4-bit）  
- **NF4**（Normal Float 4-bit）  

などが存在します。  
NF4 は、ゼロ付近の数値表現がより精度よくなるよう設計されており、同じ 4-bit 幅でも量子化誤差を低減できるため、精度が重視される場合に有利です。

また、量子化によりロードや初期変換に時間がかかることはあるものの、推論速度自体は大幅に向上し、実用的な時間に収まっています。

# CODE
## 環境とpip install
### セル1

:::note warn
今回はgoogle colabでやってます。
A100を使ってます
:::

```bash
!pip install transformers accelerate torch
!pip install bitsandbytes
```
:::note warn
今回はgoogle colabでやってます。
install後セッション再起動してください
:::


## CODE NO 量子化バージョン

### セル2

```python
import torch
from transformers import AutoModelForCausalLM
model_name = "apple/sage-ft-mixtral-8x7b"

model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
```

### セル3

```python
model.eval()

# 入力テキストのトークナイズとGPU転送
input_text = "Hello my name is SYUN"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids.to("cuda")

# 生成シーケンスの初期化
generated = input_ids

# 1トークンずつ生成（最大50トークン）
# max_new_tokens = 50
max_new_tokens = 1

print("Generation start:")
for i in range(max_new_tokens):
    with torch.no_grad():
        outputs = model(generated)
    # 最後のトークンのロジットを取得
    next_token_logits = outputs.logits[:, -1, :]
    # Greedy decoding: 最も確率の高いトークンを選択
    next_token = torch.argmax(next_token_logits, dim=-1, keepdim=True)
    # サンプリングを行う場合は以下のように変更できます：
    # probs = torch.softmax(next_token_logits, dim=-1)
    # next_token = torch.multinomial(probs, num_samples=1)
    
    generated = torch.cat((generated, next_token), dim=1)
    # 生成された1トークンをデコードして表示
    token_str = tokenizer.decode(next_token.squeeze(), skip_special_tokens=True)
    print(token_str, end="", flush=True)
    
    # EOSトークンが生成されたら終了
    if next_token.item() == tokenizer.eos_token_id:
        break

print("\nGeneration complete.")
```

# 普通のモデルで回した結果

### セル3 の結果

```bash
Generation start:
and
Generation complete.
```

:::note warn
非常に時間かかりました。５分以上
自分のコードが問題はあった可能性もあるし、実際の使い方が間違ってる可能性もあるため、わからないです。最初に言ってた通り公式の*README*公開していないです！LLM詳しい方気になったらぜひコメントで教えてくれると助かります。
:::

## CODE 量子化バージョン

### セル4 量子化
```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

model_name = "apple/sage-ft-mixtral-8x7b"

# 4bit量子化の設定
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,  # または torch.float16
    bnb_4bit_quant_type="nf4",              # nf4 や fp4 など選択可能
    bnb_4bit_use_double_quant=True
)

# トークナイザーとモデルのロード（量子化設定を適用）
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    quantization_config=quantization_config,
    device_map="auto"
)
```

:::note warn
この読み込みも時間かかりました。５分前後
:::

### セル5量子化後の逐次生成のCODE

```python

model.eval()

# 入力テキストの定義とトークナイズ（GPU転送）
input_text = "Hello my name is SYUN"
input_ids = tokenizer(input_text, return_tensors="pt").input_ids.to("cuda")

# 入力プロンプトも出力に含めるため、最初に表示
print("Input:", input_text)
print("Generation start:")

# 生成シーケンスの初期化（既存の入力を含む）
generated = input_ids

max_new_tokens = 50

for i in range(max_new_tokens):
    with torch.no_grad():
        outputs = model(generated)
    # 出力の最後のトークンのロジットを取得
    next_token_logits = outputs.logits[:, -1, :]
    # Greedy decoding で最も確率の高いトークンを選択
    next_token = torch.argmax(next_token_logits, dim=-1, keepdim=True)
    # 新たなトークンを連結
    generated = torch.cat((generated, next_token), dim=1)
    # 新たに生成されたトークンをデコード
    token_str = tokenizer.decode(next_token.squeeze(), skip_special_tokens=True)
    
    # トークンを表示。もしトークン内にピリオドが含まれていれば改行する。
    print(token_str, end=" ", flush=True)
    if "." in token_str:
        print()  # ピリオドがあれば改行

    # EOS トークンが生成されたらループ終了
    if next_token.item() == tokenizer.eos_token_id:
        break

print("\nGeneration complete.")

# 生成された全体のテキスト（入力＋生成結果）を出力
full_text = tokenizer.decode(generated.squeeze(), skip_special_tokens=True)
print("Full output:", full_text)
```



## 量子化後の逐次生成の結果

実際に 1 トークンずつ逐次生成するコード例では、以下のような結果が得られました。
見やすくために"."の時改行しています。

```plaintext
Input: Hello my name is SYUN
Generation start:
and I am a 20 year old student from Japan. 
I am currently studying abroad in the United States. 
I am a big fan of anime and manga, and I love to play video games. 
I also enjoy watching movies and TV shows 
Generation complete.
Full output: Hello my name is SYUN and I am a 20 year old student from Japan. I am currently studying abroad in the United States. I am a big fan of anime and manga, and I love to play video games. I also enjoy watching movies and TV shows
```

この結果から、量子化を利用した場合、生成されたテキストは流暢であり、入力に続く一貫した内容が出力されることが確認されました。  
また、ピリオドを検出した際に改行する工夫により、出力が読みやすくなっている点も評価できます。

# このような動きです
## 午後丸々これに使いましたので少し感動

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Appleのsage-ft-mixtral-8x7bを量子化してColabで成功した！！！（情報何一つない）午後丸々これに使いました。疲れたけど、量子化のおかげでA100でも実用的な速度で推論できるようになりました。非量子化では1トーク生成に5分以上かかっていたので、量子化した。<a href="https://twitter.com/hashtag/Apple?src=hash&amp;ref_src=twsrc%5Etfw">#Apple</a><a href="https://twitter.com/hashtag/LLM?src=hash&amp;ref_src=twsrc%5Etfw">#LLM</a> <a href="https://twitter.com/hashtag/sage?src=hash&amp;ref_src=twsrc%5Etfw">#sage</a>-ft-mixtral-8x7b <a href="https://t.co/QCkuUN59Te">https://t.co/QCkuUN59Te</a> <a href="https://t.co/vFx9NQ8WV7">pic.twitter.com/vFx9NQ8WV7</a></p>&mdash; SYUN@気は長く、勤めは堅く、昨日を越えて、今日を生きる (@syun88AI) <a href="https://twitter.com/syun88AI/status/1900449764434731414?ref_src=twsrc%5Etfw">March 14, 2025</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# まとめ

今回の記事では、Apple が push した新たなモデル `sage-ft-mixtral-8x7b` の公開直後の状況をもとに、公式の README がなくとも、config ファイルや実験結果からその構造や動作特性を考察しました。主なポイントは以下のとおりです。

- **大規模 MoE モデルの計算負荷:**  
  非量子化状態では、1 トークン生成に A100 GPU でも約 5 分かかるという非常に重い計算負荷が確認されました。

- **4-bit 量子化による劇的な推論速度改善:**  
  BitsAndBytes を利用した 4-bit 量子化（特に NF4 方式を採用）により、同じモデルで max_new_tokens=50 の生成が約 20 秒で完了するなど、推論速度が劇的に向上しました。これにより、大規模モデルでも実用的な時間内に応答を得ることが可能になっています。

- **bfloat16 の有利性:**  
  A100 GPU は bfloat16 に対して最適化が進んでいるため、同じ環境下で float16 よりも高速かつ安定した推論が実現されました。モデルやタスクによっては、この点が大きなメリットとなります。

- **生成品質と実験結果:**  
  逐次生成の実験では、入力プロンプトに続く形で自然で流暢な文章が生成され、ピリオドで改行する工夫により読みやすさも向上しています。これらの結果から、量子化を導入しても生成品質が十分に保たれていることが確認できました。

総じて、公式情報が乏しい状況でも、GPT とともに実験・考察することで、大規模 MoE モデルの特性や量子化の有効性を実感することができました。今後、公式な README や追加情報が公開されれば、さらに詳細な評価や改善策が明らかになるでしょう。現段階では、量子化技術の導入が大規模モデルの実運用において必須の手法であり、計算負荷を大幅に軽減しながらも高品質な生成が可能であるという結論に至りました。

この記事が、同じような大規模言語モデルの取り扱いや量子化技術に興味をお持ちの皆さんの参考になれば幸いです。ご意見やご質問など、ぜひコメントでお知らせください。
    （LLM初心者なので。手柔らかにお願いします）

今回も最後までお読みいただき、ありがとうございました！