Geo-Align: Video Generation Alignment via Metric Geometry Reward

Paper: arXiv:2605.23903 Code: LiZizun/GeoAlign Code reference: main @ 0465cfb8 (2026-05-25)

1. Motivation (研究动机)

Geo-Align 关注的是 video retake / camera-controlled video re-rendering:给定一段真实 conditioning video 和一条目标相机轨迹,生成沿这条新轨迹观察到的 novel-view video。这个任务比“单张首帧 + 相机轨迹”的 camera-controlled generation 更难,因为输入视频本身包含动态物体、遮挡、背景变化和真实相机运动;模型既要保留原视频的内容与时序,又要严格跟随新的 3D camera path。

当前方法的核心瓶颈有两个。第一是 paired multi-view real-world video data 极度稀缺:ReCamMaster、ReDirector 这类 implicit-camera-condition 方法主要依赖 Unreal Engine 等合成数据做 SFT;TrajectoryCrafter、CogNVS 这类 reconstruction / warping 方法则依赖点云重建、warp 和补全。二者都很难在 in-the-wild 视频上保持稳定泛化。第二是 metric-scale camera controllability 不可靠:只要监督数据或 reward 没有真实度量尺度,模型可能生成“形状看起来还可以、但移动速度明显不对”的视频,例如面对快速目标轨迹时输出慢速漂移,从而在视觉上没有明显破绽但在物理轨迹上失败。

这篇论文想解决的具体问题是:不再要求 paired target video,而是用 RL 直接优化“生成视频能否被一个 metric 3D evaluator 反推出正确相机轨迹”。如果这个问题解决,video generation 的相机控制就可以从稀缺合成多视角监督,转向更大规模的真实视频条件 + 可验证几何 reward;这对 film production、game-engine-style camera retake、world simulation 中的可控视角生成都很关键。

Figure 1 解读:输入是一段 conditioning video,目标是一条用户指定或采样得到的 target camera trajectory;Geo-Align 不是简单复制原视角,而是沿目标轨迹重新渲染 novel-view video。这个 teaser 说明论文的任务边界:内容来自输入视频,视角运动来自目标轨迹,质量标准同时包含视觉保真和 camera path adherence。

2. Idea (核心思想)

核心 insight 是:camera trajectory 是可以被外部 3D estimator 验证的结构化属性,因此可以作为 RL reward,而不必依赖 paired target video 做逐像素监督。Geo-Align 用 MapAnything 从生成视频中估计 metric camera poses,再把估计轨迹与目标轨迹做 translation / rotation 误差比较;同时加入 VideoAlign 与 HPSv3 防止几何 reward 把模型推向低质或 reward hacking 的视频。

与 ReDirector 这类 SFT 方法的根本差异在于:ReDirector 需要合成 paired multi-view data 告诉模型“这个输入在目标轨迹下应该长什么样”,而 Geo-Align 只需要真实 conditioning video 和一条可度量的目标轨迹;目标视频不存在也可以训练,因为 reward 来自 generated rollout 本身的 3D 可验证性。与 TrajectoryCrafter / CogNVS 的 reconstruction-warping 路线相比,Geo-Align 不把 3D reconstruction 作为显式生成流程的一部分,而是把 metric reconstruction 模型放在 reward side,用它评价而不是直接渲染。

3. Method (方法)

3.1 Overall framework:从 conditioning video 到 RL rollout

任务形式化为:conditioning video 为 ,文本 prompt 为 ,目标相机轨迹为 。预训练 video world model 在 flow matching / diffusion 采样过程中接收 noisy latent 、timestep 和条件集合 并预测 velocity / denoised representation: RL 目标不是匹配某个 ground-truth target video,而是最大化生成视频 的 composite reward:

Figure 2 解读:pipeline 分三步。第一步从真实 CityWalk 视频取 conditioning video,同时从 camera-annotated synthetic / gaming data 取 target trajectory,并做 metric-aware rescaling;第二步用当前策略模型生成一组 rollout videos;第三步用 MapAnything 估计每个 rollout 的 camera trajectory,得到 geometry reward,再与 VideoAlign / HPSv3 的 perceptual reward 一起进入 GRPO 优化。Figure 2 的关键是把“无 paired target video”变成可训练:target video 缺失,但 target camera path 是已知的、generated rollout 的 camera path 是可估计的。

直觉上,Geo-Align 能工作的原因是 camera control failure 往往不是单帧视觉语义错误,而是一个跨帧几何约束错误:背景、前景和视角之间的相对运动必须共同支持同一条 camera path。MapAnything 这样的 metric 3D estimator 把这种跨帧约束压缩成 pose sequence,RL 可以直接惩罚后期漂移、旋转误差和尺度不匹配;而 aesthetic reward 保留预训练视频模型的视觉先验,避免模型为了让 3D estimator 满意而生成纹理差、运动怪异或结构崩坏的视频。

3.2 Verifiable Geometry Reward:用 metric 3D evaluator 直接打相机误差

Geo-Align 的几何 reward 基于 MapAnything。给定生成视频 ,MapAnything 输出估计 translation 和 rotation ;目标轨迹提供 。论文定义 translation discrepancy 与 rotation discrepancy: 这里 是随时间单调增加的 frame weight。作者的经验观察是:预训练视频模型在前几帧通常还能贴住 conditioning trajectory,但后半段更容易累积 drift;因此让 ,可以把 RL gradient 更集中地分配给长期控制瓶颈。

released code 中 fastvideo/models/reward_model/geo_reward.py 的实现更具体:先把 reference / generated poses 都转换成相对首帧的 camera-to-world pose;translation error 被 clamp 到最大 10;rotation error 用 ;per-frame reward 是负误差,并用 torch.linspace(0.5, 1.5, N) 做时间加权平均。换言之,代码实际返回的是 ,越接近 0 越好,NaN 会回退成负分。

3.3 Perceptual / Aesthetic Reward:防止几何 reward hacking

只优化 camera trajectory 会带来一个风险:模型可能生成对 3D estimator 友好但视觉很差的结果,例如纹理异常、运动不自然、形状扭曲或高频细节崩坏。论文加入两类视觉 reward:

  • VideoAlign:sequence-level evaluator,输出 visual quality score 和 motion quality score ;released code 把它们记为 vq_rewardmq_reward
  • HPSv3:single-frame perceptual / aesthetic evaluator;released code 在 fastvideo/models/reward_model/utils.py 中每隔 4 帧采样一次,对正向 prompt 与负向 prompt 分别打分,并使用 pos_rewards - 2 * neg_rewards,再用 0.5 \rightarrow 1.5 的时间权重平均。

这个组合使 reward 同时约束“轨迹对不对”和“视频像不像好视频”。Geo reward 解决的是 camera path adherence,VideoAlign / HPSv3 解决的是视觉和运动质量;两者缺一都会留下明显 failure mode。

3.4 Flow Matching Optimization via GRPO:多 reward 在 advantage 空间聚合

Geo-Align 使用 GRPO 而不是标准 PPO。原因是 video generation 的 rollout 长、显存成本高,PPO 的 value model baseline 代价过大;GRPO 用同一条件下的 个 sampled rollouts 形成组内相对优势,从而去掉 value model。

论文写法中,每个 reward dimension 在 group 内标准化: 总优势为: 最终 clipped policy objective 为: 其中 是 policy probability ratio, 是 clipping hyperparameter, 是 timestep-aware policy loss weight。论文还强调移除 KL penalty,以便在 OOD target camera trajectories 上增加探索。

released code 的 scripts/finetune/finetune_grpo_recam.sh 设定 --reward_model Geo_VideoAlign_HPSv3--multi_reward_mix advantage_aggr--num_generations 12--kl_coeff 0.0--clip_range 1e-4--reweight_policy_loss--training_strategy part--flow_grpo_sampling。在 fastvideo/train_grpo_recam.py 中,advantage_aggr 分支会先对每个 reward key 分别做 group normalization,再按归一化后的 reward weights 相加;原始权重为 geo translation 1.0、geo rotation 1.0、HPSv3 0.5、motion quality 1.0、visual quality 1.0,归一化后约为 0.222 / 0.222 / 0.111 / 0.222 / 0.222。

论文公式与 released code 实现差异:论文称使用 LongCat Video 的 max group standard deviation 策略,即用 抑制低方差 reward 噪声;但当前 launch script 同时使用 --multi_reward_mix advantage_aggr,而 train_grpo_recam.pyadvantage_aggr 分支只用本 reward dimension 的 group_rewards.std()+1e-8,没有调用 gather_tensor(group_std).max()--use_std_max 只在 reward_aggr 分支中实际生效。因此笔记中的伪代码按 released code 写,并把论文声称的稳定化策略作为 paper-code gap 记录。

3.5 Metric-Aware Data Sampling Pipeline:真实视频条件 + 合成轨迹目标

RL 的关键好处是 target video 可以不存在。Geo-Align 因此构造了一个 hybrid data pipeline:conditioning inputs 来自 in-the-wild CityWalk 视频,覆盖室内、室外、静态和动态场景;由于这些真实视频未必有标定 camera poses,源轨迹由 MapAnything 估计。target trajectories 则从 OmniWorld gaming dataset 采样,因为它提供丰富且复杂的 camera motions。

直接使用 gaming trajectory 会有两个问题:没有绝对物理尺度,且可能有过快旋转。论文先计算 raw target trajectory 的最大逐帧 translation / rotation speed: 然后从 truncated Gaussian 采样目标速度上界: 缩放系数为: 并得到 physical-aware target trajectory: 这样做的作用不是让合成轨迹变“真实视频标签”,而是把 camera motion 的速度范围拉回可学习、可优化、物理上更合理的区域,减少 RL rollout 早期就因为目标轨迹过激而完全崩掉。

released code 的 fastvideo/dataset/hybriddataset.py 对这个思想的实现是:每个样本先从 CityWalk 取 cond_videotraj_cond 和 prompt,再随机从 game dataset 取 traj_tgttgt_video,最后返回 unpaired hybrid result。论文中的 truncated Gaussian 缩放公式主要出现在论文描述中;当前公开代码的具体 scale 参数与最终 sample count 没有在 launch script 中完整暴露。

3.6 Pseudocode(基于 released code)

Geometry reward

import torch
 
 
def compute_geo_reward(ref_pose_19d, generated_video, map_anything):
    pred = map_anything.infer(prepare_tensor_inputs(generated_video), memory_efficient_inference=True)
    gen_poses = torch.stack([item["camera_poses"] for item in pred], dim=1).float()
    ref_poses = restore_c2w_matrix(ref_pose_19d)
 
    ref_rel = torch.linalg.inv(ref_poses[:, :1]) @ ref_poses
    gen_rel = torch.linalg.inv(gen_poses[:, :1]) @ gen_poses
 
    trans_err = torch.linalg.norm(gen_rel[:, :, :3, 3] - ref_rel[:, :, :3, 3], dim=-1)
    trans_err = torch.clamp(trans_err, max=10.0)
 
    r_diff = ref_rel[:, :, :3, :3].transpose(-1, -2) @ gen_rel[:, :, :3, :3]
    cos = torch.clamp((torch.diagonal(r_diff, dim1=-2, dim2=-1).sum(-1) - 1.0) / 2.0, -1 + 1e-6, 1 - 1e-6)
    rot_err = torch.acos(cos)
 
    weights = torch.linspace(0.5, 1.5, generated_video.shape[1], device=generated_video.device)[None]
    return {
        "geo_trans": [(-(trans_err * weights).mean(dim=1)).item()],
        "geo_rot": [(-(rot_err * weights).mean(dim=1)).item()],
    }

Hybrid CityWalk + game trajectory sample

import numpy as np
 
 
def build_hybrid_sample(citywalk_dataset, game_dataset, index):
    citywalk = citywalk_dataset.get_data(index)
    if citywalk is None:
        return None
 
    game = None
    for _ in range(citywalk_dataset.max_refetch):
        game = game_dataset.get_data(np.random.randint(0, len(game_dataset)))
        if game is not None:
            break
    if game is None:
        return None
 
    return {
        "cond_video": citywalk["cond_video"],
        "traj_cond": citywalk["traj_cond"],
        "prompt": citywalk["prompt"],
        "tgt_video": game["tgt_video"],
        "traj_tgt": game["traj_tgt"],
        "tgt_path": game["tgt_path"],
    }

Multi-reward advantage aggregation

import torch
 
 
def aggregate_advantages(rewards_by_name, reward_weights, num_generations):
    model_advantages = {}
    for name, rewards in rewards_by_name.items():
        advantages = torch.zeros_like(rewards)
        groups = len(rewards) // num_generations
        for group_idx in range(groups):
            start = group_idx * num_generations
            end = (group_idx + 1) * num_generations
            group_rewards = rewards[start:end]
            mean = group_rewards.mean()
            std = group_rewards.std() + 1e-8
            advantages[start:end] = (group_rewards - mean) / std
        model_advantages[name] = advantages
 
    merged = torch.zeros_like(next(iter(model_advantages.values())))
    for name, advantages in model_advantages.items():
        merged = merged + reward_weights[name] * advantages
    return merged

GRPO policy update for flow matching timesteps

import torch
 
 
def grpo_update_step(model, optimizer, samples, train_timesteps, clip_range, kl_coeff, sigma_schedule):
    total_loss = 0.0
    for sample in samples:
        advantages = sample["advantages"]
        for t_idx in train_timesteps:
            new_log_probs = model.log_prob(sample, timestep=t_idx)
            old_log_probs = sample["log_probs"][:, t_idx]
            ratio = torch.exp(new_log_probs - old_log_probs)
 
            unclipped = -advantages * ratio
            clipped = -advantages * torch.clamp(ratio, 1.0 - clip_range, 1.0 + clip_range)
            policy_loss = torch.maximum(unclipped, clipped).mean()
 
            kl_loss = 0.5 * ((new_log_probs - old_log_probs) ** 2).mean()
            sigma = sigma_schedule[t_idx]
            next_sigma = sigma_schedule[t_idx + 1]
            policy_weight = torch.sqrt(sigma / ((1.0 - sigma) * (sigma - next_sigma)))
 
            loss = policy_weight * policy_loss + kl_coeff * kl_loss
            loss.backward()
            total_loss = total_loss + loss.item()
 
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
    optimizer.step()
    optimizer.zero_grad(set_to_none=True)
    return total_loss

3.7 Code-to-paper mapping

Code reference: main @ 0465cfb8 (2026-05-25) — pseudocode and mapping based on this commit

Paper ConceptSource FileKey Class/Function
Project page / release entryREADME.md, assets/checkpoint / dataset / reward-model instructions
GRPO training loopfastvideo/train_grpo_recam.pytrain_one_step, main, reward aggregation, clipped policy loss
Launch configscripts/finetune/finetune_grpo_recam.shtorchrun ... fastvideo/train_grpo_recam.py with paper-specific args
Geometry rewardfastvideo/models/reward_model/geo_reward.pyGeo_reward, DifferentiableGeometryReward, restore_c2w_matrix
Reward orchestrationfastvideo/models/reward_model/utils.py_compute_single_reward, compute_reward
Hybrid data samplingfastvideo/dataset/hybriddataset.pyHybridCityWalkGameDataset.get_data
Real-video condition sourcefastvideo/dataset/citywalk_v2.pyCityWalkRecamDataset.get_data
Synthetic/game target sourcefastvideo/dataset/game_dataset.py, game_dataset_v2.pyGameRecamDataset, trajectory / RGB loading
Progressive timestep windowfastvideo/utils/grpo_states.pyGRPOTrainingStates
Flow sampling utilitiesfastvideo/utils/sampling_recam.pyflow_grpo_step, run_sample_step

4. Experimental Setup (实验设置)

Datasets and scale

  • Training conditioning videos:CityWalk,用作真实 in-the-wild conditioning video 来源;论文说明其覆盖室内/室外、静态/动态场景,但论文未详细说明最终训练 clip 数量。
  • Training target trajectories:OmniWorld gaming dataset,用作 camera-annotated target trajectory 来源;论文未详细说明最终训练 trajectory / clip 采样条数,released repo 只公开 dataset core logic 与 file lists。
  • Evaluation:DAVIS 中 50 个视频,每个视频应用 10 条 ReCamMaster camera trajectories,构成 500 个 test cases;片段长度从几十帧到接近 100 帧不等。
  • Trajectory length / resolution:生成 frames,分辨率 ;TrajectoryCrafter 和 CogNVS 被限制到最多 49 frames,以避免长视频推理退化。

Baselines

  • Explicit warping / reconstruction:TrajectoryCrafter、CogNVS。
  • Implicit camera extrinsics condition:ReCamMaster、ReDirector。ReDirector 也是 Geo-Align 的 pretrained foundation / baseline model。

Metrics

  • Visual Quality:VBench 维度,包括 Subject Consistency、Background Consistency、Aesthetic Quality、Imaging Quality、Temporal Flickering、Motion Smoothness。
  • Geometric Consistency:Dyn-MEt3R(越高越好)与 MEt3R(越低越好),用于衡量跨帧几何一致性 / input-video consistency。
  • Camera Accuracy:ViPE 估计 camera parameters 后计算 TransErr(越低越好)与 RotErr(越低越好)。在不同 camera speed 对比中,论文排除 ViPE 估计失败的样本以避免 featureless frames 影响统计。

Training config

论文报告的设置:基础模型是基于 Wan2.1 1.3B 的 ReDirector;MapAnything 作为 frozen 3D evaluator;只更新 self-attention layers,其他权重冻结;GRPO group size rollouts per condition;flow matching 采样离散为 denoising timesteps;训练 140 RL iterations,constant learning rate ;post-training 使用 64 NVIDIA A800 GPUs,约 130 小时。Ablation 表说明对应消融模型训练 140 steps on 16 A800 GPUs。

released launch script 的实际 override 需要单独记录:scripts/finetune/finetune_grpo_recam.sh 当前设定 --max_train_steps 300--learning_rate 1e-5--gradient_accumulation_steps 12--train_batch_size 1--num_generations 12--kl_coeff 0.0--clip_range 1e-4--h 480 --w 832 --t 81--sampling_steps 25--training_strategy part--group_size 4(sliding timestep window size)、--iters_per_group 25--reward_model Geo_VideoAlign_HPSv3。GPU 数由 SLURM 环境变量 SLURM_NNODESGPUS_PER_NODE 决定,没有在脚本中硬编码为 64。

论文公式与 released code 实现差异:论文 §Experiments 报告 140 iterations、LR 、64 A800;当前 release 的实际 launch script 是 300 steps、LR 1e-5,GPU 数依赖 SLURM 环境变量。复现实验时应以具体 script / run config 为准,并把论文中的数值视为 paper-reported setting。

5. Experimental Results (实验结果)

5.1 Main quantitative results on DAVIS

下面表格列顺序为:Subject、Background、Aesthetic、Imaging、Temporal、Motion、Dyn-MEt3R、MEt3R、TransErr、RotErr。

MethodTypeSubj ↑Bg ↑Aes ↑Img ↑Temp ↑Motion ↑Dyn ↑MEt3R ↓Trans ↓Rot ↓
CogNVSexplicit warping0.91340.93420.48300.63980.94600.97680.80370.27360.03676.9499
TrajectoryCrafterexplicit warping0.91450.93310.52520.63940.94320.98000.82440.21360.029310.4340
ReCamMasterimplicit condition0.90500.91900.51460.66110.96440.98670.79710.34850.02452.3175
ReDirectorimplicit condition0.90980.91500.51410.68210.95370.98560.84970.31300.01491.4635
Geo-Alignimplicit condition0.91510.91790.51680.68420.95480.98620.85730.30770.01291.3645

主要结论:Geo-Align 相比 ReDirector 在 camera accuracy 上提升最直接,TransErr 从 0.0149 降到 0.0129,RotErr 从 1.4635 降到 1.3645;Dyn-MEt3R 从 0.8497 升到 0.8573,说明几何一致性也提高。相比 explicit warping 方法,Geo-Align 的 RotErr 明显低于 TrajectoryCrafter 的 10.4340 和 CogNVS 的 6.9499,表明生成模型路线在长视频相机控制上更适合配合 RL reward 优化。

Figure 3 解读:DAVIS qualitative comparison 展示了 Geo-Align 在大幅相机运动下保持前景主体与背景几何关系的能力。论文指出 ReCamMaster / ReDirector 等 baseline 容易出现 foreground deformation、background distortion 或 structure collapse,而 Geo-Align 因为在训练中被 geometry reward 反复惩罚 camera-path mismatch,能更稳定地维持前景-背景的相对运动。

5.2 Robustness under different camera speeds

MethodSpeedSubj ↑Bg ↑Aes ↑Img ↑Temp ↑Motion ↑Dyn ↑MEt3R ↓Trans ↓Rot ↓
ReDirector1.00.91300.91430.51680.67550.95400.98570.85550.32060.01401.3689
Geo-Align1.00.91780.91740.51910.67820.95520.98620.86380.31500.01231.2156
ReDirector1.50.89220.90040.50850.67130.94860.98380.83680.33540.01571.5476
Geo-Align1.50.89830.90350.51110.67410.94950.98440.84580.33070.01291.5491
ReDirector2.00.87260.88810.49840.66240.94570.98200.82490.34960.01611.9246
Geo-Align2.00.87830.89110.50170.66680.94690.98280.83380.34440.01531.8821

camera speed 越大,两个模型都退化,但 Geo-Align 在 1.0、1.5、2.0 三档下多数指标持续优于 ReDirector。特别是 speed 2.0 时,TransErr 从 0.0161 降到 0.0153、RotErr 从 1.9246 降到 1.8821,说明 metric-aware reward 对复杂轨迹有一定 robustness,但不是完全解决高速相机运动。

Figure 4 解读:CityWalk visualization 不是和 baseline 的逐列对比,而是展示真实 conditioning video 经过目标轨迹重渲染后的效果。它支撑了论文的数据论点:训练和展示可以围绕真实场景视频展开,而不需要每个真实视频都有 synchronized multi-view target ground truth。

Figure 5 解读:这个附加 qualitative comparison 把输入视频、ReDirector 输出和 Geo-Align 输出按行排列。它展示的是同一 conditioning content 下,RL 后的模型更少出现背景-主体相对运动不一致的问题;这与 Table 1 中 Dyn-MEt3R 和 TransErr / RotErr 的提升一致。

5.3 Ablation: geometry reward 是否真的必要

Reward settingSubj ↑Bg ↑Aes ↑Img ↑Temp ↑Motion ↑Dyn ↑MEt3R ↓Trans ↓Rot ↓
Baseline ReDirector0.90980.91500.51410.68210.95370.98560.84970.31300.01491.4635
Video quality reward only0.91300.91740.51450.68180.95490.98610.85310.31170.01471.6082
Full reward0.91470.91810.51630.68280.95480.98630.85500.30820.01401.3895

只用 video quality reward 能略微提高视觉指标和 TransErr,但 RotErr 从 1.4635 变差到 1.6082,说明 aesthetic reward 不会自动带来相机旋转控制。加入 geometry reward 后,RotErr 降到 1.3895,TransErr 降到 0.0140,Dyn-MEt3R 升到 0.8550,同时视觉指标也大多最好;这正好验证了论文的核心主张:camera controllability 需要显式 metric geometry reward。

5.4 Failure cases and limitations

Figure 6 解读:作者明确给出 failure case:当目标轨迹包含过快旋转、大幅平移,或前景物体离相机很近并占据大面积时,模型仍可能失败。这说明 Geo-Align 改善的是 reward-guided alignment,而不是让基础视频模型获得任意 3D scene representation;当可见内容不足、遮挡强或 motion 超出训练分布时,MapAnything reward 和生成模型本身都可能不稳定。

总体结论:Geo-Align 证明了 camera-controlled video retake 可以用 RL + verifiable metric reward 做 alignment,不必完全依赖 paired synthetic multi-view data。最强证据来自三处:主表中相机误差和几何一致性的整体提升,不同 camera speeds 下持续优于 ReDirector,以及 ablation 中 full reward 明显优于 video-quality-only reward。主要 caveat 是训练细节在论文与 released script 之间存在差异,并且方法仍受限于基础模型、MapAnything pose estimation 和极端相机运动的可靠性。