OctoAIとDockerでマルチモーダルなGenAIアプリを構築

この記事は、OctoAIの共同創設者兼DevRel責任者であるThierry Moreau氏によって寄稿されました。

ジェネレーティブAIモデルは、GPT3のような画期的なモデルで、過去1年間で計り知れない可能性を示してきました。5、 DALL-Eなど。 特に、オープンソースの基礎モデルは、クローズドソースの代替モデルと比較して、カスタマイズ可能で費用対効果が高く、透明性が高い開発者やエンタープライズユーザーの間で人気を博しています。

この記事では、オープンソースの基本モデルを、テキストだけで画像を操作して驚くほど良い結果を得ることができる合理化された画像変換パイプラインに構成する方法について説明します。

バナードッカーとオクトムルは、クリエイティブなジェネレーティブAIアプリを構築するための強力なデュオです

このアプローチにより、企業ロゴの楽しいバージョンを作成したり、子供の絵に命を吹き込んだり、製品写真を充実させたり、リビングルームを改造したりすることもできます(図 1)。

白鯨のロゴ、子供の絵、カクテルグラス、部屋のデザインなど、サンプル画像の変換を示すマルチパート図。
図 1: 左から右へ:クリエイティブな企業ロゴの生成、子供の絵に命を吹き込む、商業写真の充実、リビングルームのリフォームなど、画像変換の例

かなりクールでしょ? 舞台裏では多くのことを行う必要があり、これらの結果を自分で再現する方法を順を追って説明します。 マルチモーダルなGenAIパイプラインを OctoShop と呼ぶのは、人気の画像編集ソフトウェアにちなんでです。

いくつかの基本的なGenAIモデルをつなぎ合わせたいと思いませんか? これを可能にするテクノロジーについて詳しく見ていきましょう。

アーキテクチャの概要

これから構築するマルチモーダルパイプラインを構成するオープンソースの基盤となるGenAIモデルについて、さらに詳しく見ていきましょう。

今後は、「マルチモーダルなGenAIモデルパイプライン」ではなく、「モデルカクテルという用語を使用します。テキストと画像は、GenAIモデルがデータを消費して生成するデータモダリティの例ですが、この概念はオーディオとビデオにも拡張できます(図 2)。

カクテル(または必要に応じてモクテル)を作るのに例えると、材料を混ぜる必要がありますが、材料を組み立てると、個々の部分の合計よりも大きくなります。

genaiワークフローのテキスト図で、画像からテキスト、テキストからテキスト、テキストから画像へのオプションを示しています。
図 2: マルチモーダルなGenAIワークフロー — このパイプラインは、画像とテキストを取得することで、テキストプロンプトに従って入力画像を変換します。

例えば、私のお気に入りのカクテルであるネグローニを例に挙げてみましょう。 準備は簡単です。ジン、ベルモット、カンパリを等量必要です。 同様に、OctoShopモデルカクテルは、画像生成(SDXL)、テキスト生成(Mistral-7B)、カスタム画像からテキスト生成(CLIPインテロゲーター)モデルの3つの材料を使用します。 

プロセスは次のとおりです。 

  • CLIP Interrogatorは画像を取り込み、テキストによる説明を生成します(例:「背中に容器を乗せたクジラ」)。
  • LLMモデルであるMistral-7Bは、ユーザープロンプト(例:「画像を空間に設定」)に基づいて、より豊富なテキストの説明を生成します。 その結果、LLMは説明文をユーザーのプロンプトに合ったより豊かなものに変換します(たとえば、「広大な宇宙で、雄大なクジラは背中にコンテナを背負っています」)。
  • 最後に、SDXLモデルを使用して、LLMモデルによって変換されたテキストの説明に基づいて、AIが生成した最終的な画像を生成します。 また、 SDXL スタイルと ControlNet を利用して、スタイルとフレーミング/遠近法の観点から画像の出力をより適切に制御します。

前提 条件

カクテルを作るための前提条件を見ていきましょう。

必要なものは次のとおりです。

  • OctoAIの 画像生成(SDXL)、テキスト生成(Mistral-7B)、およびコンピューティングソリューション(CLIP Interrogator)を使用するには、OctoAIアカウントにサインアップしてください。 すでに別のコンピューティング サービスを使用している場合は、代わりにそちらを自由に使用してください。
  • Jupyter Notebook を実行して、GenAI モデルの適切な組み合わせを作成します。 ここは実験とミキシングのための場所なので、これがあなたのカクテルシェーカーになります。 ノートブックの実行と配布を容易にするために、 Google Colab を使用します。
  • 最後に、モデルカクテルを Streamlitアプリとしてデプロイします。 アプリを構築し、フロントエンドを装飾することは、五感を高めるためのカクテル(グラス、氷、付け合わせの選択など)のプレゼンテーションと考えてください。

OctoAIを使い始める

まだ行っていない場合は、 octoai.cloud にアクセスしてアカウントを作成してください。 初回サインアップ時に10 ドルのクレジットを受け取ることができますが、ここで独自のワークフローを試すには十分です。

はじめに」ページの指示 に従って、OctoAI APIトークンを取得します — これにより、OctoAI APIを使用するたびに認証を受けることができます。 

ノートブックのチュートリアル

Colab では Jupyter Notebook を作成し、モデルカクテルを構成するさまざまなモデルの使用方法を学習できるようにしました。従う手順は次のとおりです。 

1. ノートブックを起動する

まず、次の Colab ノートブックを起動します。 

ランタイムタイプを変更したり、GPUやTPUアクセラレータに頼ったりする必要はなく、AIの重労働はすべてOctoAIエンドポイントで行われるため、ここで必要なのはCPUだけです。

2. OctoAI SDKのセットアップ

OctoAI SDKのインストールから始めましょう。 SDK を使用して、SDXL や Mistral-7B など、使用しているさまざまなオープン ソースの基本モデルを呼び出します。 以下から pipインストールできます。

# Install the OctoAI SDK
!pip install octoai-sdk

場合によっては、ランタイムで以前にインポートされたpipパッケージに関するメッセージが表示され、エラーが発生することがあります。 その場合は、下部にある [セッションの再起動] ボタンを選択すると、パッケージのバージョン管理の問題が解決されます。 この後、OctoAI SDKをpip-installするセルを問題なく再実行できるはずです。

3. SDXLで画像を生成する

まず、画像生成ソリューション API を使用して SDXL で画像を生成する方法を学習します。 以下のコードで各パラメーターが何を行うかについては、OctoAI の ImageGenerator クライアントを確認してください。

特に、 ImageGenerator API は、画像を生成するためにいくつかの引数を取ります。

  • エンジン:SDXL、SD1などの安定した拡散モデルのバージョンから選択できます。5、およびSSD。
  • プロンプト: 生成するイメージを記述します。
  • ネガティブプロンプト:最終画像で避けたい特性を説明します。
  • 幅、高さ:出力画像の解像度。
  • 画像数: 一度に生成する画像の数。
  • サンプラー: イメージのノイズ除去に使用するサンプリング方法を指定します。 このプロセスに慣れていない場合は、 この記事 で包括的な概要を説明します。
  • ステップ数:ノイズ除去ステップの数 — ステップ数が多いほど品質は高くなりますが、一般的に 30 を超えると収穫逓減につながります。
  • Cfgスケール:画像の説明にどれだけ忠実に従うか — 通常は 7〜12程度にとどまります。
  • 絞り込み条件を使用: 画像の出力品質を向上させる SDXL 絞り込み条件モデルを適用するかどうか。
  • シード: 画像生成の再現性を制御できるパラメータです(安定した入力パラメータが与えられた場合、常に同じ画像を取得するには、正の値に設定します)。

ステップ数、画像数、使用するサンプラーなどの画像生成パラメーターを微調整すると、画像の生成に必要な GPU コンピューティングの量に影響することに注意してください。 GPU サイクルを増やすと、イメージ生成の 価格に影響します 。 

以下は、単純なパラメーターを使用した例です。

# To use OctoAI, we'll need to set up OctoAI to use it
from octoai.clients.image_gen import Engine, ImageGenerator


# Now let's use the OctoAI Image Generation API to generate
# an image of a whale with a container on its back to recreate
# the moby logo
image_gen = ImageGenerator(token=OCTOAI_API_TOKEN)
image_gen_response = image_gen.generate(
 engine=Engine.SDXL,
 prompt="a whale with a container on its back",
 negative_prompt="blurry photo, distortion, low-res, poor quality",
 width=1024,
 height=1024,
 num_images=1,
 sampler="DPM_PLUS_PLUS_2M_KARRAS",
 steps=20,
 cfg_scale=7.5,
 use_refiner=True,
 seed=1
)
images = image_gen_response.images


# Display generated image from OctoAI
for i, image in enumerate(images):
 pil_image = image.to_pil()
 display(pil_image)

パラメータを自由に試して、結果の画像に何が起こるかを確認してください。 ここでは、Docker のロゴを説明するための簡単なプロンプトとして、「背中にコンテナを載せたクジラ」と表示しました。 また、探している画像のスタイルを生成するのに役立つ標準の否定的なプロンプトも追加しました。 図 3 に出力を示します。

背中に容器を乗せたクジラの白黒イラスト。
図 3: SDXLで生成された、背中にコンテナを載せたクジラの画像。

4. ControlNetで画像出力を制御

SDXL でできることの 1 つは、AI が生成した画像の構成を制御することです。 たとえば、特定の人物のポーズを指定したり、特定の写真の構図や遠近法を制御したりできます。 

Moby(Dockerのマスコット)を使った実験では、クジラとコンテナの同じ形、被写体の向き、サイズなど、元のロゴに簡単に重ね合わせることができるAI生成画像を取得したいと考えています。 

ここで、ControlNetが役に立ちます: ControlNet は、制御画像を入力として供給することで、画像の生成を制限できます。 この例では、Moby ロゴの画像をコントロール入力としてフィードします。

ImageGenerator API で使用される以下のパラメーターを調整することで、SDXL 画像の生成を Moby のコントロール画像で制約しています。その制御画像は、深度推定モデルを使用して深度マップに変換され、ControlNetに供給されるため、SDXL画像の生成が制限されます。

# Set the engine to controlnet SDXL
 engine="controlnet-sdxl",
 # Select depth controlnet which uses a depth map to apply
 # constraints to SDXL
 controlnet="depth_sdxl",
 # Set the conditioning scale anywhere between 0 and 1, try different
 # values to see what they do!
 controlnet_conditioning_scale=0.3,
 # Pass in the base64 encoded string of the moby logo image
 controlnet_image=image_to_base64(moby_image),

これで、結果は Moby のアウトラインとより密接に一致したように見えます (図 4)。 これがControlNetの力です。 パラメータを変化 controlnet_conditioning_scale させることで強度を調整できます。 このようにして、出力画像をMobyのコントロール画像と多かれ少なかれ忠実に一致させることができます。

左にシンプルな白鯨のマスコット、右に背中にいくつかの容器を乗せたクジラの絵の2部構成の画像。
図 4: 左:Mobyのロゴは、ControlNetのコントロールイメージとして使用されています。 右:SDXLで生成された画像は、前の例よりもコントロール画像によく似ています。

5. SDXLスタイルのプリセットで画像出力を制御

SDXLスタイルでカスタマイズのレイヤーを追加しましょう。 ここでは、3D Model スタイルプリセットを使用します(図 5)。舞台裏では、これらの スタイル プリセットによって、 SDXL モデルが取り込む肯定的および否定的なプロンプトにキーワードが追加されています。

ベース、 3dモデル、抽象、エイリアン、アニメなどのスタイルプリセットオプションのスクリーンショット
図 5: OctoAI Image Generation Solution UIでは、さまざまなスタイルを試すことができ、 100 種類以上から選択でき、それぞれが独自の感触と美学を提供します。

図 6 は、 ImageGenerator API でこの 1 つのパラメーターを設定すると、AI が生成した Moby の画像がどのように変換されるかを示しています。 さあ、もっと多くのスタイルを試してみてください。インスピレーションを得るための ギャラリー を作成しました。

赤と白の容器を背中に乗せたクジラの 3dレンダリングを示すAI生成画像。
図 6: SDXL で生成された Moby の画像に「3D Model」スタイルのプリセットが適用されています。

6. Mistral-7B LLMで画像を操作する

ここまでは、テキストから画像への生成を行うSDXLに依存してきました。 ControlNetをミックスに追加して、コンポジションの制約としてコントロール画像を適用しました。 

次に、LLMをミックスに重ねて、元の画像プロンプトを「変換プロンプト」に基づいてクリエイティブでリッチなテキストの説明に変換します。 

基本的には、LLMを使用してプロンプトを自動的に改善します。 これにより、OctoShopモデルのカクテルパイプラインでテキストを使用して画像操作を実行できます。

  • 白鯨のロゴを撮る:宇宙で超リアルな写真に設定します。
  • 子供が描いた絵を、ファンタジーの世界で生き生きとさせましょう。
  • カクテルの写真を撮る: イタリアのビーチにカクテルをセットします。
  • リビングルームの写真を撮る: デザイナーズハウスの演出されたリビングルームに変身させます。

このテキストからテキストへの変換を実現するには、次のように LLM ユーザー プロンプトを使用します。 これにより、白鯨の元のテキストの記述は、広大な空間という新しい設定に設定されます。

'''
Human: set the image description into space: “a whale with a container on its back”
AI: '''

LLMシステムプロンプトは、LLM応答が簡潔で、最大で1文の長さになるように設定されています。 長くすることもできますが、SDXL によって使用されるプロンプトには 77トークン コンテキストの制限があることに注意してください。

テキスト生成Python SDKと、テキスト生成に使用されるチャット補完APIの詳細については、以下を参照してください。

  • モデル: Mixtral、Mistral、Llama2、Code Llama などの基本的なオープンソース モデルから選択できます (より多くのオープンソース モデルがリリースされるにつれて、選択肢が増えます)。
  • メッセージ: 完了のコンテキストとして使用するメッセージ (システムおよびユーザー) のリストが含まれます。
  • Max tokens: 出力トークンにハード制限を適用します (これにより、文の途中で補完応答がカットされる可能性があります)。
  • 温度:回答の創造性をコントロールできます:温度が高いほど、可能性の低いトークンを選択できます。

モデル、インプット、アウトプットトークンの選択は、 OctoAIの価格に影響します。 この例では、 Mistral-7B LLMを使用していますが、これは優れたオープンソースのLLMモデルであり、パラメータサイズが小さいため、非常にパンチが効いています。 

Mistral-7B LLMを呼び出すために使用されるコードを見てみましょう。

# Let's go ahead and start with the original prompt that we used in our
# image generation examples.
image_desc = "a whale with a container on its back"


# Let's then prepare our LLM prompt to manipulate our image
llm_prompt = '''
Human: set the image description into space: {}
AI: '''.format(image_desc)


# Now let's use an LLM to transform this craft clay rendition
# of Moby into a fun scify universe
from octoai.client import Client


client = Client(OCTOAI_API_TOKEN)
completion = client.chat.completions.create(
 messages=[
   {
     "role": "system",
     "content": "You are a helpful assistant. Keep your responses short and limited to one sentence."
   },
   {
     "role": "user",
     "content": llm_prompt
   }
 ],
 model="mistral-7b-instruct-fp16",
 max_tokens=128,
 temperature=0.01
)


# Print the message we get back from the LLM
llm_image_desc = completion.choices[0].message.content
print(llm_image_desc)

出力は次のとおりです。

テキスト出力: 広大な宇宙空間で、雄大なクジラがコンテナを背負っています。

私たちのLLMは、宇宙を旅するモビーの短いながらも想像力に富んだ説明を作成しました。 図 7 は、このLLMで生成されたテキスト記述をSDXLにフィードしたときの結果を示しています。

赤い容器を背負ったクジラが海の上空をホバリングする画像をAIが生成しました。
図 7: SDXL で生成された Moby の画像では、LLM を使用して空間にシーンを設定し、テキスト プロンプトを充実させました。

この画像は素晴らしいです。 宇宙の広大さを感じることができます。 LLMの力とSDXLの柔軟性により、画像の作成と操作を新たな高みに引き上げることができます。 そして素晴らしいのは、これらの画像を操作するために必要なのはテキストだけだということです。残りの作業は GenAI モデルが行います。

7. AIベースの画像ラベリングでワークフローを自動化

これまでの画像変換パイプラインでは、OctoShopモデルカクテルへの入力画像に手動でラベルを付ける必要がありました。 白鯨の画像を渡すだけでなく、その画像の説明をテキストで提供する必要がありました。

ありがたいことに、GenAIモデルを使用してテキストのラベル付けタスクを実行できます。このタスクは、SDXL が行うことの逆、つまり画像を取り込み、出力としてテキストを生成するものと考えてください。

開始するには、エンドポイントのどこかで実行される CLIP Interrogator モデルが必要です。 OctoAIでCLIP Interrogatorモデルのエンドポイントを取得するには、2つの方法があります。始めたばかりの場合はシンプルなアプローチをお勧めし、モデル エンドポイントをカスタマイズする気になった場合は、より高度なアプローチを使用できます。 たとえば、 最新バージョンの CLIP Interrogator を試してみたい場合があります。

これで、数行のコードで CLIP Interrogator モデルを呼び出すことができます。 ここでは、高速インテロゲーターモードを使用して、ラベルをできるだけ早く生成します。

# Let's go ahead and invoke the CLIP interrogator model


# Note that under a cold start scenario, you may need to wait a minute or two
# to get the result of this inference... Be patient!
output = client.infer(
   endpoint_url=CLIP_ENDPOINT_URL+'/predict',
   inputs={
       "image": image_to_base64(moby_image),
       "mode": "fast"
   }
)


# All labels
clip_labels = output["completion"]["labels"]
print(clip_labels)


# Let's get just the top label
top_label = clip_labels.split(',')[0]
print(top_label)

トップラベルには、Mobyのロゴが次のように説明されています。

白鯨の画像のトップラベルは、背中に容器を乗せたクジラです。

それはかなり的を射ています。 すべての材料を個別にテストしたので、モデルカクテルを組み立てて、興味深いユースケースでテストしましょう。

8. モデルカクテルの組み立て

3つのモデル(CLIPインテロゲーター、Mistral-7B、SDXL)をテストしたので、次の入力を受け取る1つの便利な関数にパッケージ化できます。

  • 出力画像を制御するために使用され、CLIPインテロゲーターモデルによって自動的にラベル付けされる入力画像。
  • 入力画像に適用する変換を記述する変換文字列 (例: "set the image description in space")。
  • 画像に適用する変換とは無関係に、画像の芸術的出力をより適切に制御できるスタイル文字列(たとえば、絵画的なスタイルと映画的なスタイル)。

以下の関数は、上記で紹介したすべてのコードの焼き直しを 1 つの関数に詰め込んだものです。

def genai_transform(image: Image, transformation: str, style: str) -> Image:
 # Step 1: CLIP captioning
 output = client.infer(
   endpoint_url=CLIP_ENDPOINT_URL+'/predict',
   inputs={
     "image": image_to_base64(image),
     "mode": "fast"
   }
 )
 clip_labels = output["completion"]["labels"]
 top_label = clip_labels.split(',')[0]


 # Step 2: LLM transformation
 llm_prompt = '''
 Human: {}: {}
 AI: '''.format(transformation, top_label)
 completion = client.chat.completions.create(
   messages=[
     {
       "role": "system",
       "content": "You are a helpful assistant. Keep your responses short and limited to one sentence."
     },
     {
       "role": "user",
       "content": llm_prompt
     }
   ],
   model="mistral-7b-instruct-fp16",
   max_tokens=128,
   presence_penalty=0,
   temperature=0.1,
   top_p=0.9,
 )
 llm_image_desc = completion.choices[0].message.content


 # Step 3: SDXL+controlnet transformation
 image_gen_response = image_gen.generate(
   engine="controlnet-sdxl",
   controlnet="depth_sdxl",
   controlnet_conditioning_scale=0.4,
   controlnet_image=image_to_base64(image),
   prompt=llm_image_desc,
   negative_prompt="blurry photo, distortion, low-res, poor quality",
   width=1024,
   height=1024,
   num_images=1,
   sampler="DPM_PLUS_PLUS_2M_KARRAS",
   steps=20,
   cfg_scale=7.5,
   use_refiner=True,
   seed=1,
   style_preset=style
 )
 images = image_gen_response.images


 # Display generated image from OctoAI
 pil_image = images[0].to_pil()
 return top_label, llm_image_desc, pil_image

これで、いくつかの画像、プロンプト、スタイルでこれを試すことができます。 

モデル カクテルを Web アプリにパッケージ化する

独自のGenAIカクテルを混ぜたら、それをグラスに注ぎ、比喩的に飾ります。 独自のOctoShop GenAIモデルカクテルをデプロイし、その結果を友人や同僚と共有できる シンプルなStreamlitフロントエンド を構築しました(図 8)。 GitHubで確認できます。

READMEの指示に従って、アプリをローカルにデプロイするか、StreamlitのWebホスティングサービスでホストします。

左にシンプルな白鯨のマスコット、右に青と赤の容器を背負ったクジラが宙に浮かんでいる2部構成の画像。
図 8: Streamlitアプリは、GenAIの魔法のおかげで、画像を宇宙でのリアルなレンダリングに変換します。

どんな素晴らしい画像処理アプリが生まれるのか、楽しみにしています。 OctoAIの Discord サーバーで#built_with_octoチャンネルであなたの作品を共有してください! 

OctoShopをDiscordボットの背後に配置したり、Dockerを使用して独自のモデルコンテナを構築したりする方法を知りたい場合は、 DockerCon で2023 OctoAIが主催する AI / MLワークショップ からそれを行う方法の説明もあります。

OctoAIについて

OctoAIは、GenAIを大規模、効率的、かつ堅牢に実行するためのインフラストラクチャを提供します。 Mixtral、Stable Diffusion XLなどのモデルを提供するためにOctoAIが提供するモデルエンドポイントはすべて、Dockerに依存してモデルをコンテナ化し、大規模なサービスを簡単に提供できるようにします。 

octoai.cloud に行くと、開発者が GenAI 搭載のアプリとパイプラインを本番環境に導入するために構築できる 3 つの補完的なソリューションがあります。 

  • 画像生成ソリューション は、Stable Diffusion XLやSSDなどのオープンソースの基本モデルを中心に構築されたテキストから画像、画像から画像へのタスクを実行するためのエンドポイントとAPIを公開します。
  • テキスト生成ソリューション は、Mixtral/Mistral、Llama2、CodeLlama などのオープン ソースの基本モデルに基づいて構築されたテキスト生成タスクを実行するためのエンドポイントと API を公開します。
  • コンピュートソリューション により、Docker化されたモデルコンテナを有能なOctoAIクラウドエンドポイントにデプロイして管理し、要求の厳しいGenAIニーズに対応できます。 このコンピューティング サービスは、画像生成ソリューションとテキスト生成ソリューションのいずれでも現在すぐに利用できない AI タスクの無限のプログラミング可能性とカスタマイズ可能性を公開することで、画像生成およびテキスト生成ソリューションを補完します。

免責事項

OctoShopは、CLIP InterrogatorとSDXL、Mistral-7Bを基盤として構築されているため、これらのベースモデルに内在する潜在的な危険性を引き継ぐ可能性があります。意図しない、不適切、不快な、または誤った出力を生成する可能性があります。 したがって、このモデルを実際のアプリケーションに展開する前に、注意を払い、包括的な評価を行うことを強くお勧めします。

このGenAIモデルのワークフローは、人物の肖像が保持されないため、人物には機能しません。パイプラインは、シーン、オブジェクト、または動物で最適に機能します。 この問題に対処するためのソリューションとして、Dockerでコンテナ化してOctoAI Computeソリューションにデプロイできるフェイスマッピング技術(フェイススワッピングとも呼ばれます)がありますが、これについては別のブログ記事で取り上げます。

結論

この記事では、Dockerコンテナ化によって実現される移植性とスケーラビリティを備えたテキスト生成、画像生成、コンピューティングソリューションの組み合わせに依存して、GenAIモデルカクテルを構築するための基礎について説明しました。 

このようなGenAIモデルカクテルの構築について詳しく知りたい方は、OctoAIのデモページをご覧いただくか、 Discord で OctoAI に参加して、人々が何を作っているのかをご覧ください。

確認

著者は、この記事のインスピレーションとなった DockerCon AI/ML ワークショップ 2023に貢献した Justin Gage 氏、および Luis Vega 氏、Sameer Farooqui 氏、Pedro Toruella 氏に感謝します。また、このブログ記事で使用した絵を描いてくれたCia Bodin氏と娘のAda氏にも感謝しています。

さらに詳しく