Ollamaを用いたローカルLLM環境の構築とGPUアクセラレーション最適化

OllamaによるローカルLLM基盤構築:VRAM管理の仕組みとDockerを用いたGPU最適化の完全設計

約17分で読めます
文字サイズ:
OllamaによるローカルLLM基盤構築:VRAM管理の仕組みとDockerを用いたGPU最適化の完全設計
目次

この記事の要点

  • OllamaによるセキュアなローカルLLM環境構築
  • VRAM管理の最適化によるGPU性能最大化
  • Dockerを用いたGPUパススルーの実践

イントロダクション

「社内の機密データを扱うため、ChatGPTやClaudeのようなパブリッククラウド上のLLM(大規模言語モデル)は利用禁止」。

パブリッククラウドのAIモデルは、長文の文脈理解や高度な推論、さらには自律的なPC操作まで実現するなど、目覚ましい進化を遂げています。旧モデルから新たな標準モデルへの移行が絶えず進み、その利便性は高まる一方ですが、多くの企業では依然として厳格なセキュリティポリシーが壁となります。そこで解決策として注目を集めているのがローカルLLMです。

自社サーバー内で完結するAI環境であれば、データ漏洩のリスクを物理的に遮断できます。その中でも「Ollama」は、Go言語で開発された軽量かつ強力な実行環境として、急速にデファクトスタンダード(事実上の標準)の地位を確立しつつあります。コマンド一つで最新のモデルをダウンロードし、APIサーバーとして稼働させることができる手軽さは革命的でした。さらに最近では、コーディングに特化したモデルの実行やOCR(光学文字認識)対応、実験的な画像生成にまで対応領域を広げており、その活用幅は広がるばかりです。

しかし、企業が本格的な導入を進める中で、共通の課題が頻繁に報告されています。

「個人のPCで試したときは快適だったのに、社内サーバーで複数人が使い始めた途端、応答が極端に遅くなる」
「GPUを搭載しているはずなのに、なぜかCPUがフル稼働してファンが唸りを上げている」
「長時間稼働させていると、いつの間にかプロセスが落ちてしまう」

これらはすべて、「とりあえず動かす」ための初期設定と、「業務インフラとして安定稼働させる」ためのシステム設計のギャップから生じています。

専門家の視点から見ると、Ollamaを企業インフラとして採用する場合、単なるソフトウェアのインストール作業として捉えてはいけません。それは、限られたハードウェアリソース(特にVRAMと呼ばれるGPUのメモリ)をいかに効率的に配分し、モデルの推論能力を最大化するかという、高度なリソース管理の問題なのです。扱うモデルが高性能化・多様化するほど、この最適化の重要性は増していきます。

本記事では、Ollamaの内部アーキテクチャに踏み込み、GPUアクセラレーションの仕組み、失敗しないハードウェアサイジング、そしてDockerを用いた再現性の高い構築手法について、実証に基づいた実践的なアプローチを共有します。原因不明のエラーやパフォーマンス低下に悩まされる状態から抜け出し、社内の計算リソースを極限まで引き出す堅牢な推論環境を構築するための指針としてください。

なぜ「とりあえずインストール」では失敗するのか:ローカルLLM運用の落とし穴

Ollamaの公式サイトにある「Download」ボタンを押し、インストーラーを実行する。確かにこれだけでAIは動き出します。しかし、この手軽さこそが、後の運用トラブルの温床となることがあります。システム全体の視点から、そのリスクを論理的に分解してみましょう。

手軽さの裏にあるリソース管理の難しさ

Ollamaは非常に賢いソフトウェアです。起動時にシステムのリソースを自動検出し、利用可能なGPUがあれば自動的にモデルを読み込もうと試みます。しかし、この「自動設定」はあくまで一般的な個人利用を想定した、ベストエフォート型(その時できる最大限の努力をする)の挙動です。

企業ユースの場合、サーバー上では他のアプリケーションも稼働しているかもしれませんし、あるいは複数のAIモデルを切り替えて使うニーズがあるかもしれません。デフォルト設定のままでは、OllamaがGPUメモリ(VRAM)を独占してしまい、OSの画面描画に必要なリソースさえ枯渇させてしまうことがあります。逆に、慎重になりすぎてGPUを十分に使い切れず、高価なハードウェアを遊ばせてしまうケースも散見されます。

推論速度低下の主犯:CPUオフロード問題

ローカルLLM運用で最も頻繁に起こるパフォーマンス問題が、「予期せぬCPUオフロード」です。

LLMの推論処理は、巨大な計算の塊です。これは並列処理が得意なGPUが最も力を発揮する領域ですが、モデルのサイズがVRAM容量をわずかでも超えた場合、Ollama(の裏側で動いているllama.cppというプログラム)は、溢れた部分をメインメモリ(RAM)に退避させ、CPUで計算を行おうとします。

これを「オフロード」と呼びますが、ここには大きな落とし穴があります。GPUのメモリ帯域幅(データを転送する道の太さ)が数百GB/s〜1TB/sクラスであるのに対し、メインメモリの帯域幅はその数分の一から十分の一程度しかありません。さらに、GPUとCPU間のデータ転送経路がボトルネック(渋滞の要因)となります。

結果として、モデルの一部でもCPU処理に回ると、推論速度はガクンと落ちます。「1秒あたり50文字生成できていたのが、急に3文字になった」というような劇的な劣化です。チャットボットであれば、ユーザーは「壊れた」と感じて利用をやめてしまうでしょう。

ビジネスユースで求められる安定性とは

趣味の利用であれば、エラーが出たら再起動すれば済みます。しかし、社内業務システムに組み込まれたAIが、会議中の重要な要約タスクでクラッシュすることは許されません。

ビジネスユースで求められるのは、以下の3点です。

  1. 予測可能性: どの程度の負荷まで耐えられるかが、データに基づいて計算できていること。
  2. 分離性: 特定の処理が暴走しても、システム全体を巻き込まないこと。
  3. 再現性: 開発環境と同じ構成を、本番環境でも即座に構築できること。

これらを満たすためには、Ollamaの「おまかせ機能」に頼るのではなく、意図を持って構成を定義する必要があります。

Ollamaのアーキテクチャ解剖:GPUアクセラレーションはどう機能しているか

Ollamaのアーキテクチャ解剖:GPUアクセラレーションはどう機能しているか - Section Image

ブラックボックスになりがちなOllamaの内部挙動を理解することは、トラブルシューティングの近道です。ここでは、モデルがどのようにメモリに展開され、計算が行われるのかを分かりやすく見ていきます。

llama.cppベースの推論エンジンの仕組み

Ollamaの中核には、llama.cppというオープンソースのプログラムが存在します。これは、元々MacBookなどのApple Silicon向けに最適化されていた推論エンジンを、NVIDIAやAMDのGPUにも対応させたものです。

Ollamaの役割は、このllama.cppを包み込み、モデルの管理、APIサーバー機能、そしてプロンプトの処理などを統合した「使いやすい窓口」を提供することにあります。技術的には、GGUFというファイルフォーマットを採用しており、これが単一ファイルでのモデル配布と効率的な読み込みを可能にしています。

重要なのは、Ollamaがモデルを読み込む際、モデルを「レイヤー(層)」という単位で分割して管理している点です。Transformerアーキテクチャに基づくLLMは、数十から数百の層がミルフィーユのように積み重なった構造をしています。

モデルレイヤーのVRAM/RAM配分ロジック

ユーザーがプロンプトを送信すると、Ollamaは以下の判断を瞬時に行います。

  1. ロードすべきモデルのファイルサイズを確認する。
  2. 利用可能なVRAMの空き容量を確認する。
  3. 全てのレイヤーがVRAMに収まるか?
    • Yesの場合: 全レイヤーをGPUに転送します。これが最速の状態です。
    • Noの場合: VRAMに収まる限界までのレイヤーをGPUに載せ、残りをCPU(メインメモリ)で処理するように分割します。

この「分割判断」が、先述したパフォーマンス劣化の分かれ目です。ログを確認すると、offloaded 32/32 layers to GPU といった表示が出ます。これが 20/32 などになっていると、一部がCPU処理に回っていることを意味し、データ転送の渋滞が発生して速度が低下します。

量子化(Quantization)とメモリ帯域の関係

ここで「量子化」という技術が重要になります。従来、AIモデルのデータは非常に細かい精度(16ビットや32ビット)で表現されてきました。しかし、推論処理においては、これではメモリサイズと帯域幅を過剰に消費してしまいます。

最新のハードウェアトレンドを見ても、AI推論においては「いかに精度を保ちつつデータ量を減らすか」が焦点となっています。

Ollamaで標準的に使われるGGUFフォーマットの「4ビット量子化」などは、この流れをソフトウェア側で実現したものです。

  • 容量の削減: モデルサイズを約1/4に圧縮し、限られたVRAMにより大きなモデルを載せることを可能にします。
  • メモリ帯域幅の節約: ここが最も重要です。GPUの計算速度よりも、VRAMからデータを読み出す速度がボトルネックになるケースが大半です。データサイズが小さければ、一度に転送できる情報量が増え、結果として文章の生成速度が向上します。

つまり、「高性能なGPUを買う」だけでなく、「適切な量子化モデルを選んでVRAMに完全に収める」ことこそが、ローカルLLM最適化の鍵なのです。

失敗しないサイジング:モデル規模とハードウェアの適正マッチング

「これからサーバーを調達するが、どのGPUを選べばいいか」という疑問をよく耳にします。ここでは、感覚値ではなく計算に基づいたサイジング(規模の見積もり)手法を解説します。

7B, 13B, 70Bモデルに必要なVRAM計算式

モデルのパラメータ数(B = Billion = 10億)と量子化ビット数から、必要なVRAM容量を概算する式は以下の通りです。

必要VRAM容量 (GB) ≈ パラメータ数 (B) × (量子化ビット数 / 8) + アルファ

例えば、8Bモデルを4ビット量子化で動かす場合:
8 × (4 / 8) = 4 GB

これに、推論時の作業領域(過去の会話を覚えておくためのメモリなど)として「アルファ」が必要です。安全マージンとして2〜3GB程度を見込むと、最低でも6GB〜8GBのVRAMが必要という計算になります。

一般的なモデルサイズの目安(4ビット量子化時)は以下の通りです。

  • 8Bクラス: 約5~6GB → 8GB VRAM推奨
  • 14Bクラス: 約9~10GB → 12GB/16GB VRAM推奨
  • 70Bクラス: 約40~42GB → 48GB VRAM (24GB×2)推奨

コンテキスト長(Context Window)によるメモリ消費の増加

上記の計算は「モデルを読み込むだけ」の容量です。実際には、長い文章を読ませたり、長い会話履歴を保持したりすると、KV Cacheと呼ばれる一時データがVRAMを消費します。

読み込ませる文章量(トークン数)が増えると、このKV Cacheのサイズは肥大化します。特に、社内文書を検索して回答させるようなシステム(RAG)で大量のドキュメントを読み込ませる場合、モデル本体よりもKV Cacheの方がメモリを消費することさえあります。

Ollamaでは、デフォルトのコンテキスト長は2048に設定されていますが、これを8192などに増やす場合は、VRAMに数GB単位の余裕を持たせる必要があります。VRAMが足りなくなると、Ollamaは自動的にコンテキスト長を切り詰めるか、エラーを出して停止します。

マルチGPU環境でのOllamaの挙動

「24GBのGPUが買えないので、12GBを2枚挿して24GBとして使いたい」というニーズは多いです。OllamaはマルチGPUに対応しており、自動的にモデルを複数のGPUに分割して読み込みます。

ただし、注意点があります。

  1. 通信の帯域: 2枚のGPU間で通信が発生するため、マザーボードの接続規格が重要です。十分な太さの経路(x16レーンなど)で接続されていない場合、通信がボトルネックになり速度が出ません。
  2. VRAMのオーバーヘッド: 分割管理のため、単体で使うよりも若干のメモリを余分に消費します。

コストパフォーマンスを考えるなら、コンシューマー向けのハイエンドGPU(24GB搭載モデルなど)を検討するのが、小規模な環境では現実的な解決策となることが多いです。

再現性を担保するDockerによる構築とGPUパススルー設定

再現性を担保するDockerによる構築とGPUパススルー設定 - Section Image

サーバーへの直接インストールは、他のシステムへの影響や環境を汚してしまうリスクがあります。バージョンの競合などで「昨日まで動いていたのに動かなくなった」という事態を防ぐため、Dockerコンテナ(独立した仮想環境)での運用を強く推奨します。

NVIDIA Container Toolkitの完全セットアップ

DockerコンテナからホストマシンのGPUを利用するには、単にDockerを入れるだけでは不十分です。NVIDIA Container Toolkitの導入が必須となります。

Ubuntu環境を例にすると、以下の手順が標準的です。

  1. NVIDIAドライバーのインストール
  2. Docker Engineのインストール
  3. NVIDIA Container Toolkitのインストールと設定

特に忘れがちなのが、Toolkitインストール後のDockerの再起動です。正しく設定されているかは、以下のコマンドで確認できます。

docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi

これでコンテナ内からGPU情報が見えれば成功です。

公式イメージ vs カスタムDockerfile

Ollamaは公式のDockerイメージを提供しています。基本的にはこれを使えば良いですが、GPUを利用するための起動オプションが重要です。

docker-compose.yml の構成例:

version: '3.8'
services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ./ollama_data:/root/.ollama  # モデルデータの永続化
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all             # 全GPUを使用
              capabilities: [gpu]
    environment:
      - OLLAMA_KEEP_ALIVE=5m         # モデルのメモリ常駐時間
      - OLLAMA_HOST=0.0.0.0          # 外部アクセス許可
    restart: always

環境変数によるリソース制限と制御

上記のファイルにも登場しましたが、環境変数の設定が運用の鍵を握ります。

  • OLLAMA_KEEP_ALIVE: デフォルトでは、リクエストがない状態が5分続くとモデルがVRAMから降ろされます。頻繁に利用する社内ボットの場合、再読み込みの遅延(数秒〜数十秒)がストレスになるため、-1(無期限)や1h(1時間)などに設定変更することを検討します。
  • OLLAMA_MAX_LOADED_MODELS: 同時にメモリに展開するモデルの数を制限します。VRAM容量に合わせて調整します。
  • OLLAMA_NUM_PARALLEL: 1つのモデルで同時に処理できるリクエスト数です。これを増やすと全体の処理量は上がりますが、メモリ消費も増大します。

推論速度を最大化するチューニングとベンチマーク

再現性を担保するDockerによる構築とGPUパススルー設定 - Section Image 3

環境構築ができたら、次はチューニングです。デフォルト設定と最適化後では、倍以上の性能差が出ることも珍しくありません。実証データに基づいたアプローチが重要です。

num_gpuパラメータの最適値探索

API経由で推論をリクエストする際、num_gpuパラメータを指定できます。これは「GPUに任せるレイヤー数」を指定するものです。

通常はOllamaが自動判定しますが、明示的に最大値を指定することで、判定ミスによるCPUへの意図しないオフロードを防ぐことができます。モデルの総レイヤー数を確認し、その数値を指定します。

並列リクエスト処理(Parallelism)の設定

社内で複数人が同時にチャットを使う場合、OLLAMA_NUM_PARALLELの設定が効いてきます。デフォルトは1(順番に処理)になっていることが多いです。

これを24にすると、複数のリクエストをまとめてGPUに投げることができます。個々の応答時間は若干伸びる可能性がありますが、システム全体としての処理効率は向上します。

ただし、並列数を増やすと、その分だけ一時メモリ(KV Cache)領域が必要になります。「並列数 × コンテキスト長」分のメモリが確保できるか、事前の計算が必要です。

ollama-benchmarkを用いた性能検証

設定変更の効果を測定するには、感覚ではなく数値で判断しましょう。測定すべき指標は2つです。

  1. Prompt Processing (PP): ユーザーの入力を読み込む速度。
  2. Token Generation (TG): 回答を生成する速度。

特にTGが重要です。人間が読む速度を考えると、最低でも20〜30 tokens/secは欲しいところです。これが10を下回ると「遅い」と感じます。

公開されているベンチマークツールなどを活用し、異なる量子化レベルやコンテキスト長での速度変化をグラフ化して、最適なバランスポイントを見つけましょう。

安定稼働のための監視とトラブルシューティング

最後に、運用フェーズでの守りについて解説します。AIシステムはエラーを出さずに「静かに止まる」ことが多いシステムです。

nvidia-smi / nvtop で見るべき指標

Linuxサーバーで watch -n 1 nvidia-smi コマンドを実行すると、GPUの状態をリアルタイム監視できます。

  • GPU-Util: GPUの使用率。推論中はここが100%近くに張り付くのが健全です。逆に低い場合はCPUがボトルネックになっているか、データ転送待ちが発生しています。
  • Memory-Usage: VRAM使用量。これが上限ギリギリの場合、メモリ不足エラーのリスクが高いです。理想的には1〜2GBの余力を残す運用が安全です。

より視覚的に分かりやすいツールとして nvtop もおすすめです。プロセスごとのGPU使用率がグラフで表示されます。

「応答なし」時のログ解析とリカバリ

Ollamaが応答しなくなった場合、まずはDockerコンテナのログを確認します。

docker logs ollama --tail 100

よくあるエラーメッセージと対策:

  • "CUDA error: out of memory": VRAM不足です。読み込ませる文章量を減らすか、より小さく圧縮されたモデルに変更してください。
  • "llama_print_timings: ...": 正常終了のログですが、ここに生成速度が記録されています。極端に遅い場合はCPUオフロードを疑ってください。
  • "Connection refused": Ollamaのプログラム自体が落ちています。Dockerの自動復帰設定を入れておけば再起動しますが、頻発する場合はハードウェアの熱暴走や電源容量不足も疑う必要があります。

Ollama APIのエラーハンドリング

チャット画面などのアプリケーション側では、Ollamaからの応答に対して適切なタイムアウト(待ち時間の打ち切り)設定を行うことが重要です。長い推論には時間がかかるため、デフォルトの短い設定のままだと、回答生成中に通信が切断されてしまいます。

少なくとも300秒(5分)程度のタイムアウトを設定し、少しずつ回答を表示するストリーミング受信を利用することで、ユーザーに「考え中」であることを分かりやすく伝える設計を心がけましょう。

まとめ

OllamaによるローカルLLM環境の構築は、単なるインストール作業ではありません。それは、ハードウェアの物理的制約の中で、ソフトウェアの要求リソースを最適化するパズルを解くようなものです。

  1. 仕組みを知る: レイヤーの分割と量子化の関係を論理的に理解する。
  2. 計算する: モデルサイズとコンテキスト長から、必要なVRAMを算出する。
  3. 固定する: Dockerと環境変数で、リソース配分を明示的に定義する。
  4. 測る: ベンチマークを取り、実用的な速度が出ているか実証データで検証する。

これらのステップを踏むことで、Ollamaは「個人の実験ツール」から「企業の頼れるインフラ」へと進化します。

もし、自社のハードウェア構成でどのモデルが最適か判断がつかない、あるいは既存の環境でパフォーマンスが出ずに困っているという場合は、専門家に相談することをおすすめします。現状の構成を診断し、ボトルネックを解消するための具体的なアーキテクチャ設計を行うことで、セキュアで高速なプライベートAI環境を構築できるでしょう。

OllamaによるローカルLLM基盤構築:VRAM管理の仕組みとDockerを用いたGPU最適化の完全設計 - Conclusion Image

コメント

コメントは1週間で消えます
コメントを読み込み中...