WanによるAI動画生成で「プロンプトを書いたのに人物が全然動かない」という経験はありませんか?この記事では、Wanで人物の動きを強く引き出すプロンプトのコツと、シンプルな実行コードをまとめて解説します。


なぜ人物が動かないのか?

プロンプトの書き方以前に、パラメータ設定が原因でほぼ動かなくなるケースが多いです。まず以下を確認してください。

パラメータ NG値 推奨値
guidance_scale 1~2(低すぎる) 5.0〜7.0
num_inference_steps 8(少なすぎる) 20〜30
DMD蒸留LoRA 常時ON まず外して試す

guidance_scale が低いとモデルがプロンプトをほぼ無視します。まずここを直すだけで改善することが多いです。


プロンプトで動きを引き出す5つのコツ

1. 動作を時系列で分解して書く

「歩く」だけでなく、身体の動きを順番に記述すると効果的です。

❌ "The woman walks."

✅ "She lifts her right foot, strides forward,
   swings her arms, walking briskly."

2. 副詞・強度ワードを加える

動きの強度を明示するだけで出力が変わります。

briskly / confidently / heavily / swiftly / energetically

3. 身体部位を具体的に書く

Wanは身体部位の指定に素直に反応します。

"her legs move back and forth, arms swing naturally,
 body shifts weight left and right"

4. 冒頭に動的宣言を入れる

プロンプトの最初に置くと効きやすいキーワードです。

"Dynamic motion. Full body movement. Cinematic."

5. カメラ・背景も動かす記述を足す

背景の変化もモデルへのヒントになります。

"The background moves as she walks,
 camera follows from behind."

そのまま使える歩行プロンプトテンプレート

Dynamic full body motion. The woman strides forward confidently,
her legs alternating step by step, arms swinging naturally at her sides,
hair and clothes moving with the motion.
Camera follows from behind. Smooth continuous walking movement.

シンプルなWan実行コード(Python)

以下は最小構成で動かすためのサンプルコードです。VideoX-Funのパイプラインを前提にしています。

import torch
from PIL import Image
from omegaconf import OmegaConf
from diffusers import FlowMatchEulerDiscreteScheduler
from transformers import AutoTokenizer

from videox_fun.models import (
    AutoencoderKLWan, CLIPModel, WanT5EncoderModel, WanTransformer3DModel
)
from videox_fun.pipeline import WanFunInpaintPipeline
from videox_fun.utils.utils import filter_kwargs, get_image_to_video_latent, save_videos_grid

# ========== 設定 ==========
model_name   = "Diffusion_Transformer/Wan2.1-Fun-V1.1-1.3B-InP"
image_path   = "input.png"           # 開始フレーム画像
save_path    = "./output.mp4"
prompt       = (
    "Dynamic full body motion. The woman strides forward confidently, "
    "her legs alternating step by step, arms swinging naturally at her sides, "
    "hair and clothes moving with the motion. "
    "Camera follows from behind. Smooth continuous walking movement."
)
negative_prompt    = ""
guidance_scale     = 6.0   # 動きを出すには5〜7推奨
num_inference_steps = 25   # 20〜30推奨
video_length       = 49    # フレーム数
fps                = 12
seed               = 42
weight_dtype       = torch.float32
device             = "cuda" if torch.cuda.is_available() else "cpu"
# ==========================

# 画像サイズを16の倍数に整形
img = Image.open(image_path)
w, h = img.size
if max(w, h) > 2048:
    scale = 2048 / max(w, h)
    w, h = int(w * scale), int(h * scale)
sample_size = [(h // 16) * 16, (w // 16) * 16]

config = OmegaConf.load(f"{model_name}/wan_civitaifp8.yaml")

# モデル読み込み
transformer = WanTransformer3DModel.from_pretrained(
    f"{model_name}/transformer",
    transformer_additional_kwargs=OmegaConf.to_container(config["transformer_additional_kwargs"]),
    torch_dtype=weight_dtype,
)
vae = AutoencoderKLWan.from_pretrained(
    f"{model_name}/vae",
    additional_kwargs=OmegaConf.to_container(config["vae_kwargs"]),
).to(weight_dtype)
tokenizer    = AutoTokenizer.from_pretrained(f"{model_name}/tokenizer")
text_encoder = WanT5EncoderModel.from_pretrained(
    f"{model_name}/text_encoder",
    additional_kwargs=OmegaConf.to_container(config["text_encoder_kwargs"]),
    torch_dtype=weight_dtype,
)
clip_image_encoder = CLIPModel.from_pretrained(
    f"{model_name}/image_encoder"
).to(weight_dtype)

scheduler = FlowMatchEulerDiscreteScheduler(
    **filter_kwargs(FlowMatchEulerDiscreteScheduler,
                    OmegaConf.to_container(config["scheduler_kwargs"]))
)

# パイプライン構築
pipeline = WanFunInpaintPipeline(
    transformer=transformer,
    vae=vae,
    tokenizer=tokenizer,
    text_encoder=text_encoder,
    scheduler=scheduler,
    clip_image_encoder=clip_image_encoder,
)
pipeline.enable_model_cpu_offload(device=device)

# 入力動画潜在変数の準備
video_length = (
    int((video_length - 1)
        // vae.config.temporal_compression_ratio
        * vae.config.temporal_compression_ratio) + 1
)
input_video, input_video_mask, clip_image = get_image_to_video_latent(
    image_path, None,
    video_length=video_length,
    sample_size=sample_size,
)

# 生成
generator = torch.Generator(device=device).manual_seed(seed)
with torch.no_grad():
    sample = pipeline(
        prompt,
        num_frames          = video_length,
        negative_prompt     = negative_prompt,
        height              = sample_size[0],
        width               = sample_size[1],
        generator           = generator,
        guidance_scale      = guidance_scale,
        num_inference_steps = num_inference_steps,
        video               = input_video,
        mask_video          = input_video_mask,
        clip_image          = clip_image,
        shift               = 3,
    ).videos

# 保存
save_videos_grid(sample, save_path, fps=fps, imageio_backend=True)
print("完了:", save_path)

ポイントまとめ(コード内)

  • guidance_scale = 6.0:これが最重要。1.5はNG
  • num_inference_steps = 25:8では歩行のような複雑動作は出にくい
  • LoRAは一旦なし:DMD蒸留LoRAは動きを抑制しやすいため、まずなしで試す
  • 入力画像のポーズ:直立静止より「歩きかけ」のポーズの画像を使うと大幅に改善する

まとめ

  • 動かない原因の多くは guidance_scale が低すぎることが原因
  • プロンプトは「動詞を分解・副詞で強度を加える・身体部位を明示」が基本
  • 冒頭に Dynamic motion. Full body movement. を入れるだけでも効果あり
  • 入力画像は「動きかけ」のポーズを用意すると結果が大きく変わる

設定とプロンプトを両方調整することで、Wanでもしっかり人物を歩かせることができます。ぜひ試してみてください。