HuggingFaceのオンラインモデル読込、スナップショットのダウンロード、ローカルモデル読込をしてみる（Llama3.2）

記載日2025/03/09

備忘録です。
transformersを使って、HuggingFaceのモデル読込やスナップショットのダウンロード、ローカルにあるモデルの読込について、pythonでのやり方を記載します。LLMモデルはLlama3.2（3bと11b）を使います。
なお、Llama3.2:3bのモデルをロードやローカル保存する場合、容量を数G使います。Llama3.2:11bの場合は数十G使いますのでご注意ください。また、モデルを使う場合、Llama3.2:11bはGPU必須です(たぶん25Gくらい必要)。


## 環境
・OS : Ubuntu22.04（正確には、Windows11上のWSL2環境。GPUは60Gほど。）
・python : 3.11.11 (私の環境ではpyenvを使っています)

## HuggingFace
AIモデルやデータセットを共有・利用するためのツールです。雑に言うと、AIモデル用Githubというイメージです。ホームページは[こちら](https://huggingface.co/)。

## 手順
### huggingface-hub (CLI) のインストール
AIモデルのダウンロードにhuggingface-hubを使います。huggingface-hub自体は`pip`でインストールできますが、モデルダウンロードにはHuggingFaceのアクセストークンを使う必要があります。
また、Llama3.2モデルの使用には、HuggingFaceのLlama3.2のウェブページにてMeta社へ利用申請をする必要があります。
このような理由から、huggingface-cliを使うために以下4ステップを踏みます。
詳細は[参考](https://qiita.com/drafts/b37fda326801f04fa35d/edit#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%95%E3%81%9B%E3%81%A6%E9%A0%82%E3%81%84%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88)の「HuggingFaceとは」「Llama3.2利用申請について」のサイトを確認ください。
- HuggingFaceにアカウント作成
- Meta社への利用申請
- アクセストークン作成
- huggingface-hubインストール

### ライブラリのインストール
適宜必要なライブラリをpipでインストールしてください。参考までに、私の環境のrequirements.txtを以下に記載します。
<details><summary>requirements.txt</summary>

~~~ txt
accelerate==1.4.0
bitsandbytes==0.45.2
certifi==2025.1.31
charset-normalizer==3.4.1
huggingface-hub==0.28.1
filelock==3.17.0
fsspec==2025.2.0
idna==3.10
Jinja2==3.1.5
MarkupSafe==3.0.2
mpmath==1.3.0
networkx==3.4.2
numpy==2.2.2
nvidia-cublas-cu12==12.4.5.8
nvidia-cuda-cupti-cu12==12.4.127
nvidia-cuda-nvrtc-cu12==12.4.127
nvidia-cuda-runtime-cu12==12.4.127
nvidia-cudnn-cu12==9.1.0.70
nvidia-cufft-cu12==11.2.1.3
nvidia-curand-cu12==10.3.5.147
nvidia-cusolver-cu12==11.6.1.9
nvidia-cusparse-cu12==12.3.1.170
nvidia-cusparselt-cu12==0.6.2
nvidia-nccl-cu12==2.21.5
nvidia-nvjitlink-cu12==12.4.127
nvidia-nvtx-cu12==12.4.127
packaging==24.2
pillow==11.1.0
PyYAML==6.0.2
regex==2024.11.6
requests==2.32.3
safetensors==0.5.2
sympy==1.13.1
tokenizers==0.21.0
torch==2.6.0
tqdm==4.67.1
transformers==4.48.3
triton==3.2.0
typing_extensions==4.12.2
urllib3==2.3.0

~~~
</details>

### コード
※次のコードは、事前にhuggingface-hubでloginする必要があるかと思います（もしかすると環境変数 : HF_TOKENにアクセストークンを設定しないとうまく動かない方もいるかもしれません。）。login関数を使ってコード完結することもできると思います。

pythonで、オンラインモデル読込、スナップショットのダウンロード、ローカルモデル読込を行うコードサンプルは下記です。3b用、11b用で分けていますが、中身はほぼ同じです。違いは以下。
- Llama3.2:3bはテキストのみのモデルなので、モデル作成クラスは`AutoModelForCausalLM`を使用
- Llama3.2:11bはビジョンモデルなので、モデル作成クラスは`MllamaForConditionalGeneration`を使用

~~~ python
# Llama.py
import os
import requests
import torch
from PIL import Image
from transformers import AutoModelForCausalLM, AutoProcessor, AutoTokenizer, BitsAndBytesConfig, MllamaForCausalLM, MllamaForConditionalGeneration, pipeline
from huggingface_hub import snapshot_download

class Llama():
    model_id_3b = "meta-llama/Llama-3.2-3B-Instruct"
    model_id_vision_11b = "meta-llama/Llama-3.2-11B-Vision-Instruct"

    # 4bit量子化
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.bfloat16
    )

    def __init__(self):
        # 次の1~4のいずれかでモデルを読み込む
        
        # 1) 11bのスナップショットダウンロードおよびモデル読込
        self.download_snapshot(self.model_id_vision_11b, "./llm/snapshot/11b/")
        self.load_local_model_11b("./llm/snapshot/11b/")

        # 2) 3bのスナップショットダウンロードおよびモデル読込
        # self.download_snapshot(self.model_id_3b, "./llm/snapshot/3b/")
        # self.load_local_model_3b("./llm/snapshot/3b/")
        
        # 3) 11bのオンラインモデル読込
        # self.load_online_model_11b(self.model_id_vision_11b)
        
        # 4) 3bのオンラインモデル読込
        # self.load_online_model_3b(self.model_id_3b)
    
    def download_snapshot(self, model_id, model_dir: str):
        # プロジェクトディレクトリを基準として、"./llm/snapshot/"にモデルファイルが保存される。
        snapshot_download(model_id, local_dir=model_dir)

    def load_local_model_11b(self, model_dir: str):
        self.model = MllamaForConditionalGeneration.from_pretrained(
            model_dir,
            torch_dtype=torch.bfloat16,
            quantization_config=self.bnb_config,
            device_map="auto"
        )
    
    def load_online_model_11b(self, model_id):
        # モデル作成クラスはVisionで使えるMllamaForConditionalGenerationを使う
        self.model = MllamaForConditionalGeneration.from_pretrained(
            model_id,
            torch_dtype=torch.bfloat16,
            quantization_config=self.bnb_config,
            device_map="auto"
        )
        self.processor = AutoProcessor.from_pretrained(model_id)
        self.tokenizer = AutoTokenizer.from_pretrained(model_id)
        
        # モデルのローカル保存
        self.model.save_pretrained("./llm/online/11b/")
        self.processor.save_pretrained("./llm/online/11b/")
        self.tokenizer.save_pretrained("./llm/online/11b/")

    def load_local_model_3b(self, model_dir: str):
        self.model = AutoModelForCausalLM.from_pretrained(
            model_dir,
            torch_dtype=torch.bfloat16,
            quantization_config=self.bnb_config,
            device_map="auto"
        )
    
    def load_online_model_3b(self, model_id):
        # モデル作成クラスはAutoModelForCausalLMを使う
        self.model = AutoModelForCausalLM.from_pretrained(
            model_id,
            torch_dtype=torch.bfloat16,
            quantization_config=self.bnb_config,
            device_map="auto"
        )
        self.processor = AutoProcessor.from_pretrained(model_id)
        self.tokenizer = AutoTokenizer.from_pretrained(model_id)

        # モデルのローカル保存
        self.model.save_pretrained("./llm/online/3b/")
        self.processor.save_pretrained("./llm/online/3b/")
        self.tokenizer.save_pretrained("./llm/online/3b/")

~~~


### 参考にさせて頂いたサイト
・HuggingFaceとは
https://udemy.benesse.co.jp/data-science/huggingface.html
・Llama3.2利用申請について
https://highreso.jp/edgehub/machinelearning/llama32.html