🎉

DockerとDocker Composeを使ったOllamaイメージでのELYZA-JPモデルのローカルデプロイ

こんにちは。エッジテクノロジーの李と申します。これから新たな取り組みとしてZennに執筆活動を始めることにしました。
今回はローカルLLMの一つであるOllamaのご紹介です。

なぜOllamaか?

皆様の会社やご自身がプロジェクトでLLMの活用を検討されている際、データのプライバシー問題、AWSやGCPのようなクラウドサービスプロバイダーのLLMサービスの費用、そしてカスタマイズ性について懸念をお持ちかもしれません。

そこで注目したいのがOllamaです。Ollamaは、ローカル環境で手軽に大規模言語モデル(LLM)を実行できるフレームワークであり、以下のような様々なメリットがあります。これにより、企業や研究者が安心してLLMを導入・実験できる環境を提供します。

  • オフラインでの利用
  • データのプライバシー確保
  • クラウドサービスに依存しないコスト効率の良さ
  • GPUの利用が簡単
  • 研究目的および商用利用が無料
  • Ollama JP 8Bモデルは日本語性能においてGPT-3.5 Turboを上回るとされている
    ※細字はローカルLLMのメリット、太字はOllamaだからこそのメリットについて記述しています

筆者の経験では、ハイスペックではないPC環境でもこのモデルは正常にデプロイ・実行できるため、研究や企業のPoC(概念実証)において大きな可能性を秘めていると感じています。
日本語コミュニティおよびELYZA公式からは、DockerのOllamaイメージを用いたELYZA-JPモデルのデプロイ方法が提供されていないため、本記事ではデプロイからテストまでの詳細な手順をご紹介します。


事前準備

お使いのPCには、DockerDocker Composeが正常にインストールされている必要があります。また、ある程度のメモリ容量(筆者のPCは32GB)が推奨されます。GPUは必須ではありませんが、使用することをお勧めします。

Docker内でGPUアクセラレーションを使用したい場合は、多くの既存のチュートリアル(日本語、英語、中国語)がありますので、本記事では割愛させていただきます。


ローカルデプロイ

本プロジェクトを管理するために、elyza_local_llmといったフォルダを作成することをお勧めします。

まず、ELYZAのHugging Faceのメインページからデプロイしたいモデルを選択します。本記事ではLlama-3-ELYZA-JP-8B-GGUFを使用して解説します。

モデルページのGGUFファイルをローカルにダウンロードします(約5GB)。このファイルをelyza_local_llm内の任意のフォルダ(例: elyza_jp_8B)に配置し、同じフォルダ内にModelfileDockerfileという2つの新しいファイルを作成します。

Modelfileの内容は以下の通りです。

FROM ./Llama-3-ELYZA-JP-8B-q4_k_m.gguf
TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|>

{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>

{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>

{{ .Response }}<|eot_id|>"""
PARAMETER stop "<|start_header_id|>"
PARAMETER stop "<|end_header_id|>"
PARAMETER stop "<|eot_id|>"
PARAMETER stop "<|reserved_special_token"

Dockerfileの内容は以下の通りです。

FROM ollama/ollama:latest AS builder

COPY Llama-3-ELYZA-JP-8B-q4_k_m.gguf Llama-3-ELYZA-JP-8B-q4_k_m.gguf
COPY Modelfile Modelfile

RUN ollama serve & \
    sleep 3 && \
    ollama create elyza:jp8b -f Modelfile

FROM ollama/ollama:latest

COPY --from=builder /root/.ollama /root/.ollama

RUN ollama serve & \
    sleep 3 && \
    ollama run elyza:jp8b \

EXPOSE 11434
CMD ["serve", "elyza:jp8b"]

最後に、プロジェクトのルートフォルダ(elyza_local_llm)に戻り、docker-compose.ymlファイルを作成します。

docker-compose.ymlの内容は以下の通りです。

version: "3.8"

services:
  elyza_service:
    container_name: elyza
    build:
      context: ./elyza_jp_8B
    entrypoint:
      [
        "/bin/bash",
        "-c",
        "ollama serve",
      ]
    environment:
      - OLLAMA_NUM_PARALLEL=4
      - OLLAMA_MAX_LOADED_MODELS=1
    ports:
      - "11434:11434"
    command: ollama serve elyza:jp8b

ちなみに、GPUを使いたい場合のdocker-compose.ymlの内容は以下の通りです。

version: "3.8"

services:
  elyza_service:
    container_name: elyza
    build:
      context: ./elyza_jp_8B
    entrypoint:
      [
        "/bin/bash",
        "-c",
        "ollama serve",
      ]
    environment:
      - OLLAMA_NUM_PARALLEL=4
      - OLLAMA_MAX_LOADED_MODELS=1
    ports:
      - "11434:11434"
    command: ollama serve elyza:jp8b
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

上記の手順に厳密に従うと、ファイル構造は以下のようになります。

elyza_local_llm/
├── elyza_jp_8B/
│   ├── Llama-3-ELYZA-JP-8B-q4_k_m.gguf  # ダウンロードしたGGUFファイル
│   ├── Modelfile
│   └── Dockerfile
└── docker-compose.yml

実行とテスト

ターミナルまたはCMDでプロジェクトフォルダ(elyza_local_llm)に移動し、docker-compose up -dを実行するだけでデプロイは完了です。とても簡単ですね。

テストについては、Postman、Curl、その他HTTPリクエストを送信できるさまざまなツールやライブラリを使用できます。本記事では2つの方法をご紹介します。

方法1:Postman

PostmanなどのHTTPクライアントを使用して、以下のエンドポイントにPOSTリクエストを送信します。

  • URL: http://localhost:11434/api/generate
  • Method: POST
  • Headers:
    • Content-Type: application/json
  • Body (JSON):
    {
        "model": "elyza:jp8b",
        "prompt": "日本の首都はどこですか?",
        "stream": false
    }
    

方法2:Python

PythonでHTTPリクエストを送信するためのコード例です。

import openai

client = openai.OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="api_key"
)

if __name__ == '__main__':
    prompt = "日本の首都はどこですか?"

    conversation = [
        {
            "role": "user",
            "content": prompt,
        }
    ]

    completion = client.chat.completions.create(
        model="elyza:jp8b",
        messages=conversation
    )

    response_text = completion.to_dict()["choices"][0]["message"]['content']
    print(completion)
    print(response_text)

さいごに

エッジテクノロジー株式会社は千葉銀行グループの一員で、ともに働く仲間を募集しています!!
https://edge-tech.co.jp

Discussion