rockchip-linux / rknn-toolkit2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

需求:提供手动构建计算图/动态调用NPU的API (类似rknpu_ddk)

happyme531 opened this issue · comments

目前RKNN-Toolkit2只支持将深度学习框架导出的模型文件转换成RKNPU2适用的模型文件,使用场景很受限:

  1. 模型转换工具只支持X64架构,正常情况下无法在板端运行,如果模型存在动态变化的情况会造成很大问题(例如,对于一些输入Shape多变的模型无法做到根据输入情况调整使用的Shape),且理论上能在板子上完成的全套流程现在还需要用在x64系统上操作,带来很多不便。
  2. 使用复杂,如果程序要调用NPU进行运算,例如卷积操作,需要根据要进行的运算使用ONNX提供的API构建模型,构建后保存为ONNX文件,再调用RKNN-Toolkit2转换为RKNN模型(别忘了这一步只能在x64系统上完成),之后发送到板端运行。
  3. 无法使用NPU的量化运算能力。RKNN只支持FP32/FP16精度的ONNX模型,虽然可以在模型转换过程中进行量化,但如果已有量化后的模型,但RKNN-Toolkit2不支持这样的格式(例如Relay QNN),则目前没有API可以进行模型转换。
  • RKNPU2已经有了动态计算矩阵乘法的API,但这个NPU看起来真不适合做矩阵乘法(矩阵比较大时运算速度特别慢)(参考ggerganov/llama.cpp#722 (comment) )。但NPU很适合做卷积,结果没有卷积API。能考虑在这个基础上扩展一下功能,支持下卷积,池化操作吗?

需求:提供可以手动构建计算图/动态调用NPU的API。例如ARM Compute Library中的实现:

        //conv1 << pool1 << conv2 << pool2 << fc1 << act1 << fc2 << smx
        graph << common_params.target << common_params.fast_math_hint
              << InputLayer(input_descriptor, get_input_accessor(common_params))
              << ConvolutionLayer(
                     5U, 5U, 20U, get_weights_accessor(data_path, "/cnn_data/lenet_model/conv1_w.npy", weights_layout),
                     get_weights_accessor(data_path, "/cnn_data/lenet_model/conv1_b.npy"), PadStrideInfo(1, 1, 0, 0))
                     .set_name("conv1")
              << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, operation_layout, PadStrideInfo(2, 2, 0, 0)))
                     .set_name("pool1")
              << ConvolutionLayer(
                     5U, 5U, 50U, get_weights_accessor(data_path, "/cnn_data/lenet_model/conv2_w.npy", weights_layout),
                     get_weights_accessor(data_path, "/cnn_data/lenet_model/conv2_b.npy"), PadStrideInfo(1, 1, 0, 0))
                     .set_name("conv2")
              << PoolingLayer(PoolingLayerInfo(PoolingType::MAX, 2, operation_layout, PadStrideInfo(2, 2, 0, 0)))
                     .set_name("pool2")
              << FullyConnectedLayer(500U,
                                     get_weights_accessor(data_path, "/cnn_data/lenet_model/ip1_w.npy", weights_layout),
                                     get_weights_accessor(data_path, "/cnn_data/lenet_model/ip1_b.npy"))
                     .set_name("ip1")
              << ActivationLayer(ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)).set_name("relu")
              << FullyConnectedLayer(10U,
                                     get_weights_accessor(data_path, "/cnn_data/lenet_model/ip2_w.npy", weights_layout),
                                     get_weights_accessor(data_path, "/cnn_data/lenet_model/ip2_b.npy"))
                     .set_name("ip2")
              << SoftmaxLayer().set_name("prob") << OutputLayer(get_output_accessor(common_params));

https://github.com/ARM-software/ComputeLibrary/blob/afb5a987d084e14a161b63eff916f5c0519d366f/examples/graph_lenet.cpp#L79-L103

或者类似rknpu_ddk的实现
https://github.com/airockchip/rknpu_ddk

这个API用于和其它深度学习框架(例如TVM, ONNXRuntime)整合,只需要提供几个RKNPU2支持程度最好的算子即可,其它算子可以使用原框架的实现。

但这个NPU看起来真不适合做矩阵乘法(矩阵比较大时运算速度特别慢)

是的但不只,batch size 只有 1 時候FP16上限只有11 GFLOPS。就算 batch size 很大,運算性能峰值的位置很不對。在 B x 1024 x 8192 上。但 LLM 中需要對方矩陣計算,LLaMA2 7B 上為 4096。但這時 NPU 性能就不行了