Toybrick

标题: pytorch -> rknn 转换 nn.ReLU op 有问题,似乎是 bug [打印本页]

作者: kkkaaa    时间: 2020-5-15 15:57
标题: pytorch -> rknn 转换 nn.ReLU op 有问题,似乎是 bug
版本:rknn-toolkit 1.3.2
在转换一个目标检测模型时遇到问题(问题详见帖子:http://t.rock-chips.com/forum.ph ... tid=1625&extra=)。
通过删减层、尝试不同输出,定位到问题首先出现在 nn.ReLU. 为了让问题更清晰,写了一个小模型如下:
  1. class Net(torch.nn.Module):

  2.     def __init__(self):
  3.         super(Net, self).__init__()

  4.         self.conv1 = torch.nn.Conv2d(3,24,3)
  5.         self.nonlinear = torch.nn.ReLU()  # successful op: Sigmoid, LeakyReLU

  6.     def forward(self, x):
  7.         x1 = self.conv1(x)
  8.         y = self.nonlinear(x1)
  9.         return x1, y
复制代码


问题描述:
比较 pytorch 和 rknn 模型的输出
- 对于 y: 绝对距离和 cos 距离都很小,认为几乎一致
- 对于 x1:  rknn 输出张量的所有分量严格等于0.0, cos 距离为 nan

另外,Net 中的self.nonlinear 还尝试了 Sigmoid, LeakyReLU, y 和 x1 的 rknn 输出都正常,与 torch 输出几乎一致
附上一个可以完整运行的代码:
  1. # -*- coding: utf-8 -*-
  2. # create time: 2020-05-15 15:29

  3. import torch
  4. from rknn.api import RKNN
  5. import numpy as np


  6. class Net(torch.nn.Module):

  7.     def __init__(self):
  8.         super(Net, self).__init__()

  9.         self.conv1 = torch.nn.Conv2d(3,24,3)
  10.         self.nonlinear = torch.nn.ReLU()  # successful op: Sigmoid, LeakyReLU

  11.     def forward(self, x):
  12.         x1 = self.conv1(x)
  13.         y = self.nonlinear(x1)
  14.         return x1, y


  15. def E_D(vector1, vector2):
  16.     print("vector1 norm: ", np.linalg.norm(vector1))
  17.     print("vector2 norm: ", np.linalg.norm(vector2))
  18.     print("distance: ", np.linalg.norm(vector1 - vector2))

  19. def cos_d(vector1, vector2):
  20.     d = 1 - np.dot(vector1, vector2) / (np.linalg.norm(vector1) * (np.linalg.norm(vector2)))
  21.     print(d)


  22. if __name__ == '__main__':

  23.     net = Net()
  24.     i1 = torch.rand(1,3,5,5)
  25.     # i2 = torch.rand(1,2,7,7)
  26.     # i3 = torch.rand(1,3,9,9)
  27.     trace_model = torch.jit.trace(net, (i1))
  28.     trace_model.save('test.pt')


  29.     rknn = RKNN(verbose=True)
  30.     rknn.config(batch_size=1,
  31.                 channel_mean_value='0 0 0 1',
  32.                 reorder_channel='0 1 2',
  33.                 epochs=1)

  34.     ret = rknn.load_pytorch(model='test.pt', input_size_list=[[3,5,5]])
  35.     # ret = rknn.load_onnx(model='lstm{128x64}.pt.onnx')
  36.     if ret != 0:
  37.         print('Load pytorch model failed!')
  38.         exit(ret)

  39.     ret = rknn.build(do_quantization=False, dataset='./dataset.txt')
  40.     if ret != 0:
  41.         print('Build pytorch failed!')
  42.         exit(ret)

  43.     ret = rknn.init_runtime()
  44.     if ret != 0:
  45.         print('Init runtime environment failed')
  46.         exit(ret)


  47.     rknn_r = rknn.inference(inputs=[i1.numpy()],
  48.                             data_type='float32',
  49.                             data_format='nchw')
  50.     pytorch_r = net(i1)


  51.     for d1, d2 in zip(rknn_r, pytorch_r):
  52.         d1 = d1.ravel()
  53.         d2 = d2.detach().numpy().ravel()

  54.         E_D(d1, d2)
  55.         cos_d(d1, d2)

  56.         print("---")

复制代码
希望能够得到解答~谢谢



作者: kkkaaa    时间: 2020-5-17 21:27
本帖最后由 kkkaaa 于 2020-5-17 21:40 编辑

真心求助。。。花了两天时间定位 bug
主楼的这个模型看似无厘头,其实是我把问题 isolate 出来了,发现本质上是这里出错
如果是我犯的愚蠢错误也希望能被指正出来



作者: jefferyzhang    时间: 2020-5-18 17:10
我已经报告给NPU部门了,等他们回复
作者: kkkaaa    时间: 2020-5-21 17:58
jefferyzhang 发表于 2020-5-18 17:10
我已经报告给NPU部门了,等他们回复

没有反馈吗?
作者: jefferyzhang    时间: 2020-5-21 18:13
kkkaaa 发表于 2020-5-21 17:58
没有反馈吗?

没这么快吧,你要急的话要通过公司FAE反馈。
作者: kkkaaa    时间: 2020-5-22 10:03
jefferyzhang 发表于 2020-5-21 18:13
没这么快吧,你要急的话要通过公司FAE反馈。

好的谢谢。我以为是个小 bug
作者: jefferyzhang    时间: 2020-5-22 10:19
kkkaaa 发表于 2020-5-22 10:03
好的谢谢。我以为是个小 bug

再小的bug都要等他们下一个版本出来才能测试。他们不会为任何一个个人出单独版本,NPU的工程编译一次就是一整天,不可能你们谁提个bug,他立马解决了就给你出版本。。。
作者: kkkaaa    时间: 2020-5-22 10:45
jefferyzhang 发表于 2020-5-22 10:19
再小的bug都要等他们下一个版本出来才能测试。他们不会为任何一个个人出单独版本,NPU的工程编译一次就是 ...

其实我是希望能确定一下, 在现有的最新的 NPU 版本下,我反应的问题是否的确是一个 bug, (or I messed up something),我希望能有一个反馈。

我们现在暂时暂缓嵌入式设备的开发工作了,为了规避风险,目前暂时转向 x86 。
但是嵌入式设备仍然在我们的计划中,我们需要评估从不同框架移植模型的难度和风险。

我做了一个月,目前意识到的 rknn 的问题或者说是 bug 有以下几个
1. onnx -> rknn 多输入顺序被打乱(bug)
2. 本楼提到的(bug)
3. pytorch-> rknn , onnx-> rknn 不支持 slice 操作 (not support)
4. pytorch -> rknn 还有一些无法描述的奇妙 bug(无法描述)
5. rknn.config 当通道为3时 reorder 默认 '2 1 0' (违反直觉)

以上结论都是我在反复的实验过程中总结出来的,其实我不是很专业,对自己的结论并不是很有信心,所以我发了很多帖子,也得到了很多及时的回复。

我希望 rknn 能做的更好,但是我也希望能得到更多反馈。
作者: jefferyzhang    时间: 2020-5-22 11:01
没有办法,这里只是社区,我们也只是跟你们一样的工程师而已。
要么等,要么联系FAE。
作者: kkkaaa    时间: 2020-5-22 11:07
jefferyzhang 发表于 2020-5-22 11:01
没有办法,这里只是社区,我们也只是跟你们一样的工程师而已。
要么等,要么联系FAE。 ...

I see... 你们的 NPU 部门连这是不是一个 bug 都不会立马反馈给你们是吧。。。
看来用 rknn 还是最好限制在 yolo系列这种大家都在用的模型了,如果是更加客制化的模型。。。看起来是给自己挖坑

作者: jefferyzhang    时间: 2020-5-22 11:26
kkkaaa 发表于 2020-5-22 11:07
I see... 你们的 NPU 部门连这是不是一个 bug 都不会立马反馈给你们是吧。。。
看来用 rknn 还是最好限制 ...

只要你们按文档操作,有问题肯定是bug。
你们可以自己尝试绕过去,或者只能等他们处理。

立项客户可以通过FAE或者直接跟他们交流。
作者: jefferyzhang    时间: 2020-5-25 20:01
NPU Team回复:  253049

1.如果要跑你这个模型,rknn.config(optimization_level=0)设置一下,如果不设置的话卷积和relu在硬件上会merge。

2.rknn.init_runtime 请指定设备,因为驱动更新比模拟器快,硬件跑的结果可能会和模拟器跑的结果不一样。

直接跑我这个test.py是能得到正确结果的。

  1. # -*- coding: utf-8 -*-
  2. # create time: 2020-05-15 15:29

  3. import torch
  4. from rknn.api import RKNN
  5. import numpy as np


  6. class Net(torch.nn.Module):

  7.     def __init__(self):
  8.         super(Net, self).__init__()

  9.         self.conv1 = torch.nn.Conv2d(3,24,3)
  10.         self.nonlinear = torch.nn.ReLU()  # successful op: Sigmoid, LeakyReLU

  11.     def forward(self, x):
  12.         x1 = self.conv1(x)
  13.         y = self.nonlinear(x1)
  14.         return x1, y


  15. def E_D(vector1, vector2):
  16.     print("vector1 norm: ", np.linalg.norm(vector1))
  17.     print("vector2 norm: ", np.linalg.norm(vector2))
  18.     print("distance: ", np.linalg.norm(vector1 - vector2))

  19. def cos_d(vector1, vector2):
  20.     d = 1 - np.dot(vector1, vector2) / (np.linalg.norm(vector1) * (np.linalg.norm(vector2)))
  21.     print(d)


  22. if __name__ == '__main__':

  23.     net = Net()
  24.     net.eval()
  25.     i1 = torch.rand(1,3,5,5)
  26.     # i2 = torch.rand(1,2,7,7)
  27.     # i3 = torch.rand(1,3,9,9)
  28.     trace_model = torch.jit.trace(net, (i1))
  29.     trace_model.save('test.pt')


  30.     rknn = RKNN(verbose=True)
  31.     rknn.config(batch_size=1,
  32.                 channel_mean_value='0 0 0 1',
  33.                 reorder_channel='0 1 2',
  34.                 optimization_level=0,
  35.                 epochs=1)

  36.     ret = rknn.load_pytorch(model='test.pt', input_size_list=[[3,5,5]])
  37.     # ret = rknn.load_onnx(model='lstm{128x64}.pt.onnx')
  38.     if ret != 0:
  39.         print('Load pytorch model failed!')
  40.         exit(ret)

  41.     ret = rknn.build(do_quantization=False, dataset='./dataset.txt')
  42.     if ret != 0:
  43.         print('Build pytorch failed!')
  44.         exit(ret)

  45.     ret = rknn.init_runtime(target='rk1808')
  46.     if ret != 0:
  47.         print('Init runtime environment failed')
  48.         exit(ret)


  49.     rknn_r = rknn.inference(inputs=[i1.numpy()],
  50.                             data_type='float32',
  51.                             data_format='nchw')
  52.     pytorch_r = net(i1)


  53.     for d1, d2 in zip(rknn_r, pytorch_r):
  54.         d1 = d1.ravel()
  55.         d2 = d2.detach().numpy().ravel()

  56.         E_D(d1, d2)
  57.         cos_d(d1, d2)

  58.         print("---")

复制代码





欢迎光临 Toybrick (https://t.rock-chips.com/) Powered by Discuz! X3.3