Toybrick

多输入时,通道顺序为何会乱? Python接口怎么用多输入?

xsky

中级会员

积分
388
发表于 2020-2-22 21:56:12    查看: 10108|回复: 6 | [复制链接]    打印 | 显示全部楼层
本帖最后由 xsky 于 2020-2-22 22:30 编辑

在多输入时,各个输入shape不一样,为何从onnx转换为rknn后输入的顺序会乱, 输出的顺序是正常的,
另外C API 可以支持多输入, Python接口怎么构选多输入?  user guide 文档并没有叙述.
谢谢!

Pytorch             1.2.0
RKNN                1.3.0tensorflow         1.14.0
onnx                 1.4.1
onnx-tf              1.2.1
RKNN API  1.3.0,  DRIVE: 1.3.0     Debain 10
如下代码:

  1. import platform
  2. import os
  3. import torch
  4. import numpy as np

  5. from rknn.api import RKNN

  6. import onnx
  7. from onnx_tf.backend import prepare

  8. class LSTM(torch.nn.Module):

  9.     def __init__(self, input_size, hidden_size):
  10.         super(LSTM, self).__init__()

  11.         self._input_size = input_size
  12.         self._hidden_size = hidden_size
  13.         self._fc = torch.nn.Linear(input_size, input_size)
  14.         self._tanh = torch.nn.Tanh()
  15.         self._sigmoid = torch.nn.Sigmoid()

  16.     def forward(self, x, h0, c0):

  17.         return self._fc(x), self._sigmoid(h0), self._sigmoid(c0)
  18.         #ox, (h1, c1) = self._lstm(x, (h0, c0))
  19.         return ox, h1, c1

  20. if __name__ == '__main__':

  21.     system = platform.system()

  22.     isize = 128
  23.     hsize = 64
  24.     #m = torch.nn.Linear(isize, hsize)
  25.     m = LSTM(isize, hsize)
  26.     m.eval()
  27.     m.float()

  28.     h0 = torch.full((1, 1, hsize), fill_value=0.15, dtype=torch.float)
  29.     c0 = torch.full((1, 1, hsize//2), fill_value=0.07, dtype=torch.float)
  30.     x = torch.full((1, isize), fill_value=0.1, dtype=torch.float)
  31.     #x1 = torch.full((1, hsize), fill_value=0.2, dtype=torch.float)
  32.     pt_file = "lstm{%dx%d}.pt" % (isize, hsize)

  33.     rknn = RKNN(verbose=True)
  34.     rknn.config(batch_size=1,
  35.                 epochs=1)  # asymmetric_quantized-u8,  quantized_dtype='dynamic_fixed_point-16' , channel_mean_value='0 0 0 1', reorder_channel='0 1 2',

  36.     #pt = torch.jit.trace(m, x, h0, c0)
  37.     #pt.save(pt_file)
  38.     #rknn.load_pytorch(model=pt_file, input_size_list=[[1, isize]])

  39.     onnx_file = pt_file + '.onnx'
  40.     torch.onnx.export(m, (x, h0, c0), onnx_file,
  41.                       export_params=True,  # store the trained parameter weights inside the model file
  42.                       # do_constant_folding=True,  # whether to execute constant folding for optimization
  43.                       opset_version=9,  # the ONNX version to export the model to
  44.                       input_names=['input', 'h0', 'c0'],  # the model's input names
  45.                       output_names=['output', 'h1', 'c1']  # the model's output names
  46.                       # dynamic_axes={'input' : {0 : 'batch_size'},    # variable lenght axes
  47.                       #              'output' : {0 : 'batch_size'}}
  48.                       )
  49.     rknn.load_onnx(model=onnx_file)

  50.     rknn_file = pt_file + '.rknn'
  51.     ret = rknn.build(do_quantization=False, dataset='./dataset.txt')
  52.     rknn.export_rknn(rknn_file)

  53.     print('--> Init runtime environment')

  54.     if system == 'Windows':
  55.         print("rknn run target rk1808")
  56.         ret = rknn.init_runtime(target='rk1808', target_sub_class='AICS')
  57.     else:
  58.         print("rknn run target self")
  59.         ret = rknn.init_runtime()
  60.     if ret != 0:
  61.         print('Init runtime environment failed')
  62.         exit(ret)
  63.     print('done')

  64.     ix = x.numpy()
  65.     tf_model = onnx.load(onnx_file)
  66.     tf_rep = prepare(tf_model)
  67.     tf_out, tf_h1, tf_c1 = tf_rep.run((ix, h0, c0))
  68.     tf_out = np.array(tf_out)
  69.     print("onnx out:", ix.shape, ', ', tf_out.shape)
  70.     print(tf_out)

  71.     torch_out, th_h1, th_c1 = m.forward(x, h0, c0)
  72.     print("torch [out]:", x.shape, ', ', torch_out.shape)
  73.     print(torch_out.detach().unsqueeze(0).numpy())

  74.     ih0 = h0.numpy()
  75.     ic0 = c0.numpy()
  76.     rknn_out = rknn.inference(inputs=[(ix, ih0, ic0)], data_type='float32', data_format='nchw')   # , inputs_pass_through=[1]
  77.     rknn_out = np.array(rknn_out)
  78.     print("rknn out:", ix.shape, ', ', rknn_out.shape)
  79.     print(rknn_out)

  80.     rknn.release()
复制代码


输出的模型形状,输入输出均已命名,且onnx模型可正常运行:



查询RKNN输入相关的代码, 在RK3399Pro上运行:
  1. ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &in_out_num, sizeof(in_out_num));
  2. if (ret < 0) {
  3.     printf(_LINE_MARK_ " rknn_query fail: query in out num, ret=%d\n", ret);
  4.     goto Error;
  5. }
  6. assert(_NInChs == in_out_num.n_input && _NOutChs == in_out_num.n_output);
  7. for (int i = 0; i < _NInChs; i++) {
  8.     inputs_attr[i].index = i;
  9.     ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(inputs_attr[i]), sizeof(inputs_attr[i]));
  10.     if (ret < 0) {
  11.         printf(_LINE_MARK_ " rknn_query fail: query inputs attrs, ret=%d\n", ret);
  12.         goto Error;
  13.     }
  14. }
  15. for (int i = 0; i < _NOutChs; i++) {
  16.     outputs_attr[i].index = i;
  17.     ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(outputs_attr[i]), sizeof(outputs_attr[i]));
  18.     if (ret < 0) {
  19.         printf(_LINE_MARK_ " rknn_query fail: query outputs attrs ret=%d\n", ret);
  20.         goto Error;
  21.     }
  22. }
复制代码



输入为 (x, h0, c0)按顺序对应的shape 分另为:(1, 128), (1, 1, 64), (1, 1, 32),但在RKNN C API中获取到的输入属性为 (1, 1, 32), (1, 128), (1, 1, 64):

输出的顺序确是正确的(1, 128), (1, 1, 64), (1, 1, 32):, scale = 1}}



而且,  不同次导出的onnx,   RKNN编译查询得到的输入属性都会不同

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

jefferyzhang

版主

积分
12844
发表于 2020-2-23 11:04:38 | 显示全部楼层
为啥不直接用pytorch模型转rknn试试?
回复

使用道具 举报

xsky

中级会员

积分
388
 楼主| 发表于 2020-2-24 17:43:28 | 显示全部楼层
本帖最后由 xsky 于 2020-2-24 21:35 编辑
jefferyzhang 发表于 2020-2-23 11:04
为啥不直接用pytorch模型转rknn试试?

之前试了load_pytorch加载 build报错, 应该原因是fc输入要减少一维变成两维的。

不过针对这个多输入的问题还想请教一下:
1. 是啥原因输入的顺序和给的模型不一样?另外C接口查出来的输入属性中.name是空的,如果有这个名字也方便面匹配,onnx是给了名字的。
2. 多输入的Python接口运行是怎么用的?3. 多输入如果形状不一样可以么,比如 [1, 120, 128]  [1, 64] [1, 64]?

再请教一下,目前支持的这些模型格式,是不是都不支持LSTM运算符的?
现在想做个评估看看基本性能,想把TTS部到NPU,或者是测出LSTM的性能,拆出一部分部到上面。

谢谢

回复

使用道具 举报

jefferyzhang

版主

积分
12844
发表于 2020-2-25 08:48:05 | 显示全部楼层
1. 顺序不一致要再看下,我们还在确认这个问题中
2. name可以通过Netron看
3. 多输入python请参看教程有写,文档也有写
4. 不明白你说的多输入形状不一致是什么意思,如果是多个input节点当然是可以的,如果是多batch当然是不行的
回复

使用道具 举报

jefferyzhang

版主

积分
12844
发表于 2020-2-26 09:50:54 | 显示全部楼层
NPU部门回复:
1.支持多输入多输出,多个输入时shape可以不一样,但是输入要按照nchw的格式,具体可以参考my_multiple_input_test.py;
2.目前pytorch和onnx暂不支持lstm,tensorflow有些可以支持;

my_multiple_input_test.py:
  1. import torch
  2. from rknn.api import RKNN
  3. import numpy as np

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

  5.     def __init__(self):
  6.         super(Net, self).__init__()

  7.         self.conv1 = torch.nn.Conv2d(1,6,3)
  8.         self.conv2 = torch.nn.Conv2d(2,12,3)
  9.         self.conv3 = torch.nn.Conv2d(3,24,3)

  10.     def forward(self, x, y, z):
  11.         x = self.conv1(x)
  12.         y = self.conv2(y)
  13.         z = self.conv3(z)

  14.         return x,y,z

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

  17. def cos_d(vector1, vector2):
  18.     d = np.dot(vector1, vector2) / (np.linalg.norm(vector1) * (np.linalg.norm(vector2)))
  19.     print(d)


  20. if __name__ == '__main__':

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


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

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

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

  41.     ret = rknn.init_runtime(target='rk1808',device_id='7e9f3eb02ede60e8')
  42.     if ret != 0:
  43.         print('Init runtime environment failed')
  44.         exit(ret)


  45.     rknn_r = rknn.inference(inputs=[i1.numpy(), i2.numpy(), i3.numpy()],
  46.                             data_type='float32',
  47.                             data_format='nchw')
  48.     pytorch_r = net(i1,i2,i3)


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

  52.         E_D(d1, d2)
  53.         cos_d(d1, d2)

  54.         print()


复制代码

回复

使用道具 举报

xsky

中级会员

积分
388
 楼主| 发表于 2020-2-26 20:49:47 | 显示全部楼层
jefferyzhang 发表于 2020-2-26 09:50
NPU部门回复:
1.支持多输入多输出,多个输入时shape可以不一样,但是输入要按照nchw的格式,具体可以参考m ...

好的,谢谢
回复

使用道具 举报

testcy

新手上路

积分
6
发表于 2021-1-20 16:39:40 | 显示全部楼层
多输入,在做量化时,'./dataset.txt' 应该怎么样输入呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表