# Unsloth を使って Intel GPU 上の LLM をファインチューニングする

Unslothを使えば、ローカルのIntelデバイス上でLLMのファインチューニングが可能になりました！独自のカスタムモデルをトレーニングするための開始手順については、ガイドをお読みください。

開始する前に、以下を確認してください：

* **Intel GPU：** Data Center GPU Maxシリーズ、Arcシリーズ、またはIntel Ultra AIPC
* **OS：** Linux（Ubuntu 22.04以上を推奨）またはWindows 11（推奨）
* **Windowsのみ：** Intel oneAPI Base Toolkit 2025.2.1 をインストール（バージョン2025.2.1を選択）
* **Intel Graphicsドライバー：** Windows/Linux向けの最新の推奨ドライバー
* **Python：** 3.10+

### Intelサポート付きでUnslothをビルドする

{% stepper %}
{% step %}

#### 新しいconda環境を作成（任意）

```bash
conda create -n unsloth-xpu python==3.10
conda activate unsloth-xpu
```

{% endstep %}

{% step %}

#### Unslothをインストールする

```bash
git clone https://github.com/unslothai/unsloth.git
cd unsloth
pip install .[intel-gpu-torch290]
```

{% hint style="info" %}
Linuxのみ：インストール [vLLM](https://unsloth.ai/docs/jp/ji-ben/inference-and-deployment/vllm-guide) (任意)\
推論のためにvLLMをインストールすることもできます [推論](https://unsloth.ai/docs/jp/ji-ben/inference-and-deployment) および [強化学習](https://unsloth.ai/docs/jp/meru/reinforcement-learning-rl-guide)。次に従ってください [vLLMのガイド](https://docs.vllm.ai/en/latest/getting_started/installation/gpu/#intel-xpu).
{% endhint %}
{% endstep %}

{% step %}

#### 環境を検証する

```python
import torch
print(f"PyTorch version: {torch.__version__}")
print(f"XPU available: {torch.xpu.is_available()}")
print(f"XPU device count: {torch.xpu.device_count()}")
print(f"XPU device name: {torch.xpu.get_device_name(0)}")
```

{% endstep %}

{% step %}

#### ファインチューニングを開始する。

Unslothの [ノートブック](https://unsloth.ai/docs/jp/meru/unsloth-notebooks) を直接使用するか、専用の [ファインチューニング](https://unsloth.ai/docs/jp/meru/fine-tuning-llms-guide) または [強化学習](https://unsloth.ai/docs/jp/meru/reinforcement-learning-rl-guide) ガイドを参照してください。
{% endstep %}
{% endstepper %}

### Windowsのみ - ランタイム構成

管理者権限でコマンドプロンプトを開き、Windowsレジストリで長いパスのサポートを有効にします：

```bash
powershell -Command "Set-ItemProperty -Path "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\FileSystem" -Name "LongPathsEnabled" -Value 1
```

このコマンドは単一のマシンで一度だけ設定すればよく、毎回実行前に設定する必要はありません。次に：

1. level-zero-win-sdk-1.20.2.zip をからダウンロードします [GitHub](https://github.com/oneapi-src/level-zero/releases/tag/v1.20.2)
2. level-zero-win-sdk-1.20.2.zip を解凍する
3. コマンドプロンプトで、conda環境 unsloth-xpu の下で：

```bash
call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" -
set ZE_PATH=unzipped\level-zero-win-sdk-1.20.2 のパス
```

### 例1: SFTを用いたQLoRAファインチューニング

この例では、Intel GPU上で4ビットQLoRAを使ってQwen3-32Bモデルをファインチューニングする方法を示します。QLoRAはメモリ要件を大幅に削減し、消費者向けハードウェアで大規模モデルのファインチューニングを可能にします。

{% code expandable="true" %}

```python
from unsloth import FastLanguageModel, FastModel
from trl import SFTTrainer, SFTConfig
from datasets import load_dataset
max_seq_length = 2048 # 内部でRoPEスケーリングをサポートしているため、任意の値を選択できます！
# LAIONデータセットを取得
url = "https://huggingface.co/datasets/laion/OIG/resolve/main/unified_chip2.jsonl"
dataset = load_dataset("json", data_files = {"train" :
url}, split = "train")

# 高速ダウンロードとOOM回避のためにサポートされる4ビット事前量子化モデル。
fourbit_models = [
"unsloth/Qwen3-32B-bnb-4bit",
"unsloth/Qwen3-14B-bnb-4bit",
"unsloth/Qwen3-8B-bnb-4bit",
"unsloth/Qwen3-4B-bnb-4bit",
"unsloth/Qwen3-1.7B-bnb-4bit",
"unsloth/Qwen3-0.6B-bnb-4bit",
# "unsloth/Qwen2.5-32B-bnb-4bit",
# "unsloth/Qwen2.5-14B-bnb-4bit",
# "unsloth/Qwen2.5-7B-bnb-4bit",
# "unsloth/Qwen2.5-3B-bnb-4bit",
# "unsloth/Qwen2.5-1.5B-bnb-4bit",
# "unsloth/Qwen2.5-0.5B-bnb-4bit",
# "unsloth/Llama-3.2-3B-bnb-4bit",
# "unsloth/Llama-3.2-1B-bnb-4bit",
# "unsloth/Llama-3.1-8B-bnb-4bit",
# "unsloth/Llama-3.1-70B-bnb-4bit",
# "unsloth/mistral-7b-bnb-4bit",
# "unsloth/Phi-4",
# "unsloth/Phi-3.5-mini-instruct",
# "unsloth/Phi-3-medium-4k-instruct",
# "unsloth/Phi-3-mini-4k-instruct",
# "unsloth/gemma-2-9b-bnb-4bit",
# "unsloth/gemma-2-27b-bnb-4bit",
] # その他のモデルは https://huggingface.co/unsloth を参照

model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Qwen3-32B-bnb-4bit",
max_seq_length = max_seq_length,
load_in_4bit = True,
# token = "hf_...", # meta-llama/Llama-2-7b-hfのようなゲート付きモデルを使用する場合はトークンを使用
)

model = FastLanguageModel.get_peft_model(
model,
r = 16, # 任意の正の数を選択！推奨：8, 16, 32, 64, 128
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_alpha = 16,
lora_dropout = 0, # 任意の値をサポートしますが、= 0 が最適化されています
bias = "none", # 任意の値をサポートしますが、= "none" が最適化されています
use_gradient_checkpointing = "unsloth", # 非常に長いコンテキストの場合は True または "unsloth"
random_state = 3407,
use_rslora = False, # ランク安定化LoRAをサポートしています
loftq_config = None, # およびLoftQ
)

trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 1, # Windowsで推奨
packing = False, # 短いシーケンスではトレーニングを5倍速くすることがあります。
args = SFTConfig(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
max_steps = 60,
learning_rate = 2e-4,
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
dataset_num_proc=1, # Windowsで推奨
),
)

trainer.train()
```

{% endcode %}

### 例2: 強化学習 GRPO

GRPOは [強化学習](https://unsloth.ai/docs/jp/meru/reinforcement-learning-rl-guide) 言語モデルを人間の好みに合わせるための手法です。この例では、複数の報酬関数を使って特定のXML出力形式に従うようにモデルを訓練する方法を示します。

#### GRPOとは何ですか？

GRPOは従来のRLHFを改善し、以下を行います：

* より安定したトレーニングのためのグループベース正規化を使用すること
* 複数の報酬関数をサポートして多目的最適化を可能にすること
* PPOよりメモリ効率が良いこと

{% code expandable="true" %}

```python
from unsloth import FastLanguageModel
import re
from trl import GRPOConfig, GRPOTrainer
from datasets import load_dataset, Dataset

max_seq_length = 1024  # より長い推論トレースのために増やすことができます
lora_rank = 32  # ランクが大きいほど賢くなりますが遅くなります
max_prompt_length = 256

# データセットの読み込みと準備
SYSTEM_PROMPT = """
以下の形式で応答してください：
<reasoning>
...
</reasoning>
<answer>
...
</answer>
"""

XML_COT_FORMAT = """\
<reasoning>
{reasoning}
</reasoning>
<answer>
{answer}
</answer>
"""


def extract_xml_answer(text: str) -> str:
    answer = text.split("<answer>")[-1]
    answer = answer.split("</answer>")[0]
    return answer.strip()


def extract_hash_answer(text: str) -> str | None:
    if "####" not in text:
        return None
    return text.split("####")[1].strip()


# 1ショットプロンプティングのために中間のメッセージをアンコメントしてください
def get_gsm8k_questions(split: str = "train") -> Dataset:
    data = load_dataset("openai/gsm8k", "main")[split]  # type: ignore
    data = data.map(
        lambda x: {  # type: ignore
            "prompt": [
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": x["question"]},
            ],
            "answer": extract_hash_answer(x["answer"]),
        }
    )  # type: ignore
    return data  # type: ignore


# 報酬関数
def correctness_reward_func(prompts, completions, answer, **kwargs) -> list[float]:
    responses = [completion[0]["content"] for completion in completions]
    q = prompts[0][-1]["content"]
    extracted_responses = [extract_xml_answer(r) for r in responses]
    print(
        "-" * 20,
        f"Question:\n{q}",
        f"\nAnswer:\n{answer[0]}",
        f"\nResponse:\n{responses[0]}",
        f"\nExtracted:\n{extracted_responses[0]}",
    )
    return [2.0 if r == a else 0.0 for r, a in zip(extracted_responses, answer)]


def int_reward_func(completions, **kwargs) -> list[float]:
    responses = [completion[0]["content"] for completion in completions]
    extracted_responses = [extract_xml_answer(r) for r in responses]
    return [0.5 if r.isdigit() else 0.0 for r in extracted_responses]


def strict_format_reward_func(completions, **kwargs) -> list[float]:
    """補完が特定の形式を持っているかどうかをチェックする報酬関数。"""
    pattern = r"^<reasoning>\n.*?\n</reasoning>\n<answer>\n.*?\n</answer>\n$"
    responses = [completion[0]["content"] for completion in completions]
    matches = [re.match(pattern, r) for r in responses]
    return [0.5 if match else 0.0 for match in matches]


def soft_format_reward_func(completions, **kwargs) -> list[float]:
    """補完が特定の形式を持っているかどうかをチェックする報酬関数。"""
    pattern = r"<reasoning>.*?</reasoning>\s*<answer>.*?</answer>"
    responses = [completion[0]["content"] for completion in completions]
    matches = [re.match(pattern, r) for r in responses]
    return [0.5 if match else 0.0 for match in matches]


def count_xml(text: str) -> float:
    count = 0.0
    if text.count("<reasoning>\n") == 1:
        count += 0.125
    if text.count("\n</reasoning>\n") == 1:
        count += 0.125
    if text.count("\n<answer>\n") == 1:
        count += 0.125
    count -= len(text.split("\n</answer>\n")[-1]) * 0.001
    if text.count("\n</answer>") == 1:
        count += 0.125
    count -= (len(text.split("\n</answer>")[-1]) - 1) * 0.001
    return count


def xmlcount_reward_func(completions, **kwargs) -> list[float]:
    contents = [completion[0]["content"] for completion in completions]
    return [count_xml(c) for c in contents]


if __name__ == "__main__":
    model, tokenizer = FastLanguageModel.from_pretrained(
        model_name="unsloth/Qwen3-0.6B",
        max_seq_length=max_seq_length,
        load_in_4bit=False,  # LoRA用はFalse（16ビット）
        fast_inference=False,  # vLLMの高速推論を有効にする
        max_lora_rank=lora_rank,
        gpu_memory_utilization=0.7,  # メモリ不足時は減らす
        device_map="xpu:0",
    )

    model = FastLanguageModel.get_peft_model(
        model,
        r=lora_rank,  # 任意の正の数を選択！推奨：8, 16, 32, 64, 128
        target_modules=[
            "q_proj",
            "k_proj",
            "v_proj",
            "o_proj",
            "gate_proj",
            "up_proj",
            "down_proj",
        ],  # メモリ不足の場合はQKVOを削除
        lora_alpha=lora_rank,
        use_gradient_checkpointing="unsloth",  # 長いコンテキストのファインチューニングを有効にする
        random_state=3407,
    )

    dataset = get_gsm8k_questions()

    training_args = GRPOConfig(
        learning_rate=5e-6,
        adam_beta1=0.9,
        adam_beta2=0.99,
        weight_decay=0.1,
        warmup_ratio=0.1,
        lr_scheduler_type="cosine",
        optim="adamw_torch",
        logging_steps=1,
        per_device_train_batch_size=1,
        gradient_accumulation_steps=1,  # 滑らかなトレーニングのために4に増やす
        num_generations=4,  # メモリ不足の場合は減らす
        max_prompt_length=max_prompt_length,
        max_completion_length=max_seq_length - max_prompt_length,
        # num_train_epochs=1,  # フルトレーニング実行の場合は1に設定
        max_steps=20,
        save_steps=250,
        max_grad_norm=0.1,
        report_to="none",  # Weights & Biasesを使用できます
        output_dir="outputs",
    )

    trainer = GRPOTrainer(
        model=model,
        processing_class=tokenizer,
        reward_funcs=[
            xmlcount_reward_func,
            soft_format_reward_func,
            strict_format_reward_func,
            int_reward_func,
            correctness_reward_func,
        ],
        args=training_args,
        train_dataset=dataset,
        dataset_num_proc=1,  # Windowsで推奨
    )

    trainer.train()

```

{% endcode %}

## トラブルシューティング

### メモリ不足（OOM）エラー

メモリ不足が発生した場合は、次の対策を試してください：

1. **バッチサイズを減らす：** より低い `per_device_train_batch_size`.
2. **より小さいモデルを使用する：** メモリ要件を減らすために、より小さいモデルから始めてください。
3. **シーケンス長を減らす：** より低い `max_seq_length`.
4. **LoRAランクを下げる：** 使用する `r=8` の代わりに `r=16` または `r=32`.
5. **GRPOの場合、生成数を減らす：** より低い `num_generations`.

### (Windowsのみ) Intel Ultra AIPC iGPU 共有メモリ

Windows上で最近のGPUドライバーを使用するIntel Ultra AIPCでは、統合GPUの共有GPUメモリは通常システムメモリの **57%** になります。より大きなモデル（例： **Qwen3-32B**）や、より長い最大シーケンス長、大きなバッチサイズ、より大きなLoRAランクのLoRAアダプタなどをファインチューニング中に使用する場合、iGPUに割り当てられるシステムメモリの割合を増やすことで利用可能なVRAMを増やすことができます。

これを調整するにはレジストリを変更できます：

* パス： `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\MemoryManager`
* 変更するキー：\
  `SystemPartitionCommitLimitPercentage` （より大きなパーセンテージに設定）


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://unsloth.ai/docs/jp/meru/install/intel.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
