参考github网址:https://github.com/OpenDriveLab/UniAD/tree/v2.0

参考readme:https://gitcode.com/Ascend/DrivingSDK/blob/master/model_examples/UniAD/README.md

Package                  Version          Editable project location
------------------------ ---------------- ----------------------------
absl-py                  2.3.1
addict                   2.4.0
aiohappyeyeballs         2.6.1
aiohttp                  3.13.3
aiosignal                1.4.0
asc_opc_tool             0.1.0
asttokens                3.0.1
async-timeout            5.0.1
attrs                    25.4.0
auto_tune                0.1.0
backcall                 0.2.0
black                    25.11.0
cachetools               6.2.4
casadi                   3.6.7
certifi                  2022.12.7
charset-normalizer       2.1.1
click                    8.1.8
contourpy                1.3.0
cycler                   0.12.1
dataflow                 0.0.1
decorator                5.2.1
descartes                1.1.0
einops                   0.8.1
exceptiongroup           1.3.1
executing                2.2.1
filelock                 3.19.1
fire                     0.7.1
flake8                   7.3.0
fonttools                4.60.2
frozenlist               1.8.0
fsspec                   2025.10.0
future                   1.0.0
google-api-core          2.29.0
google-auth              2.47.0
google-cloud-bigquery    3.40.0
google-cloud-core        2.5.0
google-crc32c            1.8.0
google-resumable-media   2.8.0
googleapis-common-protos 1.72.0
grpcio                   1.76.0
grpcio-status            1.76.0
hccl                     0.1.0
hccl_parser              0.1
idna                     3.4
ImageIO                  2.37.2
importlib_metadata       8.7.1
importlib_resources      6.5.2
iniconfig                2.1.0
ipython                  8.12.3
jedi                     0.19.2
Jinja2                   3.1.6
joblib                   1.5.3
kiwisolver               1.4.7
llm_datadist             0.0.1
llm_datadist_v1          0.0.1
llvmlite                 0.36.0
lyft-dataset-sdk         0.0.8
Markdown                 3.9
MarkupSafe               2.1.5
matplotlib               3.9.4
matplotlib-inline        0.2.1
mccabe                   0.7.0
mmcls                    0.25.0
mmcv-full                1.7.2
mmdet                    2.26.0
mmdet3d                  1.0.0rc6         /home/ws/torch/mmdetection3d
mmsegmentation           0.29.1
motmetrics               1.1.3
mpmath                   1.3.0
msobjdump                0.1.0
multidict                6.7.0
mx_driving               1.0.0+git595c51a
mypy_extensions          1.1.0
narwhals                 2.15.0
networkx                 2.5
ninja                    1.13.0
numba                    0.53.0
numpy                    1.23.0
nuscenes-devkit          1.2.0
op_compile_tool          0.1.0
op_gen                   0.1
op_test_frame            0.1
opc_tool                 0.1.0
opencv-python            4.8.0.76
opencv-python-headless   4.11.0.86
packaging                25.0
pandas                   1.2.2
parameterized            0.9.0
parso                    0.8.5
pathspec                 1.0.3
pexpect                  4.9.0
pickleshare              0.7.5
pillow                   11.3.0
pip                      25.3
platformdirs             4.4.0
plotly                   6.5.2
pluggy                   1.6.0
plyfile                  1.1.3
prettytable              3.16.0
prompt_toolkit           3.0.52
propcache                0.4.1
proto-plus               1.27.0
protobuf                 6.33.4
psutil                   7.2.1
ptyprocess               0.7.0
pure_eval                0.2.3
pyasn1                   0.6.2
pyasn1_modules           0.4.2
pycocotools              2.0.11
pycodestyle              2.14.0
pyflakes                 3.4.0
Pygments                 2.19.2
pyparsing                3.3.2
pyquaternion             0.9.9
pytest                   8.4.2
python-dateutil          2.9.0.post0
pytokens                 0.4.0
pytorch-lightning        1.2.5
pytz                     2025.2
PyWavelets               1.6.0
PyYAML                   6.0.3
requests                 2.28.1
rsa                      4.9.1
schedule_search          0.0.1
scikit-image             0.19.3
scikit-learn             1.6.1
scipy                    1.13.1
seaborn                  0.12.2
setuptools               80.9.0
shapely                  2.0.7
show_kernel_debug_data   0.1.0
six                      1.17.0
stack-data               0.6.3
sympy                    1.14.0
te                       0.4.0
tensorboard              2.20.0
tensorboard-data-server  0.7.2
termcolor                3.1.0
terminaltables           3.1.10
threadpoolctl            3.6.0
tifffile                 2024.8.30
tomli                    2.4.0
torch                    2.1.0+cpu
torch-npu                2.1.0.post17
torchaudio               2.1.0+cpu
torchmetrics             0.6.2
torchvision              0.16.0+cpu
tqdm                     4.67.1
traitlets                5.14.3
trimesh                  2.35.39
typing_extensions        4.15.0
tzdata                   2025.3
urllib3                  1.26.13
wcwidth                  0.2.14
Werkzeug                 3.1.5
wheel                    0.45.1
yapf                     0.40.1
yarl                     1.22.0
zipp                     3.23.0

环境搭建

  1. 拉起镜像:

# 910B
docker pull --platform=amd64 swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:8.3.rc2-910b-ubuntu22.04-py3.11

#910C
# docker pull --platform=arm64 swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:8.3.rc2-a3-openeuler24.03-py3.11
  1. 启动容器&进入容器

docker run -it -d --net=host --shm-size=256g \
    --user root \
    --privileged \
    --name UniAD_v2 \
    --device=/dev/davinci_manager \
    --device=/dev/hisi_hdc \
    --device=/dev/devmm_svm \
    --device=/dev/davinci0 \
    --device=/dev/davinci1 \
    --device=/dev/davinci2 \
    --device=/dev/davinci3 \
    --device=/dev/davinci4 \
    --device=/dev/davinci5 \
    --device=/dev/davinci6 \
    --device=/dev/davinci7 \
    --device=/dev/davinci8 \
    --device=/dev/davinci9 \
    --device=/dev/davinci10 \
    --device=/dev/davinci11 \
    --device=/dev/davinci12 \
    --device=/dev/davinci13 \
    --device=/dev/davinci14 \
    --device=/dev/davinci15 \
    -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \
    -v /usr/local/sbin:/usr/local/sbin:ro \
    -v /home/ws:/home/ws \
    -v /root/.cache:/root/.cache \
    swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:8.3.rc2-910b-ubuntu22.04-py3.11 bash
    
  #注意黄色镜像:区分镜像a2、a3
    
#进入容器
docker exec -it UniAD_v2 bash

安装miniconda

  1. 安装miniconda

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \
    bash miniconda.sh -b && \
    rm -f miniconda.sh && \
    echo "export PATH=/root/miniconda3/bin:\$PATH" >> ~/.bashrc && \
    echo "source /root/miniconda3/etc/profile.d/conda.sh" >> ~/.bashrc && \
    /root/miniconda3/bin/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main && \
    /root/miniconda3/bin/conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r && \
    /root/miniconda3/bin/conda init bash

x86用:https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

arm用:https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh

  1. 创建conda环境

conda create -n uniad2.0 python=3.8 -y
conda activate uniad2.0

安装torch, torch-npu

x86用:

pip install torch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 --index-url https://download.pytorch.org/whl/cpu
wget https://gitcode.com/Ascend/pytorch/releases/download/V7.2.0.1-pytorch2.1.0/torch_npu-2.1.0.post18-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

arm:


pip install torch==2.1.0 wheel


# arm wget https://gitcode.com/Ascend/pytorch/releases/download/V7.2.0.1-pytorch2.1.0/torch_npu-2.1.0.post18-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl && \ pip install torch_npu-2.1.0.post18-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

安装DrivingSDK(⚠️注意:DrivingSDK、mmdet3d、mmcv、模型源码UniAD在同级目录下)


git clone https://gitcode.com/Ascend/DrivingSDK.git cd DrivingSDK pip3 install -r requirements.txt bash ci/build.sh --python=3.8 cd dist pip3 install mx_driving-1.0.0+git{commit_id}-cp{Python_version}-linux_{arch}.whl # 910C机器openeuler24.03编译失败修复方法 # https://gitcode.com/xiao-shaoning/mxDriving/blob/master/ci/docker/docker_env.md#%E9%97%AE%E9%A2%98%E4%BF%AE%E5%A4%8D

源码安装mmdet3d


diff --git a/mmdet3d/__init__.py b/mmdet3d/__init__.py index 643c39c9..7455d25f 100644 --- a/mmdet3d/__init__.py +++ b/mmdet3d/__init__.py @@ -19,7 +19,7 @@ def digit_version(version_str): mmcv_minimum_version = '1.5.2' -mmcv_maximum_version = '1.7.0' +mmcv_maximum_version = '1.8.0' mmcv_version = digit_version(mmcv.__version__)


git clone -b v1.0.0rc6 https://github.com/open-mmlab/mmdetection3d.git cp -f ../mmdet3d.patch mmdetection3d #mmdet3d.patch为上方文件 cd mmdetection3d git apply --reject --whitespace=fix mmdet3d.patch pip install -r requirements/runtime.txt pip install -e .

安装mmcv

mmcv.patch

diff --git a/mmcv/ops/modulated_deform_conv.py b/mmcv/ops/modulated_deform_conv.py
index 8a348e83..dcb8c087 100644
--- a/mmcv/ops/modulated_deform_conv.py
+++ b/mmcv/ops/modulated_deform_conv.py
@@ -1,4 +1,5 @@
 # Copyright (c) OpenMMLab. All rights reserved.
+# Copyright 2024 Huawei Technologies Co., Ltd
 import math
 from typing import Optional, Tuple, Union
 
@@ -322,8 +323,9 @@ class ModulatedDeformConv2dPack(ModulatedDeformConv2d):
 
     def forward(self, x: torch.Tensor) -> torch.Tensor:  # type: ignore
         out = self.conv_offset(x)
-        o1, o2, mask = torch.chunk(out, 3, dim=1)
-        offset = torch.cat((o1, o2), dim=1)
+        len1 = ((out.shape[1] + 2) // 3) * 2
+        len2 = out.shape[1] - len1
+        offset, mask = torch.split(out, [len1, len2], dim=1)
         mask = torch.sigmoid(mask)
         return modulated_deform_conv2d(x, offset, mask, self.weight, self.bias,
                                        self.stride, self.padding,
@@ -422,4 +424,4 @@ if IS_MLU_AVAILABLE:
                 stride=self.stride,
                 padding=self.padding,
                 dilation=self.dilation,
-                mask=mask)
+                mask=mask)
\ No newline at end of file
diff --git a/mmcv/ops/multi_scale_deform_attn.py b/mmcv/ops/multi_scale_deform_attn.py
index 8c09cd2a..0107208f 100644
--- a/mmcv/ops/multi_scale_deform_attn.py
+++ b/mmcv/ops/multi_scale_deform_attn.py
@@ -1,4 +1,5 @@
 # Copyright (c) OpenMMLab. All rights reserved.
+# Copyright 2024 Huawei Technologies Co., Ltd
 import math
 import warnings
 from typing import Optional, no_type_check
@@ -15,6 +16,7 @@ from mmcv.cnn.bricks.registry import ATTENTION
 from mmcv.runner import BaseModule
 from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_NPU_AVAILABLE
 from ..utils import ext_loader
+import mx_driving.fused
 
 ext_module = ext_loader.load_ext(
     '_ext', ['ms_deform_attn_backward', 'ms_deform_attn_forward'])
@@ -363,9 +365,8 @@ class MultiScaleDeformableAttention(BaseModule):
         if ((IS_CUDA_AVAILABLE and value.is_cuda)
                 or (IS_MLU_AVAILABLE and value.is_mlu)
                 or (IS_NPU_AVAILABLE and value.device.type == 'npu')):
-            output = MultiScaleDeformableAttnFunction.apply(
-                value, spatial_shapes, level_start_index, sampling_locations,
-                attention_weights, self.im2col_step)
+            output = mx_driving.fused.multi_scale_deformable_attn(value, spatial_shapes, 
level_start_index,
+                                                                         sampling_locatio
ns, attention_weights)
         else:
             output = multi_scale_deformable_attn_pytorch(
                 value, spatial_shapes, sampling_locations, attention_weights)
@@ -376,4 +377,4 @@ class MultiScaleDeformableAttention(BaseModule):
             # (num_query, bs ,embed_dims)
             output = output.permute(1, 0, 2)
 
-        return self.dropout(output) + identity
+        return self.dropout(output) + identity
\ No newline at end of file
diff --git a/mmcv/parallel/distributed.py b/mmcv/parallel/distributed.py
index bf34cb59..f0dfecc9 100644
--- a/mmcv/parallel/distributed.py
+++ b/mmcv/parallel/distributed.py
@@ -156,8 +156,7 @@ class MMDistributedDataParallel(DistributedDataParallel):
         Returns:
             Any: Forward result of :attr:`module`.
         """
-        module_to_run = self._replicated_tensor_module if \
-            self._use_replicated_tensor_module else self.module
+        module_to_run = self.module
 
         if self.device_ids:
             inputs, kwargs = self.to_kwargs(  # type: ignore
diff --git a/mmcv/runner/dist_utils.py b/mmcv/runner/dist_utils.py
index c061b3c1..656cd069 100644
--- a/mmcv/runner/dist_utils.py
+++ b/mmcv/runner/dist_utils.py
@@ -36,7 +36,7 @@ def _is_free_port(port: int) -> bool:
 
 def init_dist(launcher: str, backend: str = 'nccl', **kwargs) -> None:
     if mp.get_start_method(allow_none=True) is None:
-        mp.set_start_method('spawn')
+        mp.set_start_method('fork')
     if launcher == 'pytorch':
         _init_dist_pytorch(backend, **kwargs)
     elif launcher == 'mpi':
diff --git a/requirements/runtime.txt b/requirements/runtime.txt
index 66e90d67..ac9275d1 100644
--- a/requirements/runtime.txt
+++ b/requirements/runtime.txt
@@ -1,7 +1,7 @@
 addict
-numpy
+numpy==1.22.0
 packaging
 Pillow
 pyyaml
 regex;sys_platform=='win32'
-yapf
+yapf
\ No newline at end of file
git clone -b 1.x https://github.com/open-mmlab/mmcv.git cd mmcv cp -f ../mmcv.patch ./ #mmcv.patch为上方文件 git apply --reject --whitespace=fix mmcv.patch pip install -r requirements/runtime.txt MMCV_WITH_OPS=1 FORCE_NPU=1 python setup.py install

准备模型源码

UniAD.patch

diff --git a/projects/mmdet3d_plugin/datasets/eval_utils/map_api.py b/projects/mmdet3d_plugin/datasets/eval_utils/map_api.py
index 5f26e58..1010998 100644
--- a/projects/mmdet3d_plugin/datasets/eval_utils/map_api.py
+++ b/projects/mmdet3d_plugin/datasets/eval_utils/map_api.py
@@ -31,7 +31,9 @@ from nuscenes.utils.geometry_utils import view_points
 from functools import partial

 # Recommended style to use as the plots will show grids.
-plt.style.use('seaborn-whitegrid')
+# plt.style.use('seaborn-whitegrid')
+# 使用环境中实际存在的新版样式名
+plt.style.use('seaborn-v0_8-whitegrid')

 # Define a map geometry type for polygons and lines.
 Geometry = Union[Polygon, LineString]
@@ -2094,10 +2096,27 @@ class NuScenesMapExplorer:
         def int_coords(x):
             # function to round and convert to int
             return np.array(x).round().astype(np.int32)
-        exteriors = [int_coords(poly.exterior.coords) for poly in polygons]
-        interiors = [int_coords(pi.coords) for poly in polygons for pi in poly.interiors]
-        cv2.fillPoly(mask, exteriors, 1)
-        cv2.fillPoly(mask, interiors, 0)
+        # exteriors = [int_coords(poly.exterior.coords) for poly in polygons]
+        # interiors = [int_coords(pi.coords) for poly in polygons for pi in poly.interiors]
+        # cv2.fillPoly(mask, exteriors, 1)
+        # cv2.fillPoly(mask, interiors, 0)
+        # 关键修复:统一处理Polygon/MultiPolygon为可迭代列表
+        if isinstance(polygons, Polygon):
+            poly_list = [polygons]  # 单个Polygon转列表
+        elif isinstance(polygons, MultiPolygon):
+            poly_list = list(polygons.geoms)  # MultiPolygon转geom列表
+        else:
+            poly_list = polygons  # 兼容已有列表/可迭代对象
+
+        # 基于可迭代列表生成外轮廓和内轮廓
+        exteriors = [int_coords(poly.exterior.coords) for poly in poly_list]
+        interiors = [int_coords(pi.coords) for poly in poly_list for pi in poly.interiors]
+
+        # 填充mask(增加空值判断,避免cv2报错)
+        if exteriors:
+            cv2.fillPoly(mask, exteriors, 1)
+        if interiors:
+            cv2.fillPoly(mask, interiors, 0)
         return mask

     @staticmethod
@@ -2108,15 +2127,36 @@ class NuScenesMapExplorer:
         :param mask: Canvas where mask will be generated.
         :return: Numpy ndarray line mask.
         """
+        # if lines.geom_type == 'MultiLineString':
+        #     for line in lines:
+        #         coords = np.asarray(list(line.coords), np.int32)
+        #         coords = coords.reshape((-1, 2))
+        #         cv2.polylines(mask, [coords], False, 1, 2)
+        # else:
+        #     coords = np.asarray(list(lines.coords), np.int32)
+        #     coords = coords.reshape((-1, 2))
+        #     cv2.polylines(mask, [coords], False, 1, 2)
+            # 空值防护:如果几何对象为空,直接返回原mask
+        if lines.is_empty:
+            return mask
+
+        # 处理MultiLineString:通过.geoms获取所有子LineString
         if lines.geom_type == 'MultiLineString':
-            for line in lines:
+            for line in lines.geoms:  # 核心修复:用.geoms迭代子LineString
+                if line.is_empty:  # 跳过空子线段
+                    continue
                 coords = np.asarray(list(line.coords), np.int32)
                 coords = coords.reshape((-1, 2))
-                cv2.polylines(mask, [coords], False, 1, 2)
-        else:
+                cv2.polylines(mask, [coords], isClosed=False, color=1, thickness=2)
+        # 处理单个LineString
+        elif lines.geom_type == 'LineString':
             coords = np.asarray(list(lines.coords), np.int32)
             coords = coords.reshape((-1, 2))
-            cv2.polylines(mask, [coords], False, 1, 2)
+            cv2.polylines(mask, [coords], isClosed=False, color=1, thickness=2)
+        # 未知几何类型:返回原mask,避免报错
+        else:
+            raise ValueError(f"Unsupported geometry type: {lines.geom_type}, only LineString/MultiLineString are allowed")
+

         return mask

diff --git a/projects/mmdet3d_plugin/datasets/pipelines/transform_3d.py b/projects/mmdet3d_plugin/datasets/pipelines/transform_3d.py
index ed0de3f..82bc453 100755
--- a/projects/mmdet3d_plugin/datasets/pipelines/transform_3d.py
+++ b/projects/mmdet3d_plugin/datasets/pipelines/transform_3d.py
@@ -382,7 +382,8 @@ class ObjectRangeFilterTrack(object):
         # using mask to index gt_labels_3d will cause bug when
         # len(gt_labels_3d) == 1, where mask=1 will be interpreted
         # as gt_labels_3d[1] and cause out of index error
-        mask = mask.numpy().astype(np.bool)
+        # mask = mask.numpy().astype(np.bool)
+        mask = mask.numpy().astype(np.bool_)  # 仅把bool改为bool_(加下划线)
         gt_labels_3d = gt_labels_3d[mask]
         gt_inds = gt_inds[mask]
         gt_fut_traj = gt_fut_traj[mask]
diff --git a/projects/mmdet3d_plugin/uniad/dense_heads/motion_head_plugin/motion_deformable_attn.py b/projects/mmdet3d_plugin/uniad/dense_heads/motion_head_plugin/motion_deformable_attn.py
index 9aaee7e..4feb794 100644
--- a/projects/mmdet3d_plugin/uniad/dense_heads/motion_head_plugin/motion_deformable_attn.py
+++ b/projects/mmdet3d_plugin/uniad/dense_heads/motion_head_plugin/motion_deformable_attn.py
@@ -9,7 +9,6 @@ import warnings
 import torch
 import math
 import torch.nn as nn
-
 from einops import rearrange, repeat
 from mmcv.ops.multi_scale_deform_attn import multi_scale_deformable_attn_pytorch
 from mmcv.cnn import xavier_init, constant_init
@@ -20,7 +19,6 @@ from mmcv.runner.base_module import BaseModule, ModuleList, Sequential
 from mmcv.utils import ConfigDict, deprecated_api_warning
 from projects.mmdet3d_plugin.uniad.modules.multi_scale_deformable_attn_function import MultiScaleDeformableAttnFunction_fp32

-
 @TRANSFORMER_LAYER.register_module()
 class MotionTransformerAttentionLayer(BaseModule):
     """Base `TransformerLayer` for vision transformer.
@@ -458,9 +456,18 @@ class MotionDeformableAttention(BaseModule):
                 MultiScaleDeformableAttnFunction = MultiScaleDeformableAttnFunction_fp32
             else:
                 MultiScaleDeformableAttnFunction = MultiScaleDeformableAttnFunction_fp32
+            # print("*****************motion_deformable MultiScaleDeformableAttnFunction*****************")
+            # print("==================value.dtype,value.shape:",value.dtype,value.shape)
+
+            # print("==================spatial_shapes:",spatial_shapes)
+            # print("==================level_start_index:",level_start_index)
+            # print("==================sampling_locations:",sampling_locations.shape,sampling_locations.dtype)
+            # print("==================attention_weights:",attention_weights.shape,attention_weights.dtype)
+            # print("==================self.im2col_step:",self.im2col_step)
             output = MultiScaleDeformableAttnFunction.apply(
                 value, spatial_shapes, level_start_index, sampling_locations,
                 attention_weights, self.im2col_step)
+
         else:
             output = multi_scale_deformable_attn_pytorch(
                 value, spatial_shapes, sampling_locations, attention_weights)
@@ -629,4 +636,4 @@ class CustomModeMultiheadAttention(BaseModule):
         out = out.transpose(0, 1)
         out = identity + self.dropout_layer(self.proj_drop(out))

-        return out.view(bs, n_agent, n_query, D)
\ No newline at end of file
+        return out.view(bs, n_agent, n_query, D)
diff --git a/projects/mmdet3d_plugin/uniad/modules/decoder.py b/projects/mmdet3d_plugin/uniad/modules/decoder.py
index 33024f8..ff07403 100644
--- a/projects/mmdet3d_plugin/uniad/modules/decoder.py
+++ b/projects/mmdet3d_plugin/uniad/modules/decoder.py
@@ -329,9 +329,18 @@ class CustomMSDeformableAttention(BaseModule):
                 MultiScaleDeformableAttnFunction = MultiScaleDeformableAttnFunction_fp32
             else:
                 MultiScaleDeformableAttnFunction = MultiScaleDeformableAttnFunction_fp32
+            # print("*****************decoder MultiScaleDeformableAttnFunction*****************")
+            # print("==================value.dtype,value.shape:",value.dtype,value.shape)
+
+            # print("==================spatial_shapes:",spatial_shapes)
+            # print("==================level_start_index:",level_start_index)
+            # print("==================sampling_locations:",sampling_locations.shape,sampling_locations.dtype)
+            # print("==================attention_weights:",attention_weights.shape,attention_weights.dtype)
+            # print("==================self.im2col_step:",self.im2col_step)
             output = MultiScaleDeformableAttnFunction.apply(
                 value, spatial_shapes, level_start_index, sampling_locations,
                 attention_weights, self.im2col_step)
+
         else:
             output = multi_scale_deformable_attn_pytorch(
                 value, spatial_shapes, sampling_locations, attention_weights)
diff --git a/tools/train.py b/tools/train.py
index 255551e..806d3f7 100755
--- a/tools/train.py
+++ b/tools/train.py
@@ -26,6 +26,9 @@ warnings.filterwarnings("ignore")

 from mmcv.utils import TORCH_VERSION, digit_version

+from torch_npu.contrib import transfer_to_npu
+
+torch.npu.config.allow_internal_format = False

 def parse_args():
     parser = argparse.ArgumentParser(description='Train a detector')
diff --git a/tools/uniad_dist_train.sh b/tools/uniad_dist_train.sh
index 2001a63..3f693c6 100755
--- a/tools/uniad_dist_train.sh
+++ b/tools/uniad_dist_train.sh
@@ -7,7 +7,7 @@ T=`date +%m%d%H%M`
 CFG=$1                                               #
 GPUS=$2                                              #
 # -------------------------------------------------- #
-GPUS_PER_NODE=$(($GPUS<8?$GPUS:8))
+GPUS_PER_NODE=$(($GPUS<16?$GPUS:16))
 NNODES=`expr $GPUS / $GPUS_PER_NODE`

 MASTER_PORT=${MASTER_PORT:-28596}
git clone https://github.com/OpenDriveLab/UniAD.git cp -f ./UniAD.patch UniAD #UniAD.patch为上方文件 cp -r ./Driv

perf.py

from __future__ import division

import argparse
import cv2
import torch
import sklearn
import mmcv
import copy
import os
import time
import warnings
from mx_driving.patcher import default_patcher_builder
from mmcv import Config, DictAction
from mmcv.runner import get_dist_info, init_dist
from os import path as osp

from mmdet import __version__ as mmdet_version
from mmdet3d import __version__ as mmdet3d_version

from mmdet3d.datasets import build_dataset
from mmdet3d.models import build_model
from mmdet3d.utils import collect_env, get_root_logger
from mmdet.apis import set_random_seed
from mmseg import __version__ as mmseg_version

warnings.filterwarnings("ignore")

from mmcv.utils import TORCH_VERSION, digit_version

import torch_npu
from torch_npu.contrib import transfer_to_npu

torch.npu.config.allow_internal_format = False

def parse_args():
    parser = argparse.ArgumentParser(description='Train a detector')
    parser.add_argument('config', help='train config file path')
    parser.add_argument('--work-dir', help='the dir to save logs and models')
    parser.add_argument(
        '--resume-from', help='the checkpoint file to resume from')
    parser.add_argument(
        '--no-validate',
        action='store_true',
        help='whether not to evaluate the checkpoint during training')
    group_gpus = parser.add_mutually_exclusive_group()
    group_gpus.add_argument(
        '--gpus',
        type=int,
        help='number of gpus to use '
        '(only applicable to non-distributed training)')
    group_gpus.add_argument(
        '--gpu-ids',
        type=int,
        nargs='+',
        help='ids of gpus to use '
        '(only applicable to non-distributed training)')
    parser.add_argument('--seed', type=int, default=0, help='random seed')
    parser.add_argument(
        '--deterministic',
        action='store_true',
        help='whether to set deterministic options for CUDNN backend.')
    parser.add_argument(
        '--options',
        nargs='+',
        action=DictAction,
        help='override some settings in the used config, the key-value pair '
        'in xxx=yyy format will be merged into config file (deprecate), '
        'change to --cfg-options instead.')
    parser.add_argument(
        '--cfg-options',
        nargs='+',
        action=DictAction,
        help='override some settings in the used config, the key-value pair '
        'in xxx=yyy format will be merged into config file. If the value to '
        'be overwritten is a list, it should be like key="[a,b]" or key=a,b '
        'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" '
        'Note that the quotation marks are necessary and that no white space '
        'is allowed.')
    parser.add_argument(
        '--launcher',
        choices=['none', 'pytorch', 'slurm', 'mpi'],
        default='none',
        help='job launcher')
    parser.add_argument('--local_rank', type=int, default=0)
    parser.add_argument(
        '--autoscale-lr',
        action='store_true',
        help='automatically scale lr with the number of gpus')
    args = parser.parse_args()
    if 'LOCAL_RANK' not in os.environ:
        os.environ['LOCAL_RANK'] = str(args.local_rank)

    if args.options and args.cfg_options:
        raise ValueError(
            '--options and --cfg-options cannot be both specified, '
            '--options is deprecated in favor of --cfg-options')
    if args.options:
        warnings.warn('--options is deprecated in favor of --cfg-options')
        args.cfg_options = args.options

    return args

def main():
    args = parse_args()

    cfg = Config.fromfile(args.config)
    if args.cfg_options is not None:
        cfg.merge_from_dict(args.cfg_options)
    # import modules from string list.
    if cfg.get('custom_imports', None):
        from mmcv.utils import import_modules_from_strings
        import_modules_from_strings(**cfg['custom_imports'])

    # import modules from plguin/xx, registry will be updated
    if hasattr(cfg, 'plugin'):
        if cfg.plugin:
            import importlib
            if hasattr(cfg, 'plugin_dir'):
                plugin_dir = cfg.plugin_dir
                _module_dir = os.path.dirname(plugin_dir)
                _module_dir = _module_dir.split('/')
                _module_path = _module_dir[0]

                for m in _module_dir[1:]:
                    _module_path = _module_path + '.' + m
                print(_module_path)
                plg_lib = importlib.import_module(_module_path)
            else:
                # import dir is the dirpath for the config file
                _module_dir = os.path.dirname(args.config)
                _module_dir = _module_dir.split('/')
                _module_path = _module_dir[0]
                for m in _module_dir[1:]:
                    _module_path = _module_path + '.' + m
                print(_module_path)
                plg_lib = importlib.import_module(_module_path)

            from projects.mmdet3d_plugin.uniad.apis.train import custom_train_model
    # set cudnn_benchmark
    if cfg.get('cudnn_benchmark', False):
        torch.backends.cudnn.benchmark = True

    # work_dir is determined in this priority: CLI > segment in file > filename
    if args.work_dir is not None:
        # update configs according to CLI args if args.work_dir is not None
        cfg.work_dir = args.work_dir
    elif cfg.get('work_dir', None) is None:
        # use config filename as default work_dir if cfg.work_dir is None
        cfg.work_dir = osp.join('./work_dirs',
                                osp.splitext(osp.basename(args.config))[0])
    # if args.resume_from is not None:
    if args.resume_from is not None and osp.isfile(args.resume_from):
        cfg.resume_from = args.resume_from
    if args.gpu_ids is not None:
        cfg.gpu_ids = args.gpu_ids
    else:
        cfg.gpu_ids = range(1) if args.gpus is None else range(args.gpus)
    if digit_version(TORCH_VERSION) == digit_version('1.8.1') and cfg.optimizer['type'] == 'AdamW':
        cfg.optimizer['type'] = 'AdamW2' # fix bug in Adamw
    if args.autoscale_lr:
        cfg.optimizer['lr'] = cfg.optimizer['lr'] * len(cfg.gpu_ids) / 8

    # init distributed env first, since logger depends on the dist info.
    if args.launcher == 'none':
        distributed = False
    else:
        distributed = True
        init_dist(args.launcher, **cfg.dist_params)
        # re-set gpu_ids with distributed training mode
        _, world_size = get_dist_info()
        cfg.gpu_ids = range(world_size)

    # create work_dir
    mmcv.mkdir_or_exist(osp.abspath(cfg.work_dir))
    # dump config
    cfg.dump(osp.join(cfg.work_dir, osp.basename(args.config)))
    # init the logger before other steps
    timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime())
    log_file = osp.join(cfg.work_dir, f'{timestamp}.log')
    # specify logger name, if we still use 'mmdet', the output info will be
    # filtered and won't be saved in the log_file
    # TODO: ugly workaround to judge whether we are training det or seg model
    if cfg.model.type in ['EncoderDecoder3D']:
        logger_name = 'mmseg'
    else:
        logger_name = 'mmdet'
    logger = get_root_logger(
        log_file=log_file, log_level=cfg.log_level, name=logger_name)

    # init the meta dict to record some important information such as
    # environment info and seed, which will be logged
    meta = dict()
    # log env info
    env_info_dict = collect_env()
    env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()])
    dash_line = '-' * 60 + '\n'
    logger.info('Environment info:\n' + dash_line + env_info + '\n' +
                dash_line)
    meta['env_info'] = env_info
    meta['config'] = cfg.pretty_text

    # log some basic info
    logger.info(f'Distributed training: {distributed}')
    logger.info(f'Config:\n{cfg.pretty_text}')

    # set random seeds
    if args.seed is not None:
        logger.info(f'Set random seed to {args.seed}, '
                    f'deterministic: {args.deterministic}')
        set_random_seed(args.seed, deterministic=args.deterministic)
    cfg.seed = args.seed
    meta['seed'] = args.seed
    meta['exp_name'] = osp.basename(args.config)

    model = build_model(
        cfg.model,
        train_cfg=cfg.get('train_cfg'),
        test_cfg=cfg.get('test_cfg'))
    model.init_weights()

    logger.info(f'Model:\n{model}')
    datasets = [build_dataset(cfg.data.train)]
    if len(cfg.workflow) == 2:
        val_dataset = copy.deepcopy(cfg.data.val)
        # in case we use a dataset wrapper
        if 'dataset' in cfg.data.train:
            val_dataset.pipeline = cfg.data.train.dataset.pipeline
        else:
            val_dataset.pipeline = cfg.data.train.pipeline
        # set test_mode=False here in deep copied config
        # which do not affect AP/AR calculation later
        val_dataset.test_mode = False
        datasets.append(build_dataset(val_dataset))
    if cfg.checkpoint_config is not None:
        # save mmdet version, config file content and class names in
        # checkpoints as meta data
        cfg.checkpoint_config.meta = dict(
            mmdet_version=mmdet_version,
            mmseg_version=mmseg_version,
            mmdet3d_version=mmdet3d_version,
            config=cfg.pretty_text,
            CLASSES=datasets[0].CLASSES,
            PALETTE=datasets[0].PALETTE  # for segmentors
            if hasattr(datasets[0], 'PALETTE') else None)
    # add an attribute for visualization convenience
    model.CLASSES = datasets[0].CLASSES
    custom_train_model(
        model,
        datasets,
        cfg,
        distributed=distributed,
        validate=(not args.no_validate),
        timestamp=timestamp,
        meta=meta)

if __name__ == '__main__':
    with default_patcher_builder.disable_patches("index").brake_at(500).build():
        main()

uniad_dist_perf.sh

#!/usr/bin/env bash

T=`date +%m%d%H%M`

# -------------------------------------------------- #
# Usually you only need to customize these variables #
CFG=$1                                               #
GPUS=$2                                              #
# -------------------------------------------------- #
GPUS_PER_NODE=$(($GPUS<16?$GPUS:16))
NNODES=`expr $GPUS / $GPUS_PER_NODE`

MASTER_PORT=${MASTER_PORT:-28596}
MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"}
RANK=${RANK:-0}

WORK_DIR=$(echo ${CFG%.*} | sed -e "s/configs/work_dirs/g")/
# Intermediate files and logs will be saved to UniAD/projects/work_dirs/

if [ ! -d ${WORK_DIR}logs ]; then
    mkdir -p ${WORK_DIR}logs
fi

PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \
torchrun \
    --nproc_per_node=${GPUS_PER_NODE} \
    --master_addr=${MASTER_ADDR} \
    --master_port=${MASTER_PORT} \
    --nnodes=${NNODES} \
    --node_rank=${RANK} \
    $(dirname "$0")/perf.py \
    $CFG \
    --launcher pytorch ${@:3} \
    --deterministic \
    --work-dir ${WORK_DIR} \
    2>&1 | tee ${WORK_DIR}logs/train.$T

# 注意⚠️:将以上perf.py和uniad_dist_perf.sh两个文件复制到源码UniAD/tools目录下

数据集下载:自行下载

准备数据集

  • 根据原仓Prepare Dataset章节准备数据集,数据集目录及结构如下:

UniAD
├── projects/
├── tools/
├── ckpts/
│   ├── bevformer_r101_dcn_24ep.pth
│   ├── uniad_base_track_map.pth
|   ├── uniad_base_e2e.pth
├── data/
│   ├── nuscenes/
│   │   ├── can_bus/
│   │   ├── maps/
│   │   ├── lidarseg/
│   │   ├── samples/
│   │   ├── sweeps/
│   │   ├── v1.0-test/
│   │   ├── v1.0-trainval/
│   │   ├── v1.0-mini/ 
│   ├── infos/
│   │   ├── nuscenes_infos_temporal_train.pkl
│   │   ├── nuscenes_infos_temporal_val.pkl
│   ├── others/
│   │   ├── motion_anchor_infos_mode6.pkl
# 处理数据集,也可以自行下载处理后的文件。
# 参考https://github.com/OpenDriveLab/UniAD/blob/v2.0/docs/DATA_PREP.md
cd UniAD/data
mkdir infos
./tools/uniad_create_data.sh
# This will generate nuscenes_infos_temporal_{train,val}.pkl

准备预训练权重

  • 在模型根目录下,执行以下指令下载预训练权重:

mkdir ckpts & cd ckpts
# r101_dcn_fcos3d_pretrain.pth (from bevformer)
wget https://huggingface.co/OpenDriveLab/UniAD2.0_R101_nuScenes/resolve/main/ckpts/r101_dcn_fcos3d_pretrain.pth

# bevformer_r101_dcn_24ep.pth
wget https://huggingface.co/OpenDriveLab/UniAD2.0_R101_nuScenes/resolve/main/ckpts/bevformer_r101_dcn_24ep.pth

# uniad_base_track_map.pth
wget https://huggingface.co/OpenDriveLab/UniAD2.0_R101_nuScenes/resolve/main/ckpts/uniad_base_track_map.pth

# uniad_base_e2e.pth
wget https://huggingface.co/OpenDriveLab/UniAD2.0_R101_nuScenes/resolve/main/ckpts/uniad_base_e2e.pth

拉起训练

单机16卡性能训练

bash test/train_stage1_performance_8p.sh # stage1
#!/bin/bash
################基础配置参数,需要模型审视修改##################
# 网络名称,同目录名称
Network="UniAD"
WORLD_SIZE=16
WORK_DIR=""
LOAD_FROM=""

NNODES=${NNODES:-1}
NODE_RANK=${NODE_RANK:-0}
PORT=${PORT:-29500}
MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"}

###############指定训练脚本执行路径###############
# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径
cur_path=$(pwd)
cur_path_last_dirname=${cur_path##*/}
if [ x"${cur_path_last_dirname}" == x"test" ]; then
  test_path_dir=${cur_path}
  cd ..
  cur_path=$(pwd)
else
  test_path_dir=${cur_path}/test
fi

if [ -d ${cur_path}/test/output/perf/stage1 ]; then
  rm -rf ${cur_path}/test/output/perf/stage1
  mkdir -p ${cur_path}/test/output/perf/stage1
else
  mkdir -p ${cur_path}/test/output/perf/stage1
fi

start_time=$(date +%s)
# 非平台场景时source 环境变量
check_etp_flag=$(env | grep etp_running_flag)
etp_flag=$(echo ${check_etp_flag#*=})
if [ x"${etp_flag}" != x"true" ]; then
  source ${test_path_dir}/env_npu.sh
fi

bash ./tools/uniad_dist_perf.sh ./projects/configs/stage1_track_map/base_track_map.py 16 \
    >$cur_path/test/output/perf/stage1/train_perf.log 2>&1 &
wait

# 训练结束时间,不需要修改
end_time=$(date +%s)
e2e_time=$(( $end_time - $start_time ))

# 训练用例信息,不需要修改
BatchSize=1
DeviceType=$(uname -m)
CaseName=${Network}_bs${BatchSize}_${WORLD_SIZE}'p'_'perf'

# 结果打印,不需要修改
echo "------------------ Final result ------------------"
# 输出性能FPS,需要模型审视修改
avg_time=`grep -a 'mmdet - INFO - Epoch '  ${test_path_dir}/output/perf/stage1/train_perf.log|awk -F "time: " '{print $2}' | awk -F ", " '{print $1}' | awk 'NR>10 {sum+=$1; count++} END {if (count != 0) printf("%.3f",sum/count)}'`
Iteration_time=$avg_time
# 打印,不需要修改
echo "Iteration time : $Iteration_time"

# 打印,不需要修改
echo "E2E Training Duration sec : $e2e_time"

# 训练总时长
TrainingTime=`grep -a 'Time'  ${test_path_dir}/output/perf/stage1/train_perf.log|awk -F "Time: " '{print $2}'|awk -F "," '{print $1}'| awk '{a+=$1} END {printf("%.3f",a)}'`

# 关键信息打印到${CaseName}.log中,不需要修改
echo "Network = ${Network}" >${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "RankSize = ${WORLD_SIZE}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "BatchSize = ${BatchSize}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "DeviceType = ${DeviceType}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "CaseName = ${CaseName}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "Iteration time = ${Iteration_time}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log
echo "TrainingTime = ${TrainingTime}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log
echo "E2ETrainingTime = ${e2e_time}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log

双机32卡训练

bash test/train_stage1_multi_server.sh 2 0 192.168.0.204 3389      #主机                                      
bash test/train_stage1_multi_server.sh 2 1 192.168.0.204 3389      #从机
#!/bin/bash
################基础配置参数,需要模型审视修改##################
# 网络名称,同目录名称
Network="UniAD"
WORLD_SIZE=32
WORK_DIR=""
LOAD_FROM=""

NNODES=$1
NODE_RANK=$2
MASTER_ADDR=$3
PORT=$4

###############指定训练脚本执行路径###############
# cd到与test文件夹同层级目录下执行脚本,提高兼容性;test_path_dir为包含test文件夹的路径
cur_path=$(pwd)
cur_path_last_dirname=${cur_path##*/}
if [ x"${cur_path_last_dirname}" == x"test" ]; then
  test_path_dir=${cur_path}
  cd ..
  cur_path=$(pwd)
else
  test_path_dir=${cur_path}/test
fi

if [ -d ${cur_path}/test/output/perf/stage1 ]; then
  rm -rf ${cur_path}/test/output/perf/stage1
  mkdir -p ${cur_path}/test/output/perf/stage1
else
  mkdir -p ${cur_path}/test/output/perf/stage1
fi

start_time=$(date +%s)
# 非平台场景时source 环境变量
check_etp_flag=$(env | grep etp_running_flag)
etp_flag=$(echo ${check_etp_flag#*=})
if [ x"${etp_flag}" != x"true" ]; then
  source ${test_path_dir}/env_npu.sh
fi

bash ./test/uniad_dist_perf.sh ./projects/configs/stage1_track_map/base_track_map.py 16 ${NNODES} ${NODE_RANK} ${MASTER_ADDR} ${PORT} \
    >$cur_path/test/output/perf/stage1/train_perf.log 2>&1 &
wait

# 训练结束时间,不需要修改
end_time=$(date +%s)
e2e_time=$(( $end_time - $start_time ))

# 训练用例信息,不需要修改
BatchSize=1
DeviceType=$(uname -m)
CaseName=${Network}_bs${BatchSize}_${WORLD_SIZE}'p'_'perf'

# 结果打印,不需要修改
echo "------------------ Final result ------------------"
# 输出性能FPS,需要模型审视修改
avg_time=`grep -a 'mmdet - INFO - Epoch '  ${test_path_dir}/output/perf/stage1/train_perf.log|awk -F "time: " '{print $2}' | awk -F ", " '{print $1}' | awk 'NR>10 {sum+=$1; count++} END {if (count != 0) printf("%.3f",sum/count)}'`
Iteration_time=$avg_time
# 打印,不需要修改
echo "Iteration time : $Iteration_time"

# 打印,不需要修改
echo "E2E Training Duration sec : $e2e_time"

# 训练总时长
TrainingTime=`grep -a 'Time'  ${test_path_dir}/output/perf/stage1/train_perf.log|awk -F "Time: " '{print $2}'|awk -F "," '{print $1}'| awk '{a+=$1} END {printf("%.3f",a)}'`

# 关键信息打印到${CaseName}.log中,不需要修改
echo "Network = ${Network}" >${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "RankSize = ${WORLD_SIZE}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "BatchSize = ${BatchSize}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "DeviceType = ${DeviceType}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "CaseName = ${CaseName}" >>${test_path_dir}/output/perf/stage1/${CaseName}.log
echo "Iteration time = ${Iteration_time}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log
echo "TrainingTime = ${TrainingTime}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log
echo "E2ETrainingTime = ${e2e_time}" >>${test_path_dir}/output/perf/stage1/${CaseName}_perf_report.log

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐