Microsoftの小型軽量生成AI、Phi-4-miniをローカルで試して色々聞いてみた

## はじめに
小型の生成AI(SLM)に期待していて、Phi-4も気になっていたんですが、それでも普通にでかいのでためらっていました。

今回、MicrosoftからPhi-4の新しいモデルPhi-4-miniが出てきたので試してみました。とりあえず需要を考えて、**GPUを使わずに**動かしてみます。

同時発表で、画像とかも処理できるマルチモーダル対応のPhi-4-multimodalも出ていますが、ちょっとでかいので今回は試していません。日本語の画像には対応していないらしいです。

https://techcommunity.microsoft.com/blog/educatordeveloperblog/welcome-to-the-new-phi-4-models---microsoft-phi-4-mini--phi-4-multimodal/4386037

## 環境
- Python 3.12 (uvで実行)
- Windows11
- Phi-4-mini
- transformers
- CPU: 13th Gen Intel(R) Core(TM) i5-13400F
- RAM 32GB



## モデルページ
なんと容量**7.16GB** 軽い。

https://huggingface.co/microsoft/Phi-4-mini-instruct

## まず結論
軽くて早くて実用性あります。つよつよPC不要。

## やってみる
適当なディレクトリを作成してcdして作業ディレクトリにしておいてください。

### 仮想環境作成
適当に仮想環境作ります。普通に生のPythonでもいいです。

```bash
 $ uv venv
 または
 $ python -m venv .venv

```
### 仮想環境を有効化
(PowerShellならバックスラッシュにしてactivate.ps1、コマンドプロンプトならactivate.bat)

```bash
$ . .venv/Scripts/activate
```

### 必要なライブラリインストール
ライブラリインストールします。

```bash
$ uv pip install transformers torch accelerate
または普通に
$ pip install transformers torch accelerate
```

### コード用意

次のコードを作成してmain.pyでディレクトリに保存してください。


```py

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
 
torch.random.manual_seed(0)

model_path = "microsoft/Phi-4-mini-instruct"

model = AutoModelForCausalLM.from_pretrained(
    model_path,
    device_map="auto",
    torch_dtype="auto",
    trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(model_path)
 
messages = [
    {"role": "system", "content": "You are a helpful AI assistant."},
    {"role": "user", "content": "Can you provide ways to eat combinations of bananas and dragonfruits?"},
    {"role": "assistant", "content": "Sure! Here are some ways to eat bananas and dragonfruits together: 1. Banana and dragonfruit smoothie: Blend bananas and dragonfruits together with some milk and honey. 2. Banana and dragonfruit salad: Mix sliced bananas and dragonfruits together with some lemon juice and honey."},
    {"role": "user", "content": "What about solving an 2x + 3 = 7 equation?"},
]
 
pipe = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
)
 
generation_args = {
    "max_new_tokens": 500,
    "return_full_text": False,
    "temperature": 0.0,
    "do_sample": False,
}
 
output = pipe(messages, **generation_args)
print(output[0]['generated_text'])


```

### 実行してみる

```bash
uv run ./main.py
または
python ./main.py
```
初回はダウンロードあるので時間かかります。
ちなみに保存場所はデフォルトだと多分下記
```
C:\Users\username\.cache\huggingface\hub
```

## 結果

なんやかんや色々でますが、質問はこれ

:::note
ユーザー：2x + 3 = 7 xの答えは何？

:::
結果はステップバイステップで考え出しました。

```
To solve the equation 2x + 3 = 7, follow these steps:

1. Subtract 3 from both sides of the equation to isolate the term with the variable (x) on one side:
   2x + 3 - 3 = 7 - 3
   2x = 4

2. Divide both sides of the equation by 2 to solve for x:
   2x / 2 = 4 / 2
   x = 2
```

x=2なので正解してますね。


## 対話形式でやる

これだと寂しいので対話形式にして、出力時間もわかるようにします。


### コード2



```py:main.py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
import time

torch.random.manual_seed(0)

model_path = "microsoft/Phi-4-mini-instruct"

print("モデルをロードしています...")
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    device_map="auto",
    torch_dtype="auto",
    trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(model_path)
print("モデルのロードが完了しました！")

# 初期メッセージの設定
messages = [
    {"role": "system", "content": "You are a helpful AI assistant."}
]

pipe = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
)

generation_args = {
    "max_new_tokens": 500,
    "return_full_text": False,
    "temperature": 0.0,
    "do_sample": False,
}

# 対話ループ
print("対話を開始します。終了するには 'exit' と入力してください。")
while True:
    user_input = input("\nユーザー: ")
    
    if user_input.lower() == 'exit':
        print("対話を終了します。")
        break
    
    # ユーザーの入力をメッセージに追加
    messages.append({"role": "user", "content": user_input})
    
    # 処理時間の測定開始
    start_time = time.time()
    
    # モデルによる生成
    output = pipe(messages, **generation_args)
    response = output[0]['generated_text']
    
    # 処理時間の測定終了
    end_time = time.time()
    elapsed_time = end_time - start_time
    
    # 応答をメッセージに追加
    messages.append({"role": "assistant", "content": response})
    
    # 応答と処理時間を表示
    print(f"\nアシスタント: {response}")
    print(f"\n[処理時間: {elapsed_time:.2f}秒]")
```



### 入力と出力(簡単な計算を英語で)

:::note warn
全部出るまで何にも出ないので待ってあげてください。
終わる時はexit→エンターで終了できます。
:::
さっきと同じ問題を聞いた後、yについての問題も聞いてみましょう。

```
ユーザー: 2x + 3 = 7 x = ?

アシスタント: To solve the equation 2x + 3 = 7 for x, follow these steps:

1. Subtract 3 from both sides of the equation:
   2x + 3 - 3 = 7 - 3
   2x = 4

2. Divide both sides by 2:
   2x / 2 = 4 / 2
   x = 2

So, x = 2.

[処理時間: 30.98秒]

ユーザー: ok, next. 3y = 12 + 3 y=?

アシスタント: To solve the equation 3y = 12 + 3 for y, follow these steps:

1. Subtract 3 from both sides of the equation:
   3y - 3 = 12 + 3 - 3
   3y - 3 = 12

2. Add 3 to both sides of the equation:
   3y - 3 + 3 = 12 + 3
   3y = 15

3. Divide both sides by 3:
   3y / 3 = 15 / 3
   y = 5

So, y = 5.

[処理時間: 78.41秒]
```
ばっちりですね。CPUの割には早いかな？GPUだとかなり早そう。
日本語でも試してみましょう

### 入力と出力(簡単な計算を日本語で)

```
ユーザー:  2x + 3 = 7 です。それでは、 x = ?

アシスタント: x = 2 を見つけることができます。これを行うには、次の手順に従います:

1. 方程式の両辺から 3 を引きます:
   2x + 3 - 3 = 7 - 3
   2x = 4

2. 両辺を 2 で割ります:
   2x / 2 = 4 / 2
   x = 2

[処理時間: 57.34秒]

ユーザー: 正解。次を解いてください。3y = 12 + 3 です。それでは、 y=?

アシスタント: y = 5 を見つけることができます。これを行うには、次の手順に従います:

1. 方程式の右辺を簡略化します:
   3y = 12 + 3
   3y = 15

2. 両辺を 3 で割ります:
   3y / 3 = 15 / 3
   y = 5

[処理時間: 67.57秒]

```
1問目は倍の時間がかかっていますが`3y = 12 + 3`の答え`y=5`も正解できてますね！

### 日本語で色々聞いてみる
色々聞いてみます。難しそうなのは後ろにChatGPTの回答も出しておきます。※推論も検索もなしの無料バージョン

:::note info
改行は後から適当に入れてます。
入力自体は全部一行にまとめてます。
改行コード入れたら精度良くなるかも。
:::


#### 1.事実確認
**『1年は何日ある？』** と聞いてみます。
```:phi-4-mini
ユーザー: 1年は何日ある？

アシスタント: 1年は365日ある（閏年を除く）。
閏年は、グレゴリオ暦の年が400で割り切れる場合、366日になります。
閏年は4年ご とに発生します。閏年の年は、2年目の偶数年に発生します。
例えば、2000年、2004年、2008年、2012年などです。
これらの年は、閏 日（2月29日）を含む366日で構成されています。閏年以外の年は365日です。
[処理時間: 66.29秒]
```
合ってる。うるう年にも言及できてて合ってますね。
ちなみに次のうるう年は2028年です。

#### 2.ちょっとひねくれた意見を聞いてみる
**『もし雨が降ったら傘を持って行くべき？でも傘が嫌いだったらどうする？』** と聞いてみます。
```:phi-4-mini
ユーザー: もし雨が降ったら傘を持って行くべき？でも傘が嫌いだったらどうする？

アシスタント: 雨が降った場合、傘を持って行くことは一般的に良いアイデアです。
なぜなら、傘はあなたを雨から保護するからです。
しかし、傘が嫌いである場合、代替の選択肢を検討することができます。例えば：

1. **雨具を使用する**: 風防付きの帽子、雨具、または防水の服を着用することができます。
2. **屋内に移動する**: 雨が降っている場合、屋内の活動に移ることができます。
3. **傘なしで歩く**: もし雨が軽いならば、傘なしで歩くことも選択肢です。ただし、長時間の雨にさらされると不快になる可能性 があります。
4. **傘を借りる**: 友人や家族に傘を借りて、雨から保護することができます。

最終的に、あなたの快適さと安全を最優先に考えることが重要です。

[処理時間: 189.14秒]
```

結構考えましたね。傘を借りるのはちょっと微妙な気がしますが、まあ許容範囲でしょう。ちなみにChatGPTの回答は以下
```:ChatGPT
雨が降ったら傘を持って行くのがセオリーだけど、傘が嫌いなら他の選択肢もあるよね。

例えば…

レインコート派 🌧️🧥 → 両手が空くから意外と快適
撥水パーカー派 → 軽い雨ならこれで十分
濡れるの覚悟派 → 「どうせ乾くし」っていう潔さもカッコいい
駆け抜ける派 → 移動時間短めなら全力ダッシュ
傘が嫌いな理由にもよるかも。
重いのが嫌なのか、持ち歩くのが面倒なのか、単純に手がふさがるのが嫌なのか…。

どれ派？ ☔🤔
```

なんかえらくフランクですね。モデルの味付けが変わったかも。
回答自体は非常に自然。

#### 3.ぶっ飛んだ創造性を試す
**『もし、宇宙でピザ屋を開くとして、その宣伝方法は？』** と質問してみました。

```:phi-4-mini
アシスタント: 宇宙でピザ屋を開くというユニークなビジネスを宣伝するには、以下のような戦略を考えることができます：

1. **宇宙テーマのマーケティング**: ピザ屋のロゴや広告は宇宙のイメージを取り入れ、
宇宙飛行士や宇宙探査のイラストを使用し て、
宇宙旅行者にとってのピザの喜びを伝えることができます。

2. **ソーシャルメディアキャンペーン**: インフルエンサーや宇宙愛好家を招待して、
宇宙でのピザの体験を共有させるキャンペーンを行う。
宇宙でのピザの写真や動画を投稿し、宇宙旅行者の間で話題を呼ぶ。

3. **宇宙博物館やイベントのパートナーシップ**: 宇宙博物館や宇宙関連のイベントで
ピザ屋のパートナーシップを提案し、
展示スペースやイベントでのピザ販売を行う。

4. **宇宙旅行者向けの特別オファー**: 宇宙旅行者向けに特別なオファーを提供し、
宇宙でのピザの体験を宣伝する。例えば、宇宙 旅行の予約にピザを含めるなど。

5. **宇宙ニュースメディアとのコラボレーション**: 宇宙ニュースメディアや宇宙関連の雑誌に
記事や広告を掲載し、宇宙でのピザ 屋の存在を広める。

6. **宇宙テーマのイベント開催**: 宇宙テーマのイベントやコンベンションで
ピザ屋を出展し、宇宙旅行者や宇宙愛好家に直接触れ る機会を提供する。

7. **インタラクティブな体験**: 宇宙でのピザ屋の体験を模倣するインタラクティブな
体験を提供し、例えばVR体験や宇宙テーマの パーティーなど。
[処理時間: 312.21秒]
```
基本は抑えてる感じがしますね。SNSとか。回答はちょっとふわっとしている感じはします。**(宇宙だけに)**

```:ChatGPT
おお、それは銀河規模のビジネスチャンスじゃないですか！🌌🍕  
宇宙ピザ屋の宣伝プランは、地球の常識を捨てて考える必要がありますね。

### 🚀 宇宙ピザ屋宣伝プラン
---

### 1. **「地球初！宇宙配達ピザ」っていうネーミングでバズらせる】
SNSのキャッチコピーは  
**「できたてのピザ、光速でお届け。」**  
ターゲットは宇宙ステーションのクルーや、これから火星移住する人たち。

---

### 2. **軌道上デリバリードローン**
ピザ専用の自律型配送ポッドを開発して、ISS（国際宇宙ステーション）まで配達。  
しかもピザを温めたまま運ぶ再突入耐熱シールド付き🚀🔥  
スローガンは  
**「宇宙一熱いピザをお届けします。」**

---

### 3. **ゼログラビティ体験オプション**
宇宙船の中で食べるとピザが浮くやつ。  
これを映像化してTikTokでバズらせる📱✨

---

### 4. **宇宙人向けメニュー**
「火星風マリナーラ」とか「ブラックホールカルツォーネ」  
謎の惑星由来のスパイス入りピザ（実際はパクチーとかを異星風にアレンジ）  

---

### 5. **月面広告（ガチ）**
月の表面にレーザーでロゴを描いて、地球からも見えるようにする。  
NASAやSpaceXに「ピザスポンサーシップ」として売り込めばワンチャン。

---

### 6. **通貨はビットコイン or 宇宙独自通貨「ピザコイン」**
デジタル決済しかできないけど、初回注文で1ピザコインプレゼント🍕💰

---

### 7. **AI搭載ピザボット「ピザGPT」**
「今日はどんなピザにしますか？」って話しかけるAI店員がドローンに搭載。

---

### まとめ
キャッチコピーは  
**「宇宙では誰もあなたのチーズが溶ける音を聞かない。」**

---

なんかもう、出資者募ればマジで宇宙ピザ屋いけそうな気がしてきました。  
どうです？CEOやります？🚀🍕
```

なんかノーコメントって感じです。友達にはなりたくないかも。


#### 4.情報処理
データをもとに色々やってもらいます。
**『データを元に、この5か月の平均売上と、売上が最も高い月を教えて。
さらに、売上が平均以下の月がいくつあるか計算して。』** と聞いてみます。
```:phi-4-mini

ユーザー: 
### データ: ある会社の月間売上（単位:万円）
- 1月: 300, 2月: 250, 3月: 320, 4月: 280, 5月: 310  

### 質問: 
データを元に、この5か月の平均売上と、売上が最も高い月を教えて。
さらに、売上が平均以下の月がいくつあるか計算して。

アシスタント: まず、5か月の平均売上を計算します:

(300 + 250 + 320 + 280 + 310) / 5 = 1460 / 5 = 292万円

次に、売上が最も高い月を見つけます:

3月の売上が320万円で、他の月よりも高いので、3月が売上が最も高い月です。

最後に、売上が平均以下の月を数えます:

- 1月: 300万円
- 2月: 250万円
- 4月: 280万円
- 5月: 310万円

これらの月の売上は平均（292万円）以下です。したがって、4か月の売上が平均以下です。

[処理時間: 115.07秒]
```
最後の問題が間違えてますね。でもこのサイズのモデルで平均を出せたのは驚きました。正確な数値処理はさせない方がいいかも。そして出力が意外と早い。

```:ChatGPT

### 回答
データ: 1月: 300, 2月: 250, 3月: 320, 4月: 280, 5月: 310  

#### 1. 平均売上
\[
(300 + 250 + 320 + 280 + 310) ÷ 5 = 1460 ÷ 5 = 292
\]
**→ 平均売上: 292万円**

#### 2. 売上が最も高い月
最も高い売上は**320万円（3月）**

#### 3. 売上が平均以下の月の数
- 1月: 300 → 平均より高い
- 2月: 250 → 平均以下
- 3月: 320 → 平均より高い
- 4月: 280 → 平均以下
- 5月: 310 → 平均より高い

**→ 平均以下の月の数: 2か月（2月と4月）**
```
ばっちりですね。でも2は売上の高い「月」を聞いているので100点ではないです。

#### 5. 小難しい文章を要約させる
報告書を条件付きで要約させてみます。
**『データの報告書抜粋を2文で要約して、企業の業績と今後の計画の要点を説明して。』** 
```:phi-4-mini
ユーザー: 
データ: 「ある企業の年次報告書抜粋 - 当社は2023年に売上12億円を達成し、前年比で15%の成長を記録した。
主な要因は海外市場の拡大と新製品の投入であり、特にアジア地域での売上が顕著に増加した。
一方で、原材料費の高騰により利益率は若干低下し、純利益は8億円にとどまった。
来年度はコスト削減と業務効率化を進め、さらなる成長を目指す。」

命令:「データの報告書抜粋を2文で要約して、企業の業績と今後の計画の要点を説明して。」

アシスタント: 
2023年の売上は12億円に達し、
前年比15%の成長を遂げ、
特にアジア市場での売上増加が主な要因であった。

利益率は 原材料費の高騰により低下し、
純利益は8億円であったが、
コスト削減と業務効率化を進める計画で来年度の成長を目指している。
[処理時間: 82.60秒]
```
ちょっと長いけど全然ありですね！ちゃんと2文で、業績と今後の計画も出せています

```:ChatGPT
当社は2023年に売上12億円（前年比15%増）を達成し、
海外市場の拡大と新製品投入が成長を牽引したが、
原材料費の高騰により純利益は8億円にとどまった。

来年度はコスト削減と業務効率化を進め、
更なる成長を目指す。
```
要約は文句なしですね。業績、今後で分けてて読みやすい。でも当社って勝手に付けてるな。

#### 6.翻訳
最後翻訳させます。日本食に関する文章。
**『データの文章を英語に翻訳して、自然で正確な表現にして。』** 

```:phi-4-mini
ユーザー: 
データ:「日本の伝統的な食事は、健康的でバランスが取れていると世界中で評価されています。
特に、米、魚、野菜を中心とした和食は、長寿の秘訣とも言われています。」

質問:「データの文章を英語に翻訳して、自然で正確な表現にして。」


アシスタント: 
The traditional Japanese cuisine is highly regarded worldwide
for being healthy and balanced.

In particular, Japanese food centered around rice, fish, and vegetables is often considered a key to longevity.

[処理時間: 22.80秒]

# DeepLで再翻訳
伝統的な日本料理は世界的に高く評価されている。
特に米、魚、野菜を中心とした和食は長寿の秘訣とされている。


```
早いですね。意味もちゃんと取れてます。後述のChatGPTよりcuisineを選んだのを評価したいかも。

```:ChatGPT
**Translation:**  
"Traditional Japanese meals are highly regarded worldwide
for being healthy and well-balanced. 

In particular, Washoku, 
which is centered around rice, fish, and vegetables, is said to be a secret to longevity."

# DeepLで再翻訳
日本の伝統的な食事は世界的に高く評価されている。
健康的でバランスの取れた食事として世界的に高く評価されている。

特に「和食」、 
特に米、魚、野菜を中心とした和食は長寿の秘訣と言われている。
```
ChatGPTは結構味付けをしていますね。「翻訳」で囲んでいるのは使いにくいかも。

## まとめ
**十分実用に耐えると思いました。** GPT-3.5以上は全然ある気がします。

これが7.16GBで保存してローカルで実行できる世界になったのは怖いですね。
気が向いたらGPUでも試してみます。

通常の用途ならローカルLLMのかなり有力な選択肢になると思います。

コーディング能力が優れているらしいですけど、個人的には軽いローカルLLMではあんまりさせたいタスクではない気がします。なんか良い使い道あったら教えてください。