3D_ResNet模型在迁移到昇腾AI处理器上训练后,发现Loss收敛效果较GPU出现异常。
在PyTorch模型迁移与训练过程中出现的精度问题,可以从以下两方面依次进行定位。
请参考ptdbg_ascend工具使用说明安装ptdbg_ascend精度工具。
cd src vi main.py
from ptdbg_ascend import register_hook, overflow_check, seed_all, set_dump_path, set_dump_switch, acc_cmp_dump
def main(): seed_all() ...
def main(): ... model = create_model(opt.arch, opt.heads, opt.head_conv) ... set_dump_path("./data/dump", dump_tag='npu_overflow') # 设置dump路径,最终数据保存在此路径下 register_hook(model, overflow_check, overflow_nums=1) # 使能溢出检测 ... for epoch in range(start_epoch + 1, opt.num_epochs + 1): ...
bash ./test/train_full_1p.sh --data_path=数据集路径
def main(): ... model = create_model(opt.arch, opt.heads, opt.head_conv) optimizer = torch.optim.Adam(model.parameters(), opt.lr) ... set_dump_path("./dump_data_new/npu") # 设置dump路径,最终数据保存在此路径下 register_hook(model, acc_cmp_dump) # 添加hook函数和数据比对dump开关 for epoch in range(start_epoch + 1, opt.num_epochs + 1): ...
set_dump_switch("ON") for epoch in range(start_epoch + 1, opt.num_epochs + 1): ... logger.write('\n') set_dump_switch("OFF")
#NPU训练命令 bash ./test/train_full_1p.sh --data_path=数据集路径
模型训练结束后,数据会落盘到输出目录。样例输出目录如下图。
from ptdbg_ascend import compare dump_result_param={ "npu_pkl_path": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump.pkl", "bench_pkl_path": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/dump.pkl", "npu_dump_data_dir": "./npu_dump/ptdbg_dump_v4.0/step0/rank0/dump", "bench_dump_data_dir": "./gpu_dump/ptdbg_dump_v4.0/step0/rank0/dump", "is_print_compare_log": True } compare(dump_result_param, "./output")
python3 compare.py
比对完成后会在指定的输出目录中生成对比结果文件“compare_result_timestamp.csv”,示例文件如下所示。
可以看到第一个存在问题的是iadd API的input_0,其余弦相似度小于0.99并且最大绝对值误差远大于0.001。
set_dump_switch("ON", mode="stack", scope=['Tensor___iadd___forward'])
def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: residual = self.downsample(x) out += residual # 问题代码行 out = self.relu(out)
因此根据以上结论,可以定位到是iadd的输出存在问题,而不是输入。
def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) # out为batchnorm的输出,代入到下方成为了自增操作的输入 if self.downsample is not None: residual = self.downsample(x) out += residual # 问题代码行 out = self.relu(out)
检视batchnorm算子的比对结果数据,如下图,可以确定batchnorm输出(即iadd真实输入)的余弦相似值为1,最大绝对值误差接近0,无精度问题。
因此可以得出结论:iadd算子的计算精度存在问题,导致iadd输出精度异常。可以联系华为工程师解决此问题,可进入昇腾开源社区使用issue进行沟通。