この記事で分かること
Hugging Face 形式のモデルを ollama create --quantize で取り込むたびに、約 50GB の中間ファイルが残り続け、ollama rm でも消えないことに気づかず、830GB 消えていました。原因の場所と、安全に掃除するスクリプトを書きます。
前提知識
Ollama はモデルを ~/.ollama/models 以下に保存します。
-
blobs/: 実体 (重みなど)。ファイル名は内容の SHA-256。 -
manifests/: モデル名ごとに「どの blob を使うか」を書いた JSON。
ollama rm <name> は manifest を消し、その manifest が参照していた blob を消します。どの manifest からも参照されていない blob は誰も消しません。
症状
ollama list の合計は 188GB なのに、du -sh ~/.ollama/models は 948GB でした。差の 830GB は、manifest から参照されていない blob 69 個で、うち 12 個が 50.5GB (取り込んだモデルの F16 精度の重みと同じサイズ) でした。
12 個の更新時刻は、過去に ollama create --quantize q4_K_M が成功した時刻と一致します。既知の報告 (ollama/ollama #18146) は「失敗したときに残る」ケースですが、成功しても残ります。Ollama のソースを読むと、safetensors から変換した F16 の GGUF をいったん blob として保存し、そこから量子化した別の blob を作って manifest に載せるため、元の F16 blob が参照されずに残る構造でした (ollama 0.33.3 で確認、報告済み: ollama/ollama #18416)。
確認方法
ollama list # 登録モデルの合計サイズを足す
du -sh ~/.ollama/models # 実際の使用量
差が大きければ未参照 blob があります。
掃除スクリプト
manifest が参照している blob の一覧を作り、blobs/ にあってその一覧に無いものだけを消します。
#!/usr/bin/env python3
"""manifest から参照されていない Ollama の blob を削除する。--dry-run で一覧のみ。"""
import json, pathlib, sys
root = pathlib.Path.home() / ".ollama/models"
dry = "--dry-run" in sys.argv
referenced = set()
for mf in (root / "manifests").rglob("*"):
if not mf.is_file():
continue
try:
d = json.loads(mf.read_text())
except Exception:
continue
for layer in d.get("layers", []) + [d.get("config", {})]:
if dg := layer.get("digest", ""):
referenced.add(dg.replace(":", "-")) # manifest は sha256:… 、ファイル名は sha256-…
orphans = [p for p in (root / "blobs").iterdir() if p.is_file() and p.name not in referenced]
print(f"未参照: {len(orphans)} 個, {sum(p.stat().st_size for p in orphans) / 1e9:.0f} GB")
if not dry:
for p in orphans:
p.unlink()
注意点:
- まず
--dry-runで件数と容量を確認する。 -
ollama createの実行中は走らせない。作成途中の blob はまだ manifest に無いので、未参照に見えて消してしまいます。ollama psが空で、create が動いていないことを確認してから実行してください。
教訓
-
dfの空きだけ見ていると原因を取り違えます (私は別の中間ファイルを疑って 2 回無駄な調査をしました)。ollama listの合計とduの差を見る。 - モデルの取り込みを自動化しているなら、取り込み直後に上のスクリプトを 1 行足しておくと再発しません。