Performance Evaluation
모델 변환 성능을 높이기 위한 모니터링 방법
Performance Evaluation 기능이 필요한 이유는 다음과 같습니다.
rknn으로 모델을 변환하거나, 경량화를 진행했을 때 성능이 형편없어졌다고 하면 (대부분 그렇지만) 우리는 어디가 문제인지 알아야 합니다.
예를 들어, 모델의 inference time이 너무 길 때 어느 레이어에서 시간과 자원을 많이 소모하고 있는지 layer by layer로 분석해야 할 필요가 있습니다.
Performance Evaluation
Performance Evaluation 기능은 각각의 레이어에서 얼마만큼의 시간이 소요되었는지 알려줍니다. 이전 챕터에서 다뤘던 Depth Anything을 예시로 계속 진행해 보도록 하겠습니다.
하단의 코드 역시 rknn이 설치되어 있는 Ubuntu 컴퓨터에 adb 모드로 오렌지 파이를 연결하고 실행하는 것을 권장합니다.
import numpy as np
import cv2
from rknn.api import RKNN
if __name__ == '__main__':
# Create RKNN object
rknn = RKNN(verbose=True)
# Pre-process config
print('--> Config model')
rknn.config(
mean_values=[[0.485*255, 0.456*255, 0.406*255]],
std_values=[[0.229*255, 0.224*255, 0.225*255]],
quant_img_RGB2BGR=True,
target_platform='rk3588')
print('done')
# load rknn model
print('--> Load rknn model')
ret = rknn.load_rknn('depth_anything_vits_OP19.rknn')
if ret != 0:
print('Load rknn model failed!')
exit(ret)
print('done')
# Set inputs
img = cv2.imread('front.jpg')
img = np.expand_dims(img, 0)
print('--> List devices')
rknn.list_devices()
# Init runtime environment
print('--> Init runtime environment')
ret = rknn.init_runtime(target='rk3588', perf_debug=True, eval_mem=True, core_mask=RKNN.NPU_CORE_0_1_2)
if ret != 0:
print('Init runtime environment failed!')
exit(ret)
print('done')
print('--> Get sdk version')
sdk_version = rknn.get_sdk_version()
print(sdk_version)
# eval perf
print('--> Eval perf')
rknn.eval_perf()
# eval perf
print('--> Eval memory')
rknn.eval_memory()
# Inference
print('--> Running model')
outputs = rknn.inference(inputs=[img], data_format=['nhwc'])
np.save('./depth_anything_eval_perf.npy', outputs[0])
# show_outputs(outputs)
print('done')
rknn.release()
rknn.eval_perf()
함수를 실행하면 다음과 같은 txt 파일이 생성됩니다.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Network Layer Information Table
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ID OpType DataType Target InputShape OutputShape Cycles(DDR/NPU/Total) Time(us) MacUsage(%) WorkLoad(0/1/2) RW(KB) FullName
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 InputOperator FLOAT16 CPU \ (1,3,480,640) 0/0/0 3 \ 0.0%/0.0%/0.0% 0 InputOperator:image
2 Conv FLOAT16 NPU (1,3,480,640),(384,3,14,14),(384) (1,384,67,90) 324681/28374528/28374528 12600 7.03/7.03/7.03 33.3%/33.3%/33.3% 2977 Conv:/patch_embed/proj/Conv_stride_split
3 Conv FLOAT16 NPU (1,384,67,90),(1,384,1,1) (1,384,34,45) 245492/9216/245492 332 0.12/0.12/0.12 35.3%/32.4%/32.4% 4523 Conv:/patch_embed/proj/Conv_select
4 Reshape FLOAT16 NPU (1,384,34,45),(4) (1,384,1,1530) 99354/0/99354 1 \ 0.0%/0.0%/0.0% 1147 Reshape:/patch_embed/Reshape_output_0_rs
5 Concat FLOAT16 NPU (1,384,1,1),(1,384,1,1530) (1,384,1,1531) 99418/0/99418 195 \ 33.3%/33.3%/33.3% 1148 Concat:/Concat_1
6 Add FLOAT16 NPU (1,384,1,1531),(1,384,1,1531) (1,384,1,1531) 149126/0/149126 206 \ 33.3%/33.3%/33.3% 2296 Add:/Add
7 exNorm FLOAT16 NPU (1,384,1,1531),(1,384,1,1),... (1,384,1,1531) 99548/0/99548 1134 \ 100.0%/0.0%/0.0% 1151 exNorm:/blocks.0/norm1/LayerNorm
8 Conv FLOAT16 NPU (1,384,1,1531),(1152,384,1,1),(1152) (1,1152,1,1531) 236433/1327104/1327104 827 53.32/53.32/53.32 33.3%/33.3%/33.3% 2016 Conv:/blocks.0/attn/qkv/MatMul_2conv
9 Reshape FLOAT16 CPU (1,1152,1,1531),(4) (3,6,64,1531) 0/0/0 3476 \ 0.0%/0.0%/0.0% 3444 Reshape:/blocks.0/attn/Reshape_output_0_squeeze_1_nd_/blocks.0/attn/Transpose
10 Transpose FLOAT16 CPU (3,6,64,1531) (6,64,3,1531) 0/0/0 14819 \ 0.0%/0.0%/0.0% 3444 Transpose:/blocks.0/attn/Transpose_output_0_tp_4/blocks.0/attn/Gather_3_2slice_2split
```
여기서 주의 깊게 보아야 할 항목들은 다음과 같습니다.
DDRCycles (Double Data Rate)
메모리 접근에 필요한 사이클 수 (데이터를 DDR RAM에서 읽거나 쓰는 데 소요되는 사이클)
높은 DDR 사이클은 메모리 병목 현상을 의미할 수 있음
NPUCycles
NPU에서 실제 연산을 수행하는 데 필요한 사이클 수
Time
MacUsage (MAC : Multiply-Accumulate)
a*b+c
NPU에서 제공하는 MAC 유닛의 사용률
100%에 가까울 수록 해당 레이어가 NPU의 MAC 리소스를 효율적으로 사용하고 있다는 의미
높은 MAC usage : 추가적인 최적화 필요 없음
낮은 MAC usage : 추가적인 최적화 여지 있음
WorkLoad
RW
따라서 DDR 사이클이 높은 레이어는 메모리를 최적화하고, NPU 사이클이 높은 레이어는 연산을 최적화하거나 Quantization을 할 필요가 있습니다. Total Cycle이 높은 레이어가 주요한 관찰 대상입니다.
eval_perf
로 생성되는 텍스트 파일 하단에 레이어 순위가 적혀 있으니 이를 참고하시면 좋을 것 같습니다.
---------------------------------------------------------------------------------------------------
Operator Time Consuming Ranking Table
---------------------------------------------------------------------------------------------------
OpType CallNumber CPUTime(us) GPUTime(us) NPUTime(us) TotalTime(us) TimeRatio(%)
---------------------------------------------------------------------------------------------------
exSDPAttention 12 0 0 556747 556747 38.64%
Resize 6 406682 0 0 406682 28.22%
Transpose 12 240229 0 0 240229 16.67%
Reshape 29 81356 0 16 81372 5.65%
Conv 49 0 0 57195 57195 3.97%
ConvExGelu 12 0 0 37473 37473 2.60%
exNorm 28 0 0 30351 30351 2.11%
Split 12 0 0 7569 7569 0.53%
ConvRelu 9 0 0 6054 6054 0.42%
Mul 24 0 0 5070 5070 0.35%
Add 25 0 0 4003 4003 0.28%
ConvTranspose 2 0 0 2898 2898 0.20%
ConvAdd 10 0 0 2878 2878 0.20%
Relu 8 0 0 1305 1305 0.09%
Slice 4 0 0 839 839 0.06%
Concat 1 0 0 195 195 0.01%
OutputOperator 1 80 0 0 80 0.01%
InputOperator 1 3 0 0 3 0.00%
---------------------------------------------------------------------------------------------------
Last updated