UniAD_v2 模型NPU适配
·
参考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
环境搭建
-
拉起镜像:
# 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
-
启动容器&进入容器
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
-
安装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
-
创建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
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐



所有评论(0)