Skills MCP Model 博客 提交 Skills

DeepSeek マルチモーダルチュートリアル

DeepSeek VL2 視覚言語モデルと Janus マルチモーダル理解および画像生成。環境構築から完全な推論まで、OCR、グラフ分析、視覚的質問応答、テキストから画像への生成など、すべてのコア機能を網羅します。

学習を始める

マルチモーダルモデル概要

DeepSeek は2つのマルチモーダルモデルを発表しました:VL2 は視覚言語理解に特化し、Janus はマルチモーダル理解と画像生成の両方をサポートします。両者はアーキテクチャ設計、能力の重点、適用シナリオにおいて異なります。

マルチモーダルモデル概要 — VL2 と Janus

VL2 と Janus の核心的な違いを理解することは、適切なモデルを選択する前提です。以下では、アーキテクチャ、能力、適用シナリオなどの観点から包括的な比較を行います。

VL2 と Janus の位置づけ比較

比較項目 DeepSeek VL2 DeepSeek Janus
中核能力 視覚言語理解(単方向) マルチモーダル理解 + 画像生成(双方向)
アーキテクチャ設計 視覚エンコーダ + 言語モデル投影 統一自己回帰 Transformer
画像理解 プロフェッショナル級、動的解像度 対応、固定 384x384 解像度
画像生成 非対応 対応、テキストから画像生成
OCR 能力 非常に強力、動的解像度による強化 基本的な対応
モデル規模 Tiny / Small / Full の 3 段階 Janus-Pro-7B(7B パラメータ)
典型的なシナリオ OCR 文書認識、グラフ分析、視覚的質問応答 画像キャプション、マルチモーダル対話、テキストからの画像生成

アーキテクチャの違いの詳細

DeepSeek VL2 は、古典的な視覚エンコーダ + 大規模言語モデルのアーキテクチャを採用しています。SigLIP が視覚エンコーダとして画像特徴を抽出し、MLP 投影層を介して言語モデルの埋め込み空間にマッピングし、最後に DeepSeekMoE 言語モデルがテキスト応答を生成します。VL2 は動的解像度をサポートしており、高解像度画像を複数のタイルに分割して個別にエンコードし、全体のサムネイルとともにモデルに入力することで、OCR と細かい視覚理解を大幅に向上させます。

DeepSeek Janus は、統一された Transformer 自己回帰アーキテクチャを採用し、画像理解と生成を単一のフレームワークに統合しています。理解パスでは SigLIP エンコーダを使用して視覚特徴を抽出し、LLM に適応させます。生成パスでは VQ トークナイザを使用して画像を離散トークン系列に変換し、LLM が自己回帰的に生成します。Janus-Pro-7B は Janus をさらに最適化し、マルチモーダル理解性能と画像生成品質を向上させています。

選定の推奨事項

  • 高精度な OCR と文書理解が必要な場合:VL2 を選択。動的解像度メカニズムにより、文字認識に優れています
  • 画像生成機能が必要な場合:Janus を選択。テキストから画像生成をサポートし、384x384 解像度です
  • 視覚的質問応答とグラフ分析が必要な場合:VL2 が第一選択。視覚理解の精度が高い
  • 統一されたマルチモーダル対話体験が必要な場合:Janus は理解と生成の切り替えがより自然
  • リソースが限られている場合:VL2 Tiny(3B)または VL2 Small(16B)はコンシューマー向け GPU で実行可能

DeepSeek VL2環境構築

依存関係のインストール、モデルのダウンロード、環境設定を行います。VL2はTiny/Small/Fullの3つのモデルサイズを提供しており、ハードウェア構成に応じて柔軟に選択できます。

VL2モデルサイズ比較

モデルバージョン パラメータ数 ビジョンエンコーダ GPUメモリ要件 ユースケース
VL2-Tiny 3B SigLIP-SO400M 約8GB 迅速なプロトタイピング、モバイル展開
VL2-Small 16B SigLIP-SO400M 約40GB 研究、高精度OCR
VL2-Full 27B(MoE) SigLIP-SO400M 約80GB プロフェッショナル向け視覚理解、複雑な文書分析

依存関係のインストール

# 仮想環境の作成 python -m venv vl2-env vl2-env\Scripts\activate # PyTorchのインストール(CUDAバージョンに応じて選択) pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # コア依存関係のインストール pip install transformers accelerate sentencepiece pip install pillow numpy opencv-python # モデルダウンロード用のhuggingface_hubのインストール pip install huggingface_hub # インストールの確認 python -c "import torch; import transformers; print('VL2環境準備完了')"

Hugging Faceからのモデルダウンロード

from huggingface_hub import snapshot_download # VL2-Tinyのダウンロード(初心者向け推奨) snapshot_download( repo_id="deepseek-ai/deepseek-vl2-tiny", local_dir="./models/deepseek-vl2-tiny", local_dir_use_symlinks=False, resume_download=True, ) # VL2-Smallのダウンロード(より多くのGPUメモリが必要) # snapshot_download( # repo_id="deepseek-ai/deepseek-vl2-small", # local_dir="./models/deepseek-vl2-small", # local_dir_use_symlinks=False, # resume_download=True, # ) print("モデルのダウンロードが完了しました")

ヒント

ダウンロード速度が遅い場合は、HFミラーを設定できます:export HF_ENDPOINT=https://hf-mirror.com。モデルダウンロードの詳細は、DeepSeekモデルダウンロードガイドをご覧ください。

VL2 画像理解

VL2 は、画像キャプション、視覚的質問応答、OCR テキスト抽出、グラフ分析、視覚的グラウンディングなどの主要機能をサポートしています。以下で各機能のコード実装を示します。

モデルと画像の読み込み

from transformers import AutoModelForCausalLM from deepseek_vl2.models import DeepseekVLV2Processor, DeepseekVLV2ForCausalLM import torch from PIL import Image # モデルとプロセッサの読み込み model_path = "./models/deepseek-vl2-tiny" vl2_processor = DeepseekVLV2Processor.from_pretrained(model_path) vl2_model = DeepseekVLV2ForCausalLM.from_pretrained( model_path, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) # 画像の読み込み image = Image.open("images/document.jpg").convert("RGB") print(f"画像サイズ: {image.size}")

視覚的質問応答(VQA)

# 単一画像の視覚的質問応答 conversation = [ { "role": "user", "content": [ {"type": "image", "image": "images/photo.jpg"}, {"type": "text", "text": "この写真には何が写っていますか?詳しく説明してください。"}, ], } ] # 入力の準備 prepare_inputs = vl2_processor( conversations=conversation, images=[image], force_batchify=True, system_prompt="", ).to(vl2_model.device) # 推論 with torch.no_grad(): inputs_embeds = vl2_model.prepare_inputs_embeds(**prepare_inputs) outputs = vl2_model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, temperature=0.0, ) answer = vl2_processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) print("回答:", answer)

OCR テキスト抽出

# OCR テキスト抽出 - VL2 の主要な強み conversation = [ { "role": "user", "content": [ {"type": "image", "image": "images/document.jpg"}, {"type": "text", "text": "この画像からすべてのテキストを抽出し、元の形式とレイアウトを維持してください。"}, ], } ] prepare_inputs = vl2_processor( conversations=conversation, images=[image], force_batchify=True, system_prompt="", ).to(vl2_model.device) with torch.no_grad(): inputs_embeds = vl2_model.prepare_inputs_embeds(**prepare_inputs) outputs = vl2_model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=1024, do_sample=False, ) ocr_text = vl2_processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) print("OCR 抽出結果:\n", ocr_text)

グラフ理解

# グラフ分析とデータ抽出 conversation = [ { "role": "user", "content": [ {"type": "image", "image": "images/chart.png"}, {"type": "text", "text": "このグラフを分析してください: 1) グラフの種類は何ですか? 2) 横軸と縦軸はそれぞれ何を表していますか? 3) データの傾向はどうですか? 4) 重要な発見は何ですか?"}, ], } ] prepare_inputs = vl2_processor(
conversations=conversation, images=[chart_image], force_batchify=True, system_prompt="", ).to(vl2_model.device) with torch.no_grad(): inputs_embeds = vl2_model.prepare_inputs_embeds(**prepare_inputs) outputs = vl2_model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, ) chart_analysis = vl2_processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) print("グラフ分析:", chart_analysis)

視覚的グラウンディング

# 視覚的グラウンディング - 画像内の特定オブジェクトの位置特定 conversation = [ { "role": "user", "content": [ {"type": "image", "image": "images/street.jpg"}, {"type": "text", "text": "画像内のすべての車の位置を特定し、バウンディングボックス座標で説明してください。"}, ], } ] prepare_inputs = vl2_processor( conversations=conversation, images=[image], force_batchify=True, system_prompt="", ).to(vl2_model.device) with torch.no_grad(): inputs_embeds = vl2_model.prepare_inputs_embeds(**prepare_inputs) outputs = vl2_model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, ) grounding_result = vl2_processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) print("位置特定結果:", grounding_result)

VL2 動的解像度

動的解像度は VL2 の主要な革新の一つです。これにより、モデルは入力画像の実際のサイズに基づいて、画像を複数のタイルに適応的に分割して処理し、高解像度画像の詳細を保持できます。

動的解像度メカニズムの原理

従来の視覚モデルは通常、画像を固定サイズ(例:384x384)にリサイズするため、高解像度画像の文字や詳細が失われます。VL2 の動的解像度メカニズムは、画像を複数のローカルタイル(各タイルはデフォルトで 384x384)に分割し、同時にグローバルサムネイルを保持することで、モデルが全体のレイアウトを理解しつつ、局所的な詳細も捉えられるようにします。

動的解像度の処理フロー:

  • 画像のアスペクト比に基づいて最適な分割プランを計算(例:2x2、3x2、1x3 など)
  • 画像をターゲット解像度にリサイズし、複数のタイルに分割
  • 全体のレイアウト情報を保持するグローバルサムネイルを生成
  • すべてのタイルとサムネイルをそれぞれ視覚エンコーダーに入力
  • エンコードされた視覚特徴を連結し、言語モデルに入力

動的解像度の設定

# VL2 プロセッサーは動的解像度サポートを内蔵 # resolution パラメータで分割モードを制御 # カスタム解像度設定 from deepseek_vl2.models.processing_vlm import VLChatProcessor # 方法1:デフォルトの動的解像度を使用 vl2_processor = DeepseekVLV2Processor.from_pretrained( model_path, resolution="dynamic", # 動的解像度モード ) # 方法2:手動で分割方法を指定 # 候補解像度リストを設定 custom_resolutions = [ (1, 1), # 1x1 = 384x384 (1, 2), # 1x2 = 384x768 (2, 1), # 2x1 = 768x384 (2, 2), # 2x2 = 768x768 (2, 3), # 2x3 = 768x1152 (3, 2), # 3x2 = 1152x768 (3, 3), # 3x3 = 1152x1152 ] # プロセッサーは画像のアスペクト比に基づいて最適な解像度を自動選択 # 推論時は追加設定不要、プロセッサーが自動処理 conversation = [ { "role": "user", "content": [ {"type": "image", "image": "images/high_res_doc.jpg"}, {"type": "text", "text": "この高解像度ドキュメントからすべてのテキストを抽出してください。"}, ], } ] prepare_inputs = vl2_processor( conversations=conversation, images=[high_res_image], force_batchify=True, system_prompt="", ).to(vl2_model.device) # 実際に使用されたタイル数を確認 num_tiles = prepare_inputs.get("images_seq_mask", torch.tensor([0])).sum().item() print(f"動的解像度は {num_tiles} タイル + 1 グローバルサムネイルを使用しました")

動的解像度 vs 固定解像度

比較 固定解像度 動的解像度
OCR 精度 低い、小さな文字がぼやける 高い、小さな文字も鮮明に読み取れる
推論速度 速い、単一タイル 遅い、複数タイルを並列処理
メモリ使用量 低い 高い、タイル数に応じて増加
適用シナリオ クイックプレビュー、低解像度画像 高精度 OCR、文書分析、チャート読み取り

ベストプラクティス

文書 OCR やチャート分析には、常に動的解像度モードを使用してください。単純なシーン分類や物体認識には、計算リソースを節約するために固定解像度を使用できます。タイル数は 9 個以内(約 1152x1152)に抑えることを推奨します。それを超えると限界利益は減少します。

VL2 マルチターン視覚対話

VL2 はマルチターン対話をサポートしており、対話中に異なる画像に切り替えることができます。モデルはコンテキストを記憶し、回答を続けます。以下にマルチターン対話の実装方法を示します。

マルチターン対話のコード実装

def vl2_multi_turn_chat(model, processor, image_paths, questions): """VL2 マルチターン視覚対話 Args: model: ロード済みの VL2 モデル processor: VL2 プロセッサ image_paths: 各ターンに対応する画像パスのリスト questions: 各ターンの質問のリスト """ conversation_history = [] images_so_far = [] for i, (img_path, question) in enumerate(zip(image_paths, questions)): # 現在のターンの画像をロード current_image = Image.open(img_path).convert("RGB") images_so_far.append(current_image) # ユーザーメッセージを構築 user_content = [] for j, img in enumerate(images_so_far): user_content.append({"type": "image", "image": img}) user_content.append({"type": "text", "text": question}) conversation_history.append({ "role": "user", "content": user_content, }) # 入力を準備 prepare_inputs = processor( conversations=conversation_history, images=images_so_far, force_batchify=True, system_prompt="", ).to(model.device) # 推論 with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, ) answer = processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) print(f"[ターン {i+1}] 質問: {question}") print(f"[ターン {i+1}] 回答: {answer}\n") # アシスタントの返答を対話履歴に追加 conversation_history.append({ "role": "assistant", "content": answer, }) return conversation_history # 使用例 images = ["images/doc_page1.jpg", "images/doc_page2.jpg"] questions = [ "最初のページの主な内容は何ですか?", "2ページ目と比べて、何が変わりましたか?", ] history = vl2_multi_turn_chat(vl2_model, vl2_processor, images, questions)

対話コンテキスト管理

マルチターン対話では、以下の点に注意してください:

  • コンテキスト長の制限: VL2 のコンテキストウィンドウには制限があるため、長い対話では履歴を切り詰めるか、要約戦略を使用する必要があります。
  • 画像蓄積戦略: 各ターンで過去の画像を保持するか選択できます。すべての画像を保持すると、より多くの GPU メモリを消費します。
  • 対話履歴の構造: role (user/assistant) と content の交互構造を維持し、モデルが対話の流れを理解できるようにします。
  • 画像の参照: 質問内で画像を明確に参照してください(例:「最初の画像の...」)。モデルの混乱を避けます。
  • タイムリーなクリーンアップ: 対話のトピックを切り替えるときは、コンテキストの汚染を避けるために conversation_history をリセットすることをお勧めします。

最適化の提案

長い対話のシナリオでは、各ターンで直近の 3〜5 ターンのみをコンテキストとして保持し、トークン制限を超えないようにすることをお勧めします。複数の画像を比較分析する必要がある場合は、複数のターンに分けて送信するのではなく、1 つのターンにすべての画像を含めることができます。

Janus 環境構築

Janus は DeepSeek の統一マルチモーダルモデルで、画像理解と画像生成の両方をサポートしています。Janus-Pro-7B は最新バージョンで、理解と生成の両方で大幅に改善されています。

依存関係のインストール

# 仮想環境の作成 python -m venv janus-env janus-env\Scripts\activate # PyTorch のインストール pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # Janus のコア依存関係のインストール pip install transformers accelerate pip install pillow numpy pip install sentencepiece # huggingface_hub のインストール pip install huggingface_hub # インストールの確認 python -c "import torch; import transformers; print('Janus 環境準備完了')"

Janus-Pro-7B のダウンロード

from huggingface_hub import snapshot_download # Janus-Pro-7B のダウンロード snapshot_download( repo_id="deepseek-ai/Janus-Pro-7B", local_dir="./models/Janus-Pro-7B", local_dir_use_symlinks=False, resume_download=True, ) # Janus-1.3B(軽量版)もダウンロード可能 # snapshot_download( # repo_id="deepseek-ai/Janus-1.3B", # local_dir="./models/Janus-1.3B", # local_dir_use_symlinks=False, # resume_download=True, # ) print("Janus モデルのダウンロードが完了しました")

Janus モデル規模の比較

モデルバージョン パラメータ規模 画像理解 画像生成 GPU メモリ要件
Janus-1.3B 1.3B 基本サポート 384x384 約 6GB
Janus-Pro-7B 7B 拡張版 384x384(品質向上) 約 20GB

Janus マルチモーダル理解

Janus は、画像キャプション、視覚的質問応答、マルチモーダル推論をサポートしています。理解精度は VL2 には及びませんが、その統一アーキテクチャにより、理解と生成をシームレスに切り替えることができます。

Janus モデルのロード

import torch from transformers import AutoModelForCausalLM from janus.models import MultiModalityCausalLM, VLChatProcessor from PIL import Image # Janus モデルのロード model_path = "./models/Janus-Pro-7B" vl_chat_processor = VLChatProcessor.from_pretrained(model_path) tokenizer = vl_chat_processor.tokenizer vl_gpt = MultiModalityCausalLM.from_pretrained( model_path, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) vl_gpt.eval() print("Janus モデルのロードが完了しました")

画像キャプション(Image Captioning)

def janus_image_caption(model, processor, image_path): """Janus 画像キャプション""" image = Image.open(image_path).convert("RGB") conversation = [ { "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": "この画像の内容を詳しく説明してください。"}, ], }, ] prepare_inputs = processor( conversations=conversation, images=[image], force_batchify=True, ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, pad_token_id=tokenizer.eos_token_id, ) caption = tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) return caption # 使用例 caption = janus_image_caption(vl_gpt, vl_chat_processor, "images/photo.jpg") print("画像キャプション:", caption)

視覚的質問応答

def janus_vqa(model, processor, image_path, question): """Janus 視覚的質問応答""" image = Image.open(image_path).convert("RGB") conversation = [ { "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": question}, ], }, ] prepare_inputs = processor( conversations=conversation, images=[image], force_batchify=True, ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, pad_token_id=tokenizer.eos_token_id, ) answer = tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) return answer # 使用例 answer = janus_vqa(vl_gpt, vl_chat_processor, "images/diagram.png", "この図にはいくつのステップがありますか?各ステップは何ですか?") print("回答:", answer)

マルチモーダル推論

# Janus は画像コンテンツに基づく論理的推論をサポート question = """このスクリーンショットのコードロジックを分析してください: 1. このコードはどのような機能を実装していますか? 2. 潜在的なバグはありますか? 3. このコードをどのように最適化できますか?""" answer = janus_vqa(vl_gpt, vl_chat_processor, "images/code_screenshot.png", question) print("マルチモーダル推論結果:\n", answer)

Janus 画像生成

Janus はテキストから画像への生成をサポートし、384x384 解像度の画像を出力します。生成パラメータを調整することで、画像の多様性と品質を制御できます。

テキストから画像への生成

import numpy as np from janus.utils.io import save_image def janus_text_to_image(model, processor, prompt, output_path, **gen_kwargs): """Janus テキストから画像への生成 Args: model: Janus モデル processor: VLChatProcessor prompt: 画像生成プロンプト output_path: 出力画像パス gen_kwargs: 生成パラメータ """ # 生成用の会話を構築 conversation = [ { "role": "user", "content": [ {"type": "text", "text": prompt}, ], }, ] prepare_inputs = processor( conversations=conversation, images=[], force_batchify=True, ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=gen_kwargs.get("max_new_tokens", 1024), do_sample=gen_kwargs.get("do_sample", True), temperature=gen_kwargs.get("temperature", 1.0), top_p=gen_kwargs.get("top_p", 0.95), pad_token_id=tokenizer.eos_token_id, ) # 生成された画像トークンをデコード generated_ids = outputs[0].cpu().tolist() image_tokens = model.decode_image_tokens(generated_ids) # トークンを画像に変換 image = model.gen_vision_model.decode_code( image_tokens.to(model.device), shape=[1, 8, 24, 24], # Janus 画像の形状 ) # 画像を保存 decoded_image = image[0].cpu().float().numpy().transpose(1, 2, 0) decoded_image = np.clip((decoded_image * 0.5 + 0.5) * 255, 0, 255).astype(np.uint8) Image.fromarray(decoded_image).save(output_path) print(f"画像が保存されました: {output_path}") # 生成例 prompt = "A serene lake at sunset with mountains in the background, oil painting style" janus_text_to_image( vl_gpt, vl_chat_processor, prompt=prompt, output_path="output/sunset_lake.png", temperature=1.0, do_sample=True, )

生成パラメータの説明

パラメータ 説明 推奨値
temperature 生成の多様性を制御します。高いほどランダムになり、低いほど決定論的になります 0.8 - 1.2
top_p 核サンプリングの閾値で、候補トークンの範囲を制御します 0.9 - 0.95
max_new_tokens 生成する最大トークン数。画像の詳細に影響します 1024 - 2048
do_sample サンプリングを使用するかどうか。False の場合は貪欲法デコードを使用 True(画像生成の場合)

バッチ画像生成

def janus_batch_generate(model, processor, prompts, output_dir="output"): """バッチで画像を生成し、各プロンプトから複数のバリエーションを生成""" import os os.makedirs(output_dir, exist_ok=True) for idx, prompt in enumerate(prompts): for variant in range(4): # 各プロンプトにつき4枚生成 output_path = f"{output_dir}/gen_{idx+1}_v{variant+1}.png" janus_text_to_image( model, processor, prompt=prompt, output_path=output_path, temperature=0.9 + variant * 0.1, # 毎回少し異なる do_sample=True, ) print(f"バッチ生成が完了しました。合計 {len(prompts) * 4} 枚の画像") # 使用例 prompts = [ "A futuristic city with flying cars at night, neon lights", "A traditional Chinese garden with a koi pond and pavilion", "A cute robot reading a book under a tree", ] janus_batch_generate(vl_gpt, vl_chat_processor, prompts)

ヒント

Janus の画像生成は自己回帰 Transformer に基づいており、生成速度は max_new_tokens に依存します。384x384 の解像度はほとんどのシナリオに適しています。より高い解像度が必要な場合は、後で超解像モデルを使用して拡大できます。プロンプトは英語で記述することをお勧めします。説明が具体的であればあるほど、生成結果が良くなります。

VL2 と Janus の包括的な比較

アーキテクチャ、能力、モデル規模、推論速度、適用シナリオなどの観点から VL2 と Janus を総合的に比較し、正しいモデル選択を支援します。

コア機能の比較

機能の側面 DeepSeek VL2 DeepSeek Janus (Pro-7B)
OCR 文字認識 非常に強い(動的解像度対応) 普通
チャート/文書理解 プロフェッショナルレベル 基本的なサポート
視覚的質問応答 高精度 中程度
画像キャプション 詳細で正確 自然で流暢
画像生成 非対応 対応(384x384)
テキストのみの対話 対応 対応(より自然)
推論速度 中程度(タイルが多いと遅い) 高速(固定解像度)
モデル規模 3B / 16B / 27B(MoE) 1.3B / 7B

推奨ユースケース

シナリオ 推奨モデル 理由
文書 OCR 認識 VL2 動的解像度、小さな文字も鮮明
財務諸表分析 VL2 チャート理解 + データ抽出
マルチモーダルチャットボット Janus 理解と生成の統合体験
AI 绘画アプリ Janus テキストから画像へのネイティブ対応
医用画像分析 VL2 高精度な細粒度認識
クリエイティブコンテンツ生成 Janus 理解と生成のクローズドループ

組み合わせ利用プラン

実際のプロジェクトでは、VL2 と Janus を補完的に利用できます:

  • VL2 で理解 + Janus で生成:VL2 でユーザーがアップロードした画像を高精度に理解し、重要な情報を抽出した後、Janus で応答や新しい画像を生成
  • VL2 で前処理 + Janus で対話:VL2 が OCR と文書解析を担当し、Janus が自然言語対話とクリエイティブ生成を担当
  • シナリオによるルーティング:文書関連のリクエストは VL2 に、クリエイティブ関連のリクエストは Janus にルーティングし、リソースを最適に活用

モデルの比較や選定ガイドの詳細は、DeepSeek オープンソースモデルリストDeepSeek モデルアーキテクチャ詳細 をご覧ください。

実践:マルチモーダルAIアプリケーション

VL2とJanusを完全なWebアプリケーションに統合し、画像アップロード、視覚的質問応答、画像生成をサポートします。Streamlitを使用してインタラクティブなUIを構築します。

完全なアプリケーションコード:multimodal_app.py

"""DeepSeek マルチモーダルAIアプリケーション — VL2理解 + Janus生成""" import streamlit as st import torch from PIL import Image import os # ページ設定 st.set_page_config( page_title="DeepSeek マルチモーダルAI", page_icon=None, layout="wide", ) st.title("DeepSeek マルチモーダルAIアプリケーション") st.markdown("VL2視覚理解とJanus画像生成をサポート") # サイドバー:モデル選択 with st.sidebar: st.header("モデル設定") model_choice = st.radio( "モデルを選択", ["DeepSeek VL2 (視覚理解)", "DeepSeek Janus (理解+生成)"], ) if "VL2" in model_choice: vl2_size = st.selectbox( "VL2モデルサイズ", ["Tiny (3B)", "Small (16B)", "Full (27B MoE)"], ) st.caption("クイックテストにはTiny、本番環境にはFullを推奨") if "Janus" in model_choice: st.caption("Janus-Pro-7Bモデルを使用") gen_mode = st.radio("モード", ["画像理解", "画像生成"]) st.divider() st.markdown("### 概要") st.markdown("DeepSeekマルチモーダルモデル実践チュートリアル") st.markdown("VL2: OCR / チャート / 視覚的QA") st.markdown("Janus: 理解 + テキストから画像生成") # モデルのロード(キャッシュ) @st.cache_resource def load_vl2_model(size="tiny"): """VL2モデルをロード""" from deepseek_vl2.models import DeepseekVLV2Processor, DeepseekVLV2ForCausalLM model_map = { "tiny": "deepseek-ai/deepseek-vl2-tiny", "small": "deepseek-ai/deepseek-vl2-small", "full": "deepseek-ai/deepseek-vl2", } model_path = model_map.get(size, model_map["tiny"]) processor = DeepseekVLV2Processor.from_pretrained(model_path) model = DeepseekVLV2ForCausalLM.from_pretrained( model_path, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) return model, processor @st.cache_resource def load_janus_model(): """Janusモデルをロード""" from janus.models import MultiModalityCausalLM, VLChatProcessor model_path = "deepseek-ai/Janus-Pro-7B" processor = VLChatProcessor.from_pretrained(model_path) model = MultiModalityCausalLM.from_pretrained( model_path, torch_dtype=torch.bfloat16, device_map="auto", trust_remote_code=True, ) model.eval() return model, processor # メインインターフェース if "VL2" in model_choice: st.header("VL2視覚理解") uploaded_file = st.file_uploader( "画像をアップロード", type=["png", "jpg", "jpeg", "webp"], help="一般的な画像形式をサポート", ) question = st.text_input( "質問を入力", placeholder="例:この画像からすべてのテキストを抽出してください...", ) task_type = st.selectbox( "タスクタイプ", ["一般的なQA", "OCRテキスト抽出", "チャート分析", "視覚的グラウンディング", "画像キャプション"], ) if uploaded_file and question: image = Image.open(uploaded_file).convert("RGB") col1, col2 = st.columns(2) with col1: st.image(image, caption="アップロードされた画像", use_container_width=True) if st.button("分析開始", type="primary"): with col2: with st.spinner("VL2が分析中..."): # タスクタイプに基づいてプロンプトを構築 task_prompts = { "一般的なQA": question, "OCRテキスト抽出": f"この画像からすべてのテキストを抽出し、元の形式を保持してください:{question}", "チャート分析": f"このチャートを分析してください:{question}", "視覚的グラウンディング": f"画像内のターゲットオブジェクトを特定してください:{question}", "画像キャプション": "この画像の内容を詳細に説明してください。", } # VL2推論を呼び出し model, processor = load_vl2_model(vl2_size.lower().split()[0]) conversation = [{ "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": task_prompts[task_type]}, ], }] prepare_inputs = processor( conversations=conversation, images=[image], force_batchify=True, system_prompt="", ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=1024, do_sample=False, ) answer = processor.tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) st.markdown("### 分析結果") st.markdown(answer) elif "Janus" in model_choice: if gen_mode == "画像理解": st.header("Janus画像理解") uploaded_file = st.file_uploader( "画像をアップロード", type=["png", "jpg", "jpeg", "webp"], ) question = st.text_input( "質問を入力", placeholder="この画像を説明してください...", ) if uploaded_file and question: image = Image.open(uploaded_file).convert("RGB") col1, col2 = st.columns(2) with col1: st.image(image, caption="アップロードされた画像", use_container_width=True) if st.button("分析開始", type="primary"): with col2: with st.spinner("Janusが分析中..."): model, processor = load_janus_model() tokenizer = processor.tokenizer conversation = [{ "role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": question}, ], }] prepare_inputs = processor( conversations=conversation, images=[image], force_batchify=True, ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=512, do_sample=False, pad_token_id=tokenizer.eos_token_id, ) answer = tokenizer.decode( outputs[0].cpu().tolist(), skip_special_tokens=True, ) st.markdown("### 分析結果") st.markdown(answer) else: st.header("Janus画像生成") prompt = st.text_area( "生成プロンプトを入力(英語推奨)", placeholder="A serene lake at sunset with mountains in the background, oil painting style", height=100, ) col1, col2 = st.columns(2) with col1: temperature = st.slider("Temperature", 0.5, 1.5, 1.0, 0.1) with col2: num_images = st.selectbox("生成枚数", [1, 2, 4], index=0) if prompt and st.button("画像を生成", type="primary"): model, processor = load_janus_model() tokenizer = processor.tokenizer for i in range(num_images): with st.spinner(f"画像 {i+1}/{num_images} を生成中..."): conversation = [{ "role": "user", "content": [{"type": "text", "text": prompt}], }] prepare_inputs = processor( conversations=conversation, images=[], force_batchify=True, ).to(model.device) with torch.no_grad(): inputs_embeds = model.prepare_inputs_embeds(**prepare_inputs) outputs = model.language_model.generate( inputs_embeds=inputs_embeds, attention_mask=prepare_inputs.attention_mask, max_new_tokens=1024, do_sample=True, temperature=temperature, top_p=0.95, pad_token_id=tokenizer.eos_token_id, ) generated_ids = outputs[0].cpu().tolist() image_tokens = model.decode_image_tokens(generated_ids) gen_image = model.gen_vision_model.decode_code( image_tokens.to(model.device), shape=[1, 8, 24, 24], ) import numpy as np decoded = gen_image[0].cpu().float().numpy().transpose(1, 2, 0) decoded = np.clip((decoded * 0.5 + 0.5) * 255, 0, 255).astype(np.uint8) st.image(decoded, caption=f"生成結果 {i+1}", use_container_width=True) # フッター st.divider() st.caption("DeepSeek マルチモーダル AI アプリ | VL2 + Janus | ローカルデプロイ、データ安全")

インストールと実行

# Streamlit のインストール pip install streamlit # アプリの実行 streamlit run multimodal_app.py # ブラウザで開く # http://localhost:8501

アプリ機能の説明

  • VL2 視覚理解:画像アップロード、複数タスクタイプ(OCR/チャート/検出/説明)、カスタム質問に対応
  • Janus 画像理解:画像をアップロードし、自然言語で Q&A
  • Janus 画像生成:テキストから画像を生成、温度調整とバッチ生成に対応
  • モデルキャッシュ:Streamlit のキャッシュ機構を使用し、モデルは一度だけ読み込む
  • サイドバー設定:モデルとモードを柔軟に切り替え、生成パラメータを調整

デプロイメントの推奨事項

本番環境では、ハードウェアコストを抑えるために VL2-Tiny または Janus-1.3B の使用を推奨します。高性能な推論が必要な場合は、vLLM や TGI を使用してモデルサービスをデプロイし、フロントエンドは API 経由で呼び出します。詳細は DeepSeek デプロイチュートリアル を参照してください。

DeepSeek マルチモーダルよくある質問

DeepSeek VL2 と Janus のどちらを選ぶべきですか? +
ニーズによります:高精度の OCR、文書分析、チャート理解が必要なら VL2 を選んでください(動的解像度メカニズムにより文字認識に優れています);画像生成機能や統一されたマルチモーダル対話体験が必要なら Janus を選んでください。両方を組み合わせることもできます:VL2 で理解の前処理を行い、Janus で生成と対話を行います。
VL2 の動的解像度にはどのくらいの VRAM が必要ですか? +
VRAM 消費はタイル数に比例します。VL2-Tiny は 1x1 タイルで約 8GB、2x2 タイルで約 12GB、3x3 タイルで約 18GB の VRAM が必要です。実際の画像サイズと GPU の VRAM に基づいてタイル数を調整することをお勧めします。VL2-Small と VL2-Full はより多くの VRAM が必要で、A100 や H100 などのハイエンド GPU を推奨します。
Janus が生成した画像は拡大できますか? +
はい。Janus はネイティブで 384x384 解像度を出力します。超解像モデル(Real-ESRGAN、SwinIR など)を使用して 1024x1024 以上に拡大できます。また、Stable Diffusion の img2img 機能を使用して高解像度修復も可能です。Janus 生成後に超解像モデルで後処理を行うことをお勧めします。
VL2 と Janus は CPU で実行できますか? +
はい、ただし非常に遅くなります。VL2-Tiny と Janus-1.3B は CPU で実行できますが、推論時間は GPU の数秒から数十秒、場合によっては数分に増加する可能性があります。軽量バージョンを実行するには、少なくとも 8GB VRAM の GPU(RTX 3060/4060 など)を使用することをお勧めします。GPU がない場合は、クラウド GPU サービスや DeepSeek 公式 API の利用を検討してください。
マルチモーダルモデルの推論速度を最適化するには? +
1) bfloat16 または int8 量子化を使用して VRAM と計算量を削減;2) VL2 でタイル数を減らす(精度を犠牲にして速度を向上);3) Flash Attention を使用してアテンション計算を高速化;4) vLLM や TensorRT-LLM を使用して推論サービスをデプロイ;5) 複数の画像をバッチ処理して GPU の並列処理を最大限に活用。本番環境では、vLLM でのデプロイを強くお勧めします。
VL2 と Janus はファインチューニングできますか? +
はい。両モデルとも LoRA や QLoRA を使用したパラメータ効率的なファインチューニングをサポートしています。VL2 は特定ドメインの文書やチャートデータでのファインチューニングに適しており、OCR と理解精度を向上させます;Janus は特定スタイルの画像データでのファインチューニングに適しており、生成品質を改善します。ファインチューニング方法の詳細は DeepSeek モデルファインチューニングチュートリアル を参照してください。

DeepSeek 関連チュートリアル

DeepSeek モデルの使用方法、デプロイ、エコシステムツールを詳しく学びます。

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

完全免费,取消任意时间。我们不会发送垃圾邮件。