Chuyển đến nội dung chính

レッスン 10: パフォーマンスの最適化 - RAM、コンテキスト ウィンドウ、同時実行性

OLLAMA_NUM_PARALLEL、OLLAMA_MAX_LOADED_MODELS、コンテキスト ウィンドウと RAM。ベンチマーク、モニタリング、各 MacBook 構成に最適化。

🧠 AI と ML — レッスン 0 レッスン 10: パフォーマンスの最適化 - RAM、コンテキスト ウィンドウと同時実行性

Apple Silicon で Ollama を使用して AI Local を実行する

パート 4: 最適化、管理、および生産セットアップ

xdev.asia

はじめに

AI をローカルで実行するということは、クラウド プロバイダーではなくリソースを管理することを意味します。この記事では、Ollama が Mac 上で最速で動作するように、RAM、コンテキスト ウィンドウ、同時実行性を最適化する方法について説明します。


1. Ollama が RAM をどのように使用するかを理解する

Apple Silicon 上のユニファイド メモリ

Apple Silicon は ユニファイド メモリ を使用します。CPU と GPU は同じメモリを共有します。

┌─────────────────────────────────┐
│        Unified Memory           │
│  ┌───────────┐ ┌──────────────┐ │
│  │  CPU RAM   │ │   GPU VRAM   │ │
│  │  (macOS,   │ │  (Model      │ │
│  │   apps)    │ │   weights,   │ │
│  │            │ │   KV cache)  │ │
│  └───────────┘ └──────────────┘ │
└─────────────────────────────────┘

モデル実行時の RAM の故障

成分説明例 (ラマ 3.2 3B Q4)
モデルの重み量子化された重み~2.0 GB
KVキャッシュコンテキスト ウィンドウ キャッシュ~0.5 ~ 2.0 GB
OS のオーバーヘッドmacOS を実行する必要があります~3~4 GB
Ollama ランタイムサーバープロセス~200MB

モデルに必要な RAM を計算します。

推定式:

RAM = Model_Size + KV_Cache + OS_Overhead

KV_Cache ≈ (context_length × num_layers × hidden_dim × 2 × 2) / (1024³)
          ≈ (context_length × num_params_billions × 0.05) GB

参考表:

モデルQ4_K_Mコンテキスト 2Kコンテキスト8Kコンテキスト 32K
1B0.7GB1.2GB1.5GB3.0GB
3B2.0GB2.8GB3.5GB6.5GB
7B4.4GB5.5GB7.0GB13GB
13B7.9GB10GB13GB22GB
27B17GB20GB25GB40GB以上

2. Ollama 環境変数

重要な構成

# Số request xử lý song song (default: 1)
export OLLAMA_NUM_PARALLEL=2

# Số model giữ trong RAM cùng lúc (default: 1)
export OLLAMA_MAX_LOADED_MODELS=2

# Context window tối đa (default: 2048)
export OLLAMA_NUM_CTX=4096

# Thời gian giữ model trong RAM (default: 5m)
export OLLAMA_KEEP_ALIVE=10m

# Bind address (default: 127.0.0.1:11434)
export OLLAMA_HOST=0.0.0.0:11434

# Thư mục lưu model
export OLLAMA_MODELS=~/.ollama/models

# Flash attention (nhanh hơn)
export OLLAMA_FLASH_ATTENTION=1

# Max queue size
export OLLAMA_MAX_QUEUE=512

永続的に設定 (macOS)

ファイルの作成 ~/.zshrc または次のように追加します。

# Ollama optimization
export OLLAMA_NUM_PARALLEL=2
export OLLAMA_FLASH_ATTENTION=1
export OLLAMA_NUM_CTX=4096
export OLLAMA_KEEP_ALIVE=10m

または、launchd plist (Ollama アプリの場合) を使用します。

# Tạo file override
cat > ~/Library/LaunchAgents/com.ollama.env.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.ollama.env</string>
    <key>ProgramArguments</key>
    <array>
        <string>launchctl</string>
        <string>setenv</string>
        <string>OLLAMA_NUM_PARALLEL</string>
        <string>2</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
EOF

3. MacBook の構成に応じて最適化する

MacBook Air/Pro 8GB RAM

export OLLAMA_NUM_PARALLEL=1
export OLLAMA_MAX_LOADED_MODELS=1
export OLLAMA_NUM_CTX=2048
export OLLAMA_KEEP_ALIVE=3m
export OLLAMA_FLASH_ATTENTION=1

推奨モデル:

  • llama3.2:1b — 速くて軽い
  • gemma3:4b — 品質と速度のバランスをとる
  • qwen2.5-coder:1.5b — コード生成
  • phi4-mini — 軽い推理

MacBook Pro 16GB RAM

export OLLAMA_NUM_PARALLEL=2
export OLLAMA_MAX_LOADED_MODELS=2
export OLLAMA_NUM_CTX=4096
export OLLAMA_KEEP_ALIVE=10m
export OLLAMA_FLASH_ATTENTION=1

推奨モデル:

  • llama3.2:3b — 汎用
  • gemma3:12b — 高品質
  • qwen2.5-coder:7b — 優れたコード生成
  • deepseek-r1:7b — 推論

MacBook Pro 24-36GB RAM

export OLLAMA_NUM_PARALLEL=4
export OLLAMA_MAX_LOADED_MODELS=3
export OLLAMA_NUM_CTX=8192
export OLLAMA_KEEP_ALIVE=30m
export OLLAMA_FLASH_ATTENTION=1

推奨モデル:

  • llama3.3:70b (Q4) — 40 GB、48GB 以上の RAM が必要
  • gemma3:27b — とても強い
  • qwen2.5-coder:14b — コードの専門家
  • command-r:35b — 専用RAG

Mac Studio/Pro 64GB+ RAM

export OLLAMA_NUM_PARALLEL=8
export OLLAMA_MAX_LOADED_MODELS=4
export OLLAMA_NUM_CTX=16384
export OLLAMA_KEEP_ALIVE=1h
export OLLAMA_FLASH_ATTENTION=1

4. コンテキストウィンドウと num_ctx

コンテキストウィンドウとは何ですか?

コンテキスト ウィンドウ = モデルの短期記憶。すべてのメッセージ (システム + ユーザー + アシスタント) はコンテキスト ウィンドウ内に存在する必要があります。

import ollama

# Set context window per request
response = ollama.chat(
    model='llama3.2',
    messages=[{'role': 'user', 'content': 'Hello'}],
    options={
        'num_ctx': 4096,       # Context window
        'num_predict': 512,    # Max tokens to generate
    }
)

トレードオフ

数値ctx追加RAM (7Bモデル)スピード使用例
2048年+0 GB最速短いチャット
4096+0.5GB速いカジュアルチャット
8192+1.5GB平均文書分析
16384+3.5GB遅い長い文書
32768+8 GB遅いRAG、書籍分析

コンテキストの自動調整

import ollama
import psutil

def get_optimal_ctx():
    """Tự động chọn context window dựa trên RAM available."""
    available_gb = psutil.virtual_memory().available / (1024**3)

    if available_gb > 24:
        return 16384
    elif available_gb > 12:
        return 8192
    elif available_gb > 6:
        return 4096
    else:
        return 2048

ctx = get_optimal_ctx()
print(f"Setting num_ctx = {ctx}")

5. 同時実行と並列リクエスト

OLLAMA_NUM_PARALLEL

1 つのモデルに対して同時に処理するリクエストの数を制御します。

# 1 request/lần (default) - ít RAM nhất
export OLLAMA_NUM_PARALLEL=1

# 2 request/lần - cần thêm ~1.5x KV cache RAM
export OLLAMA_NUM_PARALLEL=2

# 4 request/lần - cần thêm ~3x KV cache RAM
export OLLAMA_NUM_PARALLEL=4

同時実行性のテスト

import ollama
import concurrent.futures
import time

def chat(prompt):
    start = time.time()
    response = ollama.chat(
        model='llama3.2:3b',
        messages=[{'role': 'user', 'content': prompt}],
        options={'num_predict': 100}
    )
    elapsed = time.time() - start
    return elapsed

prompts = [
    "Giải thích Docker bằng 3 câu",
    "Python list comprehension là gì?",
    "REST vs GraphQL khác nhau thế nào?",
    "Git rebase vs merge: khi nào dùng?",
]

# Sequential
print("=== Sequential ===")
total_seq = 0
for p in prompts:
    t = chat(p)
    total_seq += t
    print(f"  {t:.1f}s")
print(f"  Total: {total_seq:.1f}s\n")

# Concurrent
print("=== Concurrent ===")
start = time.time()
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    futures = [executor.submit(chat, p) for p in prompts]
    for f in concurrent.futures.as_completed(futures):
        print(f"  {f.result():.1f}s")
total_conc = time.time() - start
print(f"  Total: {total_conc:.1f}s")

print(f"\nSpeedup: {total_seq/total_conc:.1f}x")

6. モニタリングとベンチマーク

RAM 使用量を監視する

# Xem Ollama process
ps aux | grep ollama

# Realtime monitoring
top -pid $(pgrep ollama)

# Hoặc dùng htop
brew install htop && htop -p $(pgrep ollama)

GPU 使用率

# macOS Activity Monitor → GPU History (Window menu)
# Hoặc dùng powermetrics (cần sudo)
sudo powermetrics --samplers gpu_power -i 1000

ベンチマーク スクリプト

#!/usr/bin/env python3
"""Benchmark Ollama models trên Mac."""

import ollama
import time
import json

def benchmark_model(model, prompt, num_ctx=2048, num_predict=256):
    start = time.time()
    response = ollama.chat(
        model=model,
        messages=[{'role': 'user', 'content': prompt}],
        options={
            'num_ctx': num_ctx,
            'num_predict': num_predict,
        }
    )
    elapsed = time.time() - start

    content = response['message']['content']
    tokens = len(content.split())  # Rough estimate
    tps = tokens / elapsed if elapsed > 0 else 0

    return {
        'model': model,
        'time': round(elapsed, 2),
        'tokens': tokens,
        'tokens_per_sec': round(tps, 1),
        'num_ctx': num_ctx,
    }

# Run benchmarks
models = ['llama3.2:1b', 'llama3.2:3b', 'gemma3:4b']
prompt = "Write a Python function to sort a list using quicksort algorithm. Include docstring and comments."

print("🏁 Benchmarking Ollama models...\n")
results = []
for model in models:
    print(f"  Testing {model}...")
    try:
        result = benchmark_model(model, prompt)
        results.append(result)
        print(f"  ✅ {result['time']}s, ~{result['tokens_per_sec']} tok/s")
    except Exception as e:
        print(f"  ❌ Error: {e}")

print("\n📊 Results:")
print(f"{'Model':<20} {'Time (s)':<10} {'Tokens':<10} {'Tok/s':<10}")
print("-" * 50)
for r in results:
    print(f"{r['model']:<20} {r['time']:<10} {r['tokens']:<10} {r['tokens_per_sec']:<10}")

7. 高度な最適化のヒント

フラッシュアテンション

export OLLAMA_FLASH_ATTENTION=1

KV キャッシュのメモリ フットプリントを削減し、コンテキストが長い場合は最大 10 ~ 20% 高速化します。

キープアライブ管理

# Giữ model trong RAM lâu hơn (tránh reload)
export OLLAMA_KEEP_ALIVE=30m

# Luôn giữ (không tự unload)
export OLLAMA_KEEP_ALIVE=-1

# Unload ngay sau response (tiết kiệm RAM nhất)
export OLLAMA_KEEP_ALIVE=0

またはリクエストごとに:

response = ollama.chat(
    model='llama3.2',
    messages=[{'role': 'user', 'content': 'Hi'}],
    keep_alive='30m'
)

モデルを手動でアンロードする

# Unload model khỏi RAM ngay lập tức
ollama.chat(model='llama3.2', messages=[], keep_alive=0)

必要に応じて、より低い量子化を使用します

# Q8 — chất lượng cao nhất, tốn RAM nhất
ollama pull llama3.2:3b-instruct-q8_0

# Q4_K_M — balance (default)
ollama pull llama3.2:3b

# Q2_K — nhỏ nhất, chất lượng thấp hơn
# Tạo Modelfile custom với quantization thấp

スワップとメモリの負荷

# Check memory pressure
memory_pressure

# Xem swap usage
sysctl vm.swapusage

# Nếu quá nhiều swap → giảm model size hoặc num_ctx

推奨構成の概要

RAMマックスモデル数値ctx並列数最大ロード
8GB3B (Q4)2048年11
16GB7B (Q4)409622
24GB13B (Q4)819222
36GB27B (Q4)819243
64GB70B (Q4)1638484

演習

  1. MacBook RAM を確認し、最適な構成を設定します
  2. 上記のスクリプトを使用して 3 つの異なるモデルをベンチマークします。
  3. 同時実行性のテスト: OLLAMA_NUM_PARALLEL=1 対 2 対 4 を比較します。 4.アクティビティモニターを使用してモデルを実行する際のGPU使用率を監視する
  4. (おまけ) 利用可能な RAM に基づいてモデル/構成を自動的に選択するスクリプトを作成します。

次の記事: Modelfiles — カスタム モデルとシステム プロンプト →