looyifan / GenAD

Created Wed, 02 Apr 2025 11:08:42 +0800 Modified Fri, 11 Apr 2025 15:51:07 +0800
1932 Words

GenAD: Generative End-to-End Autonomous Driving

方案细节

Instance-Centric Scene Representation

Image to BEV

  • 初始化一个 \(H\times W\)的BEV query \(B_{0}\),将摄像头提取的multi-scaled feature \(F\)与之进行deformable cross-attention,得到BEV feature

    $$B=DA(B_{0},F,F)$$

    • \(DA(Q,K,V)\)表示deformable cross-attention

BEV to Map

  • 借鉴VAD的思路,初始化一个learnable query \(M_{0}\),集合BEV feature通过global cross-attention得到地图元素表达 \(M\)

    $$M=CA(M_{0},B,B)$$

BEV to agent

  • 类似地图元素,agent特征的提取方式为:

    $$A=DA(A_{0},B,B)$$

    • \(A_{0}\)是learnable query
    • 这边得到agent特征后,会接一个3D目标检测head进行agent的位置、朝向、种类的解码

Instance-centric scene representation

  • 将上面学到的agent特征和ego query拼在一起, \(I=concat(e,A)\)
  • 学习agent和ego之间的相互影响, \(I=SA(I,I,I)\), \(SA(Q,K,V)\)表示self-attention
  • 学习agent、ego和地图之间的交互, \(I=CA(I,M,M)\)

Trajectory Prior Modeling

  • 自车和障碍物的轨迹都是高度结构化的(连续的),并遵循一定的模式。例如,当车辆以恒定速度行驶时,大多数轨迹都是直线,当车辆右转或左转时,其中一些轨迹是曲率接近恒定的曲线。只有在极少数情况下,轨迹才会是曲折的。考虑到这一点,我们采用变分自动编码器(VAE)架构来学习latent spaec \(Z\),以此来建模trajectory prior。

  • 这里利用一个GT轨迹encoder \(e_{f}\)来建模 \(p(z|\mathsf{\mathbf{T}}(T,f))\),它将未来轨迹映射到latent spaec \(Z\)。encoder \(e_{f}\)输出一组 \(\mu_{f}\)和 \(\sigma_{f}\)来表示GMM的均值和方差。

    • \(e_{f}\)代码实现

      pic

    $$p(z|\mathsf{\mathbf{T}}(T,f)) \thicksim N(\mu_{f},\sigma_{f})$$

  • 分布 \(p(z|\mathsf{\mathbf{T}}(T,f))\)包含未来轨迹的先验,可用于提高障碍物和自车的运动预测和规划的真实性。

Latent Future Trajectory Generation

  • 有了未来轨迹的latent distribution作为先验后,我们需要将未来轨迹从latent spaec \(Z\)中解码出来。最直接的办法是用一个MLP在BEV space下解码出轨迹点,但是这种方法无法模拟障碍物和自车随时间变化产生的交互。为了建模每个实例在不同时间戳之间的时间上的联系,对联合概率分布 \(p(\mathsf{\mathbf{T}}(T,f)|z)\)进行分解:

    $$p(\mathsf{\mathbf{T}}(T,f)|z)=p(w^{T+1}|z^{T})\cdot p(w^{T+2}|w^{T+1},z^{T})…p(w^{T+f}|w^{T+1},…,w^{T+f-1},z^{T})$$

  • 我们从分布 \(N(\mu_{f},\sigma_{f})\)中采样一组 \(\mu_{f}\)和\(\sigma_{f}\)作为当前时刻的 \(z^{T}\)的latent state。不同于其他方法中一次性将轨迹decode出来,这边是采用分步解码的方法。引入decoder \(d_{w}\)(MLP)从latent state中解码轨迹点。 \(p(w^{T+1}|z^{T})\)通过 \(w=d_{w}(z)\)来表示。

    • 采样代码实现: pic
  • 我们通过GRU模型来建模状态随时间的演化。 \(z^{T+1}=g(z^{T})\),然后再解码下个时刻的轨迹点, \(w^{T+1}=g(z^{T+1})\), \(T+f\)时刻同理。

    pic

    • 从distribution里面采样出的latent state进行future state的预测

      pic

    • 这边的self.predict_model函数里包含了GRU的实现,但是从代码上看,没有按照T循环调用GRU,而是设计了一个4层(layer_num=4)的GRU模拟状态随时间的推演。

      pic

      pic

    • decoder是按照T循环解码出的轨迹点(下面的for循环),这里的self.ego_fut_decoder是个MLP,将GRU输出的latent future state转化为轨迹点

      pic

Generative End-to-End Autonomous Driving

  • 轨迹loss

    $$J_{prior}=L_{traj}(\hat{T_{e}},T_{e})+\frac{1}{N_{a}}L_{traj}(\hat{T_{a}},T_{a})+\lambda_{c}L_{focal}(\hat{C_{a}},C_{a})$$

    • \(L_{traj}()\)衡量两条轨迹的L1 loss。 \(N_{a}\)是agent的数量, \(C_{a}\)是agent的预测类别, \(T_{a}\)是agent的预测轨迹。
  • 将上面得到的instance tokens \(I\)通过encoder \(e_{i}\)映射到latent space \(Z\),也类似地输出一组输出一组 \(\mu_{i}\)和 \(\sigma_{i}\)。

    • \(e_{i}\)代码实现:

      pic

    $$p(z|I)\thicksim N(\mu_{i},\sigma_{i})$$

  • 通过KL散度衡量 \(p(z|I)\)和GT轨迹 \(p(z|\mathsf{\mathbf{T}}(T,f))\)之间的差异

    $$J_{plan}=D_{KL}(p(z|I),p(z|\mathsf{\mathbf{T}}(T,f)))$$ pic

    • KL散度衡量的就是上面的output_distribution中present和future的分布差异
  • 总loss

    $$J_{GenAD}=J_{prior}+\lambda_{plan}J_{plan}+\lambda_{map}J_{map}+\lambda_{det}J_{det}$$

  • 在infer阶段,弃用future trajectory encoder(因为没有GT),从 \(p(z|I)\)中采样latent state,作为轨迹生成模块的输入

    pic