Ollama + LangChainで画像を入力する方法【Gemma3 27B】
はじめに
Gemma3がGoogleからリリースされたようです。
色々な方が評価をしているので、あまりやることはないかなと思っていたのですが、どうやら画像も入力できるよう。
私は、基本的にLangChainを利用しているので、LangChainで画像の読み取りも含めて、Gemma3を動かせたらとおもい、試した内容を記事にします。
また、Gemma3に関しては下記の記事で詳しく説明してくださっています。
準備
Ollamaの導入
まずは、OllamaでGemma3を利用できるようにします。
Ollamaの導入方法などは様々記事があるのでそちらを参照してください。
基本的には、下記の公式のページからインストールをするだけです。
Gemma3を導入
下記にて、様々なモデルパラメータのGemma3が選べます。
今回の記事では、「gemma3:27b」を利用します。
コンソールにて、下記のコマンドを入力してください。
ollama pull gemma3:27b
これで、導入は完了です。
LangChainを利用してOllamaからGemma3を利用
基本的には下記の公式記事を参考にして実装しています。
普通にテキストでの利用
コード
Ollamaが起動していることを確認してください。
その後、下記のコードで実行できます。
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_ollama import ChatOllama
messages = [
("system", "あなたは日本語を話す優秀なアシスタントです。回答には必ず日本語で答えてください。また考える過程も出力してください。"),
("human", "{user_input}")
]
query = ChatPromptTemplate.from_messages(messages)
model = ChatOllama(
model="gemma3:27b",
max_tokens=4096,
temperature=0.2,
top_p=0.9
)
chain = query | model | StrOutputParser()
output = chain.invoke({"user_input": "日本で一番高い山は何ですか?"})
print(output)
ここでは、「日本で一番高い山は何ですか?」と質問をしています。
システムプロンプトは適当です。
ChatOllama
クラスを利用して、起動中のOllamaに保存されているモデルを読み込み、LangChainで読み込むことができます。
あとは、普通のLangChainの書き方でOKです。
ちなみに、LangChainに関しては、下記でも記事を書いております。
実行結果
下記が実行結果です。
はい、承知いたしました。日本で一番高い山についてお答えします。
考える過程:
日本で一番高い山を尋ねられているので、日本の山々の中で標高が最も高いものを特定する必要があります。小学校で学習する地理の知識から、富士山が日本で最も高い山であるとすぐに思い浮かびます。念のため、他の山と比較して確認してみましたが、やはり富士山が一番高いことがわかりました。
回答:
日本で一番高い山は、富士山です。標高は3,776.24mです。
なんか、「考える過程」が面白いですね。無理やり捻り出したみたいなw
画像を読み込む方法
読み込む画像
下記の画像を読み込もうと思います。AIで生成した画像です。
上記の画像をinputs/image.png
のパスに格納します。
コード
下記のコードで実行ができます。
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_ollama import ChatOllama
import base64
from io import BytesIO
from PIL import Image
def convert_to_base64(pil_image):
"""
Convert PIL images to Base64 encoded strings
:param pil_image: PIL image
:return: Base64 string
"""
buffered = BytesIO()
pil_image.save(buffered, format="PNG") # You can change the format if needed
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return img_str
def prompt_func(data):
user_input = data["user_input"]
image = data["image"]
message = [
SystemMessage(content= "あなたは日本語を話す優秀なアシスタントです。回答には必ず日本語で答えてください。また考える過程も出力してください。"),
HumanMessage(
content=[
{
"type": "text",
"text": f"{user_input}"
},
{
'type': 'image_url',
'image_url': f'data:image/png;base64,{image}',
},
]
)
]
return message
model = ChatOllama(
model="gemma3:27b",
max_tokens=4096,
temperature=0.2,
top_p=0.9
)
chain = prompt_func | model | StrOutputParser()
file_path = "inputs/images.png"
pil_image = Image.open(file_path)
image_b64 = convert_to_base64(pil_image)
#下記でも実行可能
#output = chain.invoke(
# {"user_input": "画像には何が映っているか説明してください。", "image": image_b64}
#)
#テキストが少しずつ生成されるようにするために、streamを使う
for chunk in chain.stream({"user_input": "画像に何が映っているか説明してください。", "image": image_b64}):
print(chunk, end="", flush=True)
上記では、一旦画像をbase64に変換した上で、それをモデルに入力する形で画像を読み込ませています。
基本的にモデルがgeminiなど他のものになっても、同じように処理可能です。
(モデルが変わってもコードを変える必要がないところがLangChainのいいところです)
また、関数はchainで繋げる際に、他に繋いだものがRannableである場合、勝手に関数もRannableに変換して繋げてくれます。便利ですね。
ちなみに丁寧に書くと下記です。RunnableLambda
でラップするとRunnable化できます。
chain = RunnableLambda(prompt_func) | model | StrOutputParser()
また、出力にちょっと時間かかるなと思ったので、stream出力にしています。
for chunk in chain.stream({"user_input": "画像に何が映っているか説明してください。", "image": image_b64}):
print(chunk, end="", flush=True)
モデルには{"user_input": "画像に何が映っているか説明してください。", "image": image_b64}
(ユーザの質問文と画像のbase64)が入力として与えられ、chainの最初であるprompt_func
で処理されてプロンプトを完成させ、それがモデルに入力され、出力が1tokenずつ出力されるようになっています。
実行結果
下記が実行結果です。
はい、承知いたしました。画像に映っているものを説明します。
思考過程:
- 全体的な印象: 画像は、窓辺に立つ若い女性のポートレート写真です。
- 人物: 女性は、長い茶色の髪で、白いセーターを着ています。顔立ちは美しく、少し物憂げな表情をしています。
- 背景: 背景は、白いカーテンと窓枠で、光が差し込んでいます。
- 雰囲気: 全体的に、柔らかく、穏やかな雰囲気です。
説明:
画像には、窓辺に立つ若い女性が写っています。彼女は長い茶色の髪を持ち、白いセーターを着ています。少し物憂げな表情をしており、柔らかい光が彼女を照らしています。背景には白いカーテンと窓枠が見え、穏やかな雰囲気を醸し出しています。
ちゃんと、画像の特徴を踏まえて回答ができています。
まとめ
Ollamaに限らず、LangChainを利用すると、上記のような形で画像を読み込ませることができます。
Github
おすすめ書籍
LangChainとLangGraphによるRAG・AIエージェント[実践]入門
ChatGPT/LangChainによるチャットシステム構築[実践]入門
今回は、さまざまなモデルを統一的に利用するために、LangChainを利用しています。
langchainに関しては、こちらの書籍を読めば大体のことはできるようになりますので、おすすめです。
Discussion