LongLive-Plug-Wan2.2-TI2V-5B-few-step: Our Generated Video, File List

October 2, 2026

LongLive-Plug-Wan2.2-TI2V-5B-few-step: Our Generated Video, File List

At a Glance

Item Value
Repository Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step
Publisher guide Efficient Large Model (NVIDIA and MIT): models and licenses
Published 2026-09-29
License apache-2.0
Formats safetensors
Source type Primary source (the publisher itself)

Values determined by this site’s code when the information was collected. Dates are JST.

What we checked ourselves

  • We generated video on a rented cloud GPU from our own fixed prompts and show it unedited.

Details and conditions are in “Our Own Measurements” below.

Overview

Efficient-Large-Model has released a Generator LoRA, LongLive-Plug-Wan2.2-TI2V-5B-few-step, designed for video generation models based on Wan-AI/Wan2.2-TI2V-5B to enable inference in an extremely low number of steps. This LoRA supports both Text-to-Video and Image-to-Video tasks, which output videos from text or image inputs, achieving a 4-step non-autoregressive full-sequence inference.

The base model, Wan2.2-TI2V-5B, supports 720P resolution at 24fps video generation and is among the fastest available 720P@24fps models. The checkpoint in this release is a trained model at iteration 1500 from dev/nonAR experiments using 16 GPUs. real_guidance_scale=3 was set during training. Note that this distilled Generator has been validated with guidance_scale=1.0, which does not use CFG (Classifier-Free Guidance) during inference. The published file is a lossless extraction of the Generator only. While the original checkpoint also includes a training-only Critic LoRA, only the Generator LoRA is provided in this release.

Specifications

  • Base Model: Wan-AI/Wan2.2-TI2V-5B
  • Architecture: full-sequence non-AR
  • Training Objective: DMD (Differentiable Diffusion Model) with backward simulation
  • Real Guidance Scale (RGS) during Training: 3
  • Checkpoint Identifier: checkpoint_model_001500
  • World Size during Training: 16
  • LoRA Rank / Alpha: 128 / 128
  • Generator LoRA Parameters: 322,437,120 (600 FP32 tensors)
  • Denoising Steps during Inference: 4 steps
  • CFG Scale during Inference: 1.0 (No CFG)
  • License: Apache-2.0

Strengths and Use Cases

This model is specialized in dramatically improving generation speed while maintaining the advanced video generation capabilities of the base model, Wan2.2-TI2V-5B. Its main use cases are both Text-to-Video and Image-to-Video generation. The primary advantage is that it can complete high-quality video generation, which normally requires many steps, in just 4 steps of inference.

The Wan2.2 series, which serves as the base model, features a significantly expanded training dataset compared to the previous version, Wan2.1. Specifically, image data has increased by 65.6% and video data by 83.2%, which greatly improves versatility in depicting complex motions, semantics, and visual aesthetics. It is developed with a particular focus on “cinematic aesthetics" and is trained on datasets with detailed labels for lighting, composition, contrast, and color tone. Therefore, it excels at generating precise and controllable cinematic-style videos tailored to user preferences.

Additionally, the Wan2.2-VAE adopted by this model achieves a high compression rate of 16×16×4, enabling efficient generation while maintaining high-quality video reconstruction. This allows for the generation of 720P resolution (1280×704 or 704×1280) videos at 24fps. Because this model natively supports both text and image inputs within a single framework, advanced control combining prompt instructions and image-based composition specification is possible.

Applying this LoRA makes it a powerful tool for creative applications requiring many trial-and-error iterations in a short time, applications demanding near-real-time responses, or technical environments aiming to obtain high-quality videos while suppressing computational resources. By adopting non-autoregressive (non-AR) full-sequence inference, the efficiency of the entire generation process is optimized.

Distributed Files

Weight files published in Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step, listed by this site from the Hugging Face API. Sizes are the actual file sizes.

File Size
adapter_model.safetensors 1.29GB
generator_lora.pt 1.29GB

How to Get It

LoRA weights and related configuration files for this model are available from the Hugging Face repository Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step. This repository holds selected training checkpoint weights, configuration files, runtime source code, and license notices.

The main distributed files are as follows:
– generator_lora.pt: Native format weights for use in the LongLive wrapper
– adapter_model.safetensors: Safetensors format weights containing 600 tensors
– adapter_config.json: Configuration file including PEFT Rank/Alpha settings
– inference_config.yaml: Inference configuration file including 4-step inference and No-CFG settings
– training_config.yaml: Detailed configuration records during training with 16 GPUs
– provenance.json: Checksum records of source files and published files

When downloading weights using Python, the following code can be used:

from huggingface_hub import hf_hub_download

lora_path = hf_hub_download(
    repo_id="Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step",
    filename="generator_lora.pt",
)

During inference, the following settings must be strictly observed. These are settings dedicated to this adapter, and default settings for general autoregressive models should not be used:
– Sampling Steps: 4
– Guidance Scale during Inference: 1.0 (No CFG)
– LoRA Rank / Alpha: 128 / 128
– generator_is_causal: false (non-autoregressive setting)

This model is released under the Apache-2.0 license, allowing flexible use for both commercial and research purposes. No special consent process (Gated) is required to obtain it.

Can You Run It Locally?

The publisher distributes this model as safetensors.

License — apache-2.0 (Commercial use allowed): Permits commercial use, modification and redistribution. Redistribution requires including the license and stating changes; includes a patent grant.

Compiled by this site’s code from the published formats and the license field. License summaries are not legal advice — check the publisher’s original terms before relying on them.

Our Own Measurements

Generated by us — not samples copied from the model card. We cannot run video models on our own server (no GPU), so we generated on a rented cloud GPU (conditions below). How we measure, and the results for every model: Our Measurements.

Video We Generated (Cloud GPU)

Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step (apache-2.0 license) is a LoRA adapter and does not run on its own, so we merged it into the base model Wan-AI/Wan2.2-TI2V-5B-Diffusers (apache-2.0 license) in the combination the publisher recommends (LongLive-Plug-Wan2.2-TI2V-5B-few-step at weight 1.0, LongLive-Plug-Wan2.2-TI2V-5B-cfg at weight 0.5) and generated with 4 steps and guidance scale 1.0. We set the sampler to match the publisher’s inference code (LongLive-Plug inference.py): UniPC with shift 5.0 (diffusers’ UniPCMultistepScheduler). The publisher says to use this adapter together with LongLive-Plug-Wan2.2-TI2V-5B-cfg, so we merged both, and the same videos also appear in that adapter’s article. We ran diffusers’ WanPipeline (diffusers 0.40.0) and did not run any code from the publisher. The LoRA was merged by our own code: we map the original Wan layer names to diffusers’ names and add weight × (alpha / r) × BA to each weight. This mapping is our interpretation, not something the publisher documents; we only confirmed that every layer name and shape matched.

Conditions: NVIDIA L40S (VRAM 44GB) on Modal, weights in BF16 (VAE in FP32), 1280×704 pixels, 121 frames at 24 fps (about 5.04 s), seed 0, two fixed prompts without people, logos or text, generated 2026-10-02 (JST). Not selected — each clip is the first output. To fit our server’s upload limit we re-encoded each clip as H.264 (under 12.0 MB), so fine detail may be softer than the raw output.

Prompt: “a small red paper boat drifting down a clear forest stream, sunlight flickering through the leaves, gentle ripples, realistic”

Without the LoRA (base model, same 4 steps), 51 s to generate

With the LoRA, 52 s to generate

Prompt: “time-lapse of white clouds rolling over snowy mountain peaks at sunrise, golden light, wide shot”

Without the LoRA (base model, same 4 steps), 52 s to generate

With the LoRA, 52 s to generate

Item Result
VRAM after loading the model (BF16, text encoder already released) 12.0GB
Peak VRAM while generating 32.3GB

Generation times are for a rented cloud NVIDIA L40S and are not a guide to your own GPU; the text encoder runs first and is released before the video model loads, so the VRAM above does not include it. The “without the LoRA” clips use the same 4 steps for comparison only; the base model’s usual settings use many more steps with guidance, so they do not show what the base model can do.

Setup, Download and Run Steps (What We Actually Ran)

We split the work into two containers on Modal, both built from the Debian (slim) image with Python 3.12. The downloading container fetches only the listed files (configs, safetensors weights and the tokenizer) from Hugging Face at pinned revisions; the generating container has no network access. These are the packages we installed:

# 1. Environment for downloading (no GPU)
python -m pip install huggingface_hub

# 2. Environment for generating (GPU, network blocked)
python -m pip install torch diffusers transformers accelerate safetensors sentencepiece ftfy imageio-ffmpeg numpy

We then called download(job) in the first container and run(job) in the second one from the script below (video_remote.py, written by us; full text). Files go under /models/<dir>:

"""
Modal のコンテナの中で動く、動画生成モデルの生成(2026-10-01、ユーザーの判断)。lmw/lab/gpu_modal.py の
video_download / video_run から呼ばれる。**標準ライブラリだけを先頭で読み**、huggingface_hub・torch・diffusers は
各関数の中で読む(コンテナごとに入っているものが違う)。

【配布元のコードは動かさない】diffusers・transformers の公開パッケージだけで読み込む。重みは safetensors だけで、
Hugging Face のリポジトリのコードを読み込む設定は使わない。LoRA は当サイトのコード(merge_lora)が、名前の対応表と
形を照合しながら元の重みに足し込む(配布元の読み込み処理は使わない)。

【2つのコンテナに分ける】(lmw/lab/remote_code_remote.py と同じ)
- download: GPU の無いコンテナ・ネットワークあり。Hugging Face から、版を固定して決まったファイルだけを落とす。
- run: GPU のコンテナ・**ネットワーク遮断**・Modal の機能も使えない・Volume は読み取り専用。

【VRAM を節約する順番】テキストエンコーダ(UMT5-XXL は 11GB)でプロンプトを先に全部埋め込みにしてから捨て、
その後で動画の本体(transformer)と VAE を読む。2つを同時に GPU に載せないので、安い GPU に収まる。

【結果の返し方】run は生成器で、動画のバイト列を CHUNK_BYTES ずつ(kind: "chunk")、最後に記録(kind: "record")を返す。
Modal は 2MiB を超える戻り値を自分の API で預けるが、生成のコンテナは Modal の機能を遮断している
(restrict_modal_access)ので断られる(2026-10-02、14B の4本を作り終えた後に 401 で全て失った)。1回の戻り値を小さく保つ。

【費用を抑える】同じ読み込みのまま、LoRA を足す前(元のモデル)と足した後を続けて生成する(読み込みは1回)。
動画は WordPress のアップロードの上限に収まるよう H.264 で圧縮する(MAX_BYTES を超えたら画質を下げて作り直す)。

記事執筆用の LLM は呼ばない。
"""
import hashlib
import json
import os
import platform
import subprocess
import time
from datetime import datetime, timezone

MOUNT = "/models"
PYTHON_VERSION = "3.12"
DOWNLOAD_PACKAGES = ("huggingface_hub",)
# diffusers の Wan のパイプラインが使うもの(ftfy はプロンプトの整形、imageio-ffmpeg は H.264 の書き出しに使う)
RUN_PACKAGES = ("torch", "diffusers", "transformers", "accelerate", "safetensors", "sentencepiece", "ftfy",
                "imageio-ffmpeg", "numpy")
# 落としてよいファイル(pickle の .bin / .pt / .ckpt は落とさない)
ALLOWED_EXTS = (".json", ".safetensors", ".model", ".txt")

# 元の Wan の層の名前(LoRA が使う)→ diffusers の WanTransformer3DModel の層の名前。
# diffusers の変換スクリプト(scripts/convert_wan_to_diffusers.py)と同じ対応
WAN_LORA_MODULES = {
    "self_attn.q": "attn1.to_q", "self_attn.k": "attn1.to_k", "self_attn.v": "attn1.to_v",
    "self_attn.o": "attn1.to_out.0",
    "cross_attn.q": "attn2.to_q", "cross_attn.k": "attn2.to_k", "cross_attn.v": "attn2.to_v",
    "cross_attn.o": "attn2.to_out.0",
    "ffn.0": "ffn.net.0.proj", "ffn.2": "ffn.net.2",
}
# 1回に返すバイト数(Modal が自分の API に預けずにそのまま返せる 2MiB より十分小さく)
CHUNK_BYTES = 1024 * 1024
LORA_PREFIXES = ("base_model.model.", "diffusion_model.", "model.")
# 生成に使うデバイス。Modal では常に cuda(当サイトの評価で、小さなモデルを CPU で通すときだけ cpu にする)
DEVICE = "cuda"

def installed_packages() -> list[str]:
    from importlib import metadata
    seen = {}
    for dist in metadata.distributions():
        name = dist.metadata["Name"]
        if name and name.lower() not in seen:
            seen[name.lower()] = f"{name}=={dist.version}"
    return sorted(seen.values(), key=str.lower)

def _log(t0: float, message: str) -> None:
    print(f" {message}", flush=True)

def _sha256(path: str) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()

def download(job: dict) -> dict:
    """
    job: {"dir", "base": {"repo", "revision", "files"}, "loras": [{"repo", "revision", "file"}]}。
    元のモデルは <dir>/base、LoRA は <dir>/lora<i>/ に置く。戻り値: {"bytes", "seconds", "packages", "lora_sha256"}。
    """
    from huggingface_hub import hf_hub_download
    t0 = time.time()
    base_dir = os.path.join(MOUNT, job["dir"])
    total = 0
    targets = [(job["base"]["repo"], job["base"]["revision"], name, os.path.join(base_dir, "base"))
               for name in job["base"]["files"]]
    targets += [(lora["repo"], lora["revision"], lora["file"], os.path.join(base_dir, f"lora{i}"))
                for i, lora in enumerate(job.get("loras") or [])]
    for repo, revision, name, dest in targets:
        if not name.endswith(ALLOWED_EXTS) or ".." in name.split("/"):
            raise ValueError(f"落とさない種類のファイルです: {name}")
        path = hf_hub_download(repo, name, revision=revision, local_dir=dest)
        total += os.path.getsize(path)
    lora_sha = [_sha256(os.path.join(base_dir, f"lora{i}", lora["file"]))
                for i, lora in enumerate(job.get("loras") or [])]
    seconds = round(time.time() - t0)
    _log(t0, f"ダウンロード {total / 1024 ** 3:.1f}GB・{seconds}秒")
    return {"bytes": int(total), "seconds": int(seconds), "packages": installed_packages(), "lora_sha256": lora_sha}

def _lora_pairs(state: dict) -> dict:
    """{元の層の名前: {"A", "B", "alpha"?}}。名前の頭(base_model.model. 等)を外し、A と B の揃わない層は断る。"""
    pairs: dict = {}
    for key, tensor in state.items():
        name = key
        for prefix in LORA_PREFIXES:
            if name.startswith(prefix):
                name = name[len(prefix):]
                break
        if name.endswith(".lora_A.weight"):
            pairs.setdefault(name[:-len(".lora_A.weight")], {})["A"] = tensor
        elif name.endswith(".lora_B.weight"):
            pairs.setdefault(name[:-len(".lora_B.weight")], {})["B"] = tensor
        elif name.endswith(".alpha"):
            pairs.setdefault(name[:-len(".alpha")], {})["alpha"] = float(tensor.item())
        else:
            raise ValueError(f"LoRA の重みではない名前です: {key}")
    broken = [n for n, p in pairs.items() if "A" not in p or "B" not in p]
    if broken:
        raise ValueError(f"A と B が揃わない層があります: {broken[:5]}")
    return pairs

def diffusers_module_name(name: str) -> str:
    """blocks.12.self_attn.q → blocks.12.attn1.to_q。対応表に無い層は断る(推測で当てない)。"""
    parts = name.split(".")
    if len(parts) < 4 or parts[0] != "blocks" or not parts[1].isdigit():
        raise ValueError(f"対応表に無い層です: {name}")
    tail = ".".join(parts[2:])
    if tail not in WAN_LORA_MODULES:
        raise ValueError(f"対応表に無い層です: {name}")
    return f"blocks.{parts[1]}.{WAN_LORA_MODULES[tail]}"

def merge_lora(transformer, path: str, weight: float, alpha: float | None, rank: int | None) -> dict:
    """
    LoRA を元の重みに足し込む: W ← W + weight × (alpha / r) × (B @ A)。alpha と r は配布元の adapter_config.json の値を
    ホスト側が渡す(重みのファイルに alpha があればそちらを使う)。足し込みは float32 で計算してから元の型に戻す。
    全ての層が対応表で見つかり、形が一致することを確かめる(1つでも外れたら断る)。
    """
    import torch
    from safetensors.torch import load_file
    pairs = _lora_pairs(load_file(path))
    merged = 0
    for name, p in sorted(pairs.items()):
        module = transformer.get_submodule(diffusers_module_name(name))
        a, b = p["A"].float(), p["B"].float()
        r = a.shape[0]
        if rank and r != rank:
            raise ValueError(f"{name}: ランク {r} が adapter_config.json の {rank} と違います")
        scale = weight * ((p.get("alpha") or alpha or r) / r)
        w = module.weight
        delta = (b.to(w.device) @ a.to(w.device)) * scale
        if tuple(delta.shape) != tuple(w.shape):
            raise ValueError(f"{name}: 形 {tuple(delta.shape)} が元の重み {tuple(w.shape)} と違います")
        with torch.no_grad():
            w.copy_((w.float() + delta).to(w.dtype))
        merged += 1
    return {"modules": merged, "weight": weight, "scale": round(weight * ((alpha or rank or 1) / (rank or 1)), 6)}

def encode_mp4(frames, fps: int, path: str, max_bytes: int) -> dict:
    """
    0〜1 の RGB のコマ(F, H, W, 3)を H.264(yuv420p)の mp4 にする。max_bytes を超えたら、ビットレートの上限を
    下げて作り直す(3回まで)。戻り値: 実際に使った ffmpeg の引数と大きさ。
    """
    import imageio_ffmpeg
    import numpy as np
    pixels = (np.clip(frames, 0.0, 1.0) * 255).round().astype(np.uint8)
    count, height, width = pixels.shape[0], pixels.shape[1], pixels.shape[2]
    duration = count / fps
    # 上限の大きさの 85% に収まるビットレート(音声なし)
    kbps = int(max_bytes * 8 * 0.85 / duration / 1000)
    for attempt, crf in enumerate((18, 22, 26)):
        rate = int(kbps * (0.8 ** attempt))
        args = ["-y", "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{width}x{height}", "-r", str(fps), "-i", "-",
                "-an", "-c:v", "libx264", "-preset", "slow", "-crf", str(crf), "-maxrate", f"{rate}k",
                "-bufsize", f"{rate * 2}k", "-pix_fmt", "yuv420p", "-movflags", "+faststart", path]
        proc = subprocess.run([imageio_ffmpeg.get_ffmpeg_exe(), *args], input=pixels.tobytes(),
                              capture_output=True, timeout=600)
        if proc.returncode != 0:
            raise RuntimeError(f"ffmpeg が失敗しました: {proc.stderr.decode(errors='replace')[-400:]}")
        size = os.path.getsize(path)
        if size <= max_bytes:
            return {"ffmpeg_args": ["ffmpeg", *args[:-1], os.path.basename(path)], "bytes": size,
                    "frames": int(count), "width": int(width), "height": int(height), "fps": int(fps),
                    "duration": round(duration, 2)}
    raise ValueError(f"動画を {max_bytes} バイト以下に圧縮できませんでした")

def run(job: dict):
    """
    job: {"dir", "pipeline", "settings": {height, width, num_frames, fps, steps, guidance, flow_shift?},
          "seed", "prompts": [{"id", "en"}], "loras": [{"file", "weight", "alpha", "rank"}], "compare_base",
          "max_bytes"}。
    生成器: {"kind": "chunk", "id", "index", "data": bytes} を動画ごとに順に返し、最後に
    {"kind": "record", ...記録の一部(秒数・VRAM・版。動画の中身は含まない)} を返す。
    """
    import diffusers
    import numpy as np
    import torch
    import transformers
    os.environ["HF_HUB_OFFLINE"] = "1"
    os.environ["TRANSFORMERS_OFFLINE"] = "1"
    os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
    t0 = time.time()
    base_dir = os.path.join(MOUNT, job["dir"])
    model_dir = os.path.join(base_dir, "base")
    settings = job["settings"]
    guidance = float(settings["guidance"])
    cuda = DEVICE == "cuda"
    gpu = torch.cuda.get_device_name(0) if cuda else "cpu"
    _log(t0, f"GPU: {gpu}・diffusers {diffusers.__version__}・torch {torch.__version__}")
    record = {"gpu": gpu, "vram_total": int(torch.cuda.get_device_properties(0).total_memory) if cuda else 0,
              "diffusers": str(diffusers.__version__), "transformers": str(transformers.__version__),
              "torch": str(torch.__version__), "dtype": "bfloat16", "vae_dtype": "float32",
              "packages": installed_packages(), "python": platform.python_version(),
              "measured_at": datetime.now(timezone.utc).isoformat()}
    pipeline_cls = getattr(diffusers, job["pipeline"])

    # 1. プロンプトを埋め込みにする(テキストエンコーダだけを GPU に載せ、終わったら捨てる)
    with open(os.path.join(model_dir, "model_index.json"), encoding="utf-8") as f:
        index = json.load(f)
    skip_models = {name: None for name, spec in index.items()
                   if isinstance(spec, list) and name not in ("text_encoder", "tokenizer", "scheduler")}
    text_pipe = pipeline_cls.from_pretrained(model_dir, torch_dtype=torch.bfloat16, use_safetensors=True,
                                             local_files_only=True, **skip_models)
    text_pipe.text_encoder.to(DEVICE)
    embeds = {}
    with torch.no_grad():
        for p in job["prompts"]:
            # max_sequence_length はパイプラインの __call__ の既定(512。元の Wan も 512)に合わせる。
            # encode_prompt の既定は 226 で、そのままだと標準の呼び出しと違う埋め込みになる
            pos, neg = text_pipe.encode_prompt(prompt=p["en"], negative_prompt="", device=DEVICE,
                                               do_classifier_free_guidance=guidance > 1.0,
                                               max_sequence_length=int(settings.get("max_sequence_length", 512)))
            embeds[p["id"]] = (pos.cpu(), None if neg is None else neg.cpu())
    del text_pipe
    if cuda:
        torch.cuda.empty_cache()
    record["encode_sec"] = round(time.time() - t0)

    # 2. 本体と VAE を読む(VAE は float32。diffusers の Wan の例と同じ)
    vae_cls = getattr(diffusers, index["vae"][1])
    vae = vae_cls.from_pretrained(model_dir, subfolder="vae", torch_dtype=torch.float32, use_safetensors=True,
                                  local_files_only=True)
    pipe = pipeline_cls.from_pretrained(model_dir, vae=vae, text_encoder=None, tokenizer=None,
                                        torch_dtype=torch.bfloat16, use_safetensors=True, local_files_only=True)
    if settings.get("flow_shift") is not None:
        pipe.scheduler = type(pipe.scheduler).from_config(pipe.scheduler.config, flow_shift=float(settings["flow_shift"]))
    record["scheduler"] = {"class": type(pipe.scheduler).__name__,
                           **{k: v for k, v in dict(pipe.scheduler.config).items()
                              if k in ("flow_shift", "use_flow_sigmas", "prediction_type", "solver_order")}}
    pipe.to(DEVICE)
    if cuda:
        torch.cuda.synchronize()
    record["vram_loaded"] = int(torch.cuda.memory_allocated()) if cuda else 0
    record["load_sec"] = round(time.time() - t0)
    _log(t0, f"読み込み: VRAM {record['vram_loaded'] / 1024 ** 3:.1f}GB・{record['load_sec']}秒")
    if cuda:
        torch.cuda.reset_peak_memory_stats()

    def generate(group: str) -> list[dict]:
        out = []
        for p in job["prompts"]:
            pos, neg = embeds[p["id"]]
            started = time.time()
            generator = torch.Generator("cpu").manual_seed(int(job["seed"]))
            frames = pipe(prompt_embeds=pos.to(DEVICE),
                          negative_prompt_embeds=None if neg is None else neg.to(DEVICE),
                          height=int(settings["height"]), width=int(settings["width"]),
                          num_frames=int(settings["num_frames"]), num_inference_steps=int(settings["steps"]),
                          guidance_scale=guidance, generator=generator, output_type="np").frames[0]
            if cuda:
                torch.cuda.synchronize()
            seconds = time.time() - started
            frames = np.asarray(frames, dtype=np.float32)
            if not np.isfinite(frames).all():
                raise FloatingPointError("生成したコマに数でない値があります")
            # 処理の誤り(真っ黒・一色の動画)を取り込み役の機械の検査(lmw/lab/sanity.py)が見つけるための値
            stats = {"pixel_mean": round(float(frames.mean()) * 255, 2), "pixel_std": round(float(frames.std()) * 255, 2)}
            path = os.path.join("/tmp", f"{group}-{p['id']}.mp4")
            encoded = encode_mp4(frames, int(settings["fps"]), path, int(job["max_bytes"]))
            with open(path, "rb") as f:
                raw = f.read()
            blobs[f"{group}-{p['id']}"] = raw
            out.append({"id": f"{group}-{p['id']}", "prompt_id": p["id"], "group": group,
                        "seconds": round(seconds, 1), **encoded, **stats,
                        "sha256": hashlib.sha256(raw).hexdigest()})
            _log(t0, f"{group}/{p['id']}: {encoded['frames']}コマ・生成 {seconds:.0f}秒・{encoded['bytes'] / 1e6:.2f}MB")
        return out

    videos = []
    blobs: dict[str, bytes] = {}
    loras = job.get("loras") or []
    # 3. LoRA を足す前の元のモデル(比べるため。同じプロンプト・シード・ステップ数)
    if loras and job.get("compare_base"):
        videos += generate("base")
    # 4. LoRA を足し込んでから生成する
    merges = []
    for i, lora in enumerate(loras):
        path = os.path.join(base_dir, f"lora{i}", lora["file"])
        merges.append(merge_lora(pipe.transformer, path, float(lora["weight"]), lora.get("alpha"), lora.get("rank")))
        _log(t0, f"LoRA {i}: {merges[-1]['modules']}層を足し込みました(重み {lora['weight']})")
    if merges:
        record["merges"] = merges
    videos += generate("lora" if loras else "model")
    record["vram_peak"] = int(torch.cuda.max_memory_allocated()) if cuda else 0
    record["videos"] = videos
    for vid, raw in blobs.items():
        for index in range(0, len(raw), CHUNK_BYTES):
            yield {"kind": "chunk", "id": vid, "index": index // CHUNK_BYTES, "data": raw[index:index + CHUNK_BYTES]}
    yield {"kind": "record", **plain(record)}

def plain(value):
    """JSON に通して、標準の型だけにする(ホストには torch も diffusers も無い)。"""
    return json.loads(json.dumps(value, default=str))

The job passed to download (as used):

{
  "dir": "video-1790915190",
  "base": {
    "repo": "Wan-AI/Wan2.2-TI2V-5B-Diffusers",
    "revision": "b8fff7315c768468a5333511427288870b2e9635",
    "files": [
      "model_index.json",
      "scheduler/scheduler_config.json",
      "text_encoder/config.json",
      "text_encoder/model-00001-of-00003.safetensors",
      "text_encoder/model-00002-of-00003.safetensors",
      "text_encoder/model-00003-of-00003.safetensors",
      "text_encoder/model.safetensors.index.json",
      "tokenizer/special_tokens_map.json",
      "tokenizer/spiece.model",
      "tokenizer/tokenizer.json",
      "tokenizer/tokenizer_config.json",
      "transformer/config.json",
      "transformer/diffusion_pytorch_model-00001-of-00005.safetensors",
      "transformer/diffusion_pytorch_model-00002-of-00005.safetensors",
      "transformer/diffusion_pytorch_model-00003-of-00005.safetensors",
      "transformer/diffusion_pytorch_model-00004-of-00005.safetensors",
      "transformer/diffusion_pytorch_model-00005-of-00005.safetensors",
      "transformer/diffusion_pytorch_model.safetensors.index.json",
      "vae/config.json",
      "vae/diffusion_pytorch_model.safetensors"
    ]
  },
  "loras": [
    {
      "repo": "Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-few-step",
      "revision": "38a6ec4e8f5b644749d3072bfe1ac383d00951c0",
      "file": "adapter_model.safetensors"
    },
    {
      "repo": "Efficient-Large-Model/LongLive-Plug-Wan2.2-TI2V-5B-cfg",
      "revision": "fa1f9280778aa27c8038fe06e29fb5f2ed6be451",
      "file": "adapter_model.safetensors"
    }
  ]
}

The job passed to run (as used):

{
  "dir": "video-1790915190",
  "pipeline": "WanPipeline",
  "settings": {
    "height": 704,
    "width": 1280,
    "num_frames": 121,
    "fps": 24,
    "steps": 4,
    "guidance": 1.0,
    "flow_shift": 5.0
  },
  "seed": 0,
  "prompts": [
    {
      "id": "boat",
      "en": "a small red paper boat drifting down a clear forest stream, sunlight flickering through the leaves, gentle ripples, realistic"
    },
    {
      "id": "clouds",
      "en": "time-lapse of white clouds rolling over snowy mountain peaks at sunrise, golden light, wide shot"
    }
  ],
  "loras": [
    {
      "file": "adapter_model.safetensors",
      "weight": 1.0,
      "alpha": 128,
      "rank": 128
    },
    {
      "file": "adapter_model.safetensors",
      "weight": 0.5,
      "alpha": 64,
      "rank": 64
    }
  ],
  "compare_base": true,
  "max_bytes": 12000000
}
Package versions in the generating container (full list)
accelerate==1.15.0 aiohappyeyeballs==2.6.1 aiohttp==3.12.7 aiosignal==1.3.2 annotated-doc==0.0.5 anyio==4.15.1 attrs==25.3.0 cbor2==5.7.0 certifi==2026.7.22 charset-normalizer==3.5.2 click==8.5.0 cuda-bindings==13.4.3 cuda-pathfinder==1.8.2 cuda-toolkit==13.0.3.0 diffusers==0.40.0 filelock==4.0.9 frozenlist==1.6.0 fsspec==2026.9.0 ftfy==6.3.1 grpclib==0.4.8 h11==0.16.0 h2==4.2.0 hf-xet==1.6.0 hpack==4.1.0 httpcore==1.0.9 httpx==0.28.1 huggingface_hub==1.33.0 hyperframe==6.1.0 idna==3.20 imageio-ffmpeg==0.6.0 importlib_metadata==9.0.1 Jinja2==3.1.6 markdown-it-py==4.2.0 MarkupSafe==3.0.3 mdurl==0.1.2 mpmath==1.3.0 multidict==6.4.4 networkx==3.7 numpy==2.5.3 nvidia-cublas==13.1.1.3 nvidia-cuda-cupti==13.0.85 nvidia-cuda-nvrtc==13.0.88 nvidia-cuda-runtime==13.0.96 nvidia-cudnn-cu13==9.24.0.43 nvidia-cufft==12.0.0.61 nvidia-cufile==1.15.1.6 nvidia-curand==10.4.0.35 nvidia-cusolver==12.0.4.66 nvidia-cusparse==12.6.3.3 nvidia-cusparselt-cu13==0.8.1 nvidia-nccl-cu13==2.30.7 nvidia-nvjitlink==13.4.92 nvidia-nvshmem-cu13==3.4.5 nvidia-nvtx==13.0.85 packaging==26.3 pillow==12.3.0 pip==25.1.1 propcache==0.3.1 protobuf==6.31.1 psutil==7.2.2 Pygments==2.21.0 PyYAML==6.0.3 regex==2026.9.29 requests==2.34.2 rich==15.0.0 safetensors==0.8.0 sentencepiece==0.2.2 setuptools==84.0.0 shellingham==1.5.4 sympy==1.14.0 tokenizers==0.23.2 torch==2.14.1 tqdm==4.70.1 transformers==5.18.0 triton==3.8.0 typer==0.27.2 typing_extensions==4.16.0 urllib3==2.8.0 uv==0.7.19 wcwidth==0.9.1 wheel==0.45.1 yarl==1.20.0 zipp==4.1.0
Package versions in the downloading container (full list)
aiohappyeyeballs==2.6.1 aiohttp==3.12.7 aiosignal==1.3.2 anyio==4.15.1 attrs==25.3.0 cbor2==5.7.0 certifi==2025.4.26 click==8.5.0 filelock==4.0.7 frozenlist==1.6.0 fsspec==2026.9.0 grpclib==0.4.8 h11==0.16.0 h2==4.2.0 hf-xet==1.6.0 hpack==4.1.0 httpcore2==2.13.1 httpx2==2.13.1 huggingface_hub==2.0.0 hyperframe==6.1.0 idna==3.20 multidict==6.4.4 packaging==26.3 pip==25.1.1 propcache==0.3.1 protobuf==6.31.1 PyYAML==6.0.3 tqdm==4.70.1 truststore==0.10.4 typing_extensions==4.16.0 uv==0.7.19 wheel==0.45.1 yarl==1.20.0

Related Articles

What to Read Next

Sources

Update History

  • 2026-09-30: Changed the title to show what the article covers (VRAM requirements, file list, etc.).
  • 2026-10-02: Added our own measurements: video we generated.
  • 2026-10-02: Changed the title to show what the article covers (VRAM requirements, file list, etc.).