Ollama は Hugging Face から GGUF を直接取得することができますが、量子化を指定するとエラーになることがあります。その時に調べたことをメモしておきます。
対処方法
以下で公開されている GGUF を例とします。
VRAM 16GB に収めるため 12.3GB の IQ3_S を使いたいのですが、pull に失敗します。
$ ollama pull hf.co/DavidAU/Mistral-Small-3.1-24B-Instruct-2503-MAX-NEO-Imatrix-GGUF:IQ3_S
pulling manifest
Error: pull model manifest: 400: The specified tag is not available in the repository. Please use another tag or "latest"
ファイル名を確認しました。
量子化はファイル名のサフィックスとして検索されるのではないかと推測して、:IQ3_S-imat
と指定すれば成功しました。
$ ollama pull hf.co/DavidAU/Mistral-Small-3.1-24B-Instruct-2503-MAX-NEO-Imatrix-GGUF:IQ3_S-imat
pulling manifest
pulling 95496228fa92... 100% ▕████████████████████████████████████████▏ 12 GB
pulling 6db27cd4e277... 100% ▕████████████████████████████████████████▏ 695 B
pulling ba2521a0e789... 100% ▕████████████████████████████████████████▏ 20 B
pulling 6d03bf5500a2... 100% ▕████████████████████████████████████████▏ 193 B
verifying sha256 digest
writing manifest
success
補足
Mistral-Small 3.1 を例にしましたが、別の GGUF が公開されています。
以下の理由で、こちらの利用を推奨します。
-
-imat
のようなサフィックスが付いていないので、ファイル名の確認が不要 - Ollama では対応していない Vision のデータがカットされている
- テキストのみの利用には支障なし
- ファイルサイズが軽い:Q4_K_M で 16.1GB → 14.3GB
別の問題
以前の Mistral-Small 2409 でも、GGUF が取得できないという問題が発生しました。
IQ3_M を pull しようとしても失敗します。
$ ollama pull hf.co/bartowski/Mistral-Small-Instruct-2409-GGUF:IQ3_M
pulling manifest
Error: pull model manifest: 400: The specified tag is not a valid quantization scheme. Please use another tag or "latest"
ファイル名を確認してもサフィックスは付いていません。Hugging Face 側で IQ3_M は認識されないらしく、量子化のリストにありませんでした。
他の GGUF を見ても同様に IQ3_M は認識されないようなので、Hugging Face の仕様みたいです。
仕方ないので手動でダウンロードして、Modelfile を書いて登録しました。
毎回 Modelfile を書くのは大変です。IQ3_M と IQ3_S はそこまで性能差はないようなので、もし IQ3_S があればそちらを使った方が無難かもしれません。
ソースコードを確認
量子化の指定がどのように処理されるのか、Ollama のソースコードを確認しました。
Ollama サーバーが pull 要求を処理するコードを追います。
switch cmd := flag.Arg(0); cmd {
case "pull":
rc, err := ollama.DefaultRegistry()
if err != nil {
log.Fatal(err)
}
return cmdPull(ctx, rc)
errc := make(chan error)
go func() {
errc <- rc.Pull(ctx, model)
}()
m, err := r.Resolve(ctx, name)
if err != nil {
return err
}
scheme, n, d, err := r.parseNameExtended(name)
if err != nil {
return nil, err
}
manifestURL := fmt.Sprintf("%s://%s/v2/%s/%s/manifests/%s", scheme, n.Host(), n.Namespace(), n.Model(), n.Tag())
if d.IsValid() {
manifestURL = fmt.Sprintf("%s://%s/v2/%s/%s/blobs/%s", scheme, n.Host(), n.Namespace(), n.Model(), d)
}
parseNameExtended
メソッドは入力文字列を解析して、scheme(スキーム)、name(名前)、digest(ダイジェスト)の3つの要素に分解します。
scheme, n, d, err := r.parseNameExtended("example.com/library/model:tag")
-
scheme
は指定されていないため、デフォルト値の"https"
-
n
はnames.Name
型-
n.Host()
:"example.com"
-
n.Namespace()
:"library"
-
n.Model()
:"model"
-
n.Tag()
:"tag"
-
-
d
はダイジェストが指定されていないため、空のblob.Digest
-
err
はエラーが発生しないのでnil
よって manifestURL
は "https://example.com/v2/library/model/manifests/tag"
となります。
この URL に対して API リクエストを行い、その結果に基づいてモデルをダウンロードします。量子化を指定する tag
は API のサーバー側で処理されるため、具体的な処理方法は Ollama のソースコードからは確認できませんでした。
例
Mistral-Small 3.1 の GGUF は次のようになります。
- name:
hf.co/DavidAU/Mistral-Small-3.1-24B-Instruct-2503-MAX-NEO-Imatrix-GGUF:IQ3_S-imat
- manifestURL:
https:/hf.co/v2/DavidAU/Mistral-Small-3.1-24B-Instruct-2503-MAX-NEO-Imatrix-GGUF/manifests/IQ3_S-imat
この URL にアクセスすれば JSON が返されます。
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"digest": "sha256:6d03bf5500a220805a88919dbabf2f94f38b67b55ecc4dc01dfd8d36640baca1",
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 193
},
"layers": [
{
"digest": "sha256:95496228fa9288db6bd1983b5ba7aeb65697080fb2dde61e8071f22f442a79e2",
"mediaType": "application/vnd.ollama.image.model",
"size": 12273620192
},
{
"digest": "sha256:6db27cd4e277c91264572b9c899c1980daa8dea11e902f0070a6f4763f3d13c8",
"mediaType": "application/vnd.ollama.image.template",
"size": 695
},
{
"digest": "sha256:ba2521a0e7896c890e81ae7e9892882bfc3d4bb43a3a989ddfe2852f70056eb5",
"mediaType": "application/vnd.ollama.image.params",
"size": 20
}
]
}
この情報に基づいてダウンロードが行われます。
調査方法
Ollama のソースコードは巨大なため、どこを見ればよいのか探すのに一苦労します。
まず Cursor でリポジトリを開いて Codebase で当たりを付けると、C++ の common_get_hf_file()
が示されました。
@Codebase Hugging FaceからGGUFをダウンロードするとき、指定された量子化ファイルを探す箇所。
std::pair<std::string, std::string> common_get_hf_file(const std::string & hf_repo_with_tag, const std::string & hf_token) {
この関数では API 用の URL を生成しています。
std::string url = "https://huggingface.co/v2/" + hf_repo + "/manifests/" + tag;
この時点でソースコードを追っても処理方法は書かれていないことが判明しました。
Ollama 本体は Go で書かれていますが、Go からこの C++ の関数が呼ばれている形跡はありません。Go のオプションがどこで処理されているかを探すと server/internal/cmd/opp/opp.go であることが分かりました。
Codebase ではコード量が巨大な C++ 部分に引っ張られてしまうようなので、その先は Claude の Web サイトに切り替えて、GitHub 連携で server/internal 以下を読み込んで調査しました。
メンションでフォルダを絞り込んでも良かったのですが、Cursor の無料枠を使い切って Gemini を使っていると、箇条書きの中でインデントされた引用がうまくレンダリングされずに読みにくかったため、Claude に切り替えました。
関連記事
Modelfile の書き方
Cursor の無料枠に追加設定する方法