1. XNNPACK이란?
XNNPACK은 아래와 같은 다양한 device(architecture)를 위해 floating-point neural netowrk의 inference operator를 최적화한 library입니다. (floating-point란 fp32, fp16 모델만 가속화 가능하다는 뜻입니다.) 한마디로 DL 모델의 inference속도를 가속화 해주는 library입니다.
Desktop기준으로 XNNPACK을 사용하기 위해서는 bazel build할때 XNNPACK사용에 대한 명시를 해주어야 합니다. 그리고 TFLite모델에만 사용이 가능합니다. 또 다른 특징으로는 XNNPACK은 PAD operator와 CONV_2D operator(with VALID padding)을 감지하여 하나의 convolution operator로 fusing해주는 역할도 합니다.
1.1 Supported architectures
- ARM64 on Android, Linux, macOS, and IOS
- ARMv6 (with VFPv2) on Linux
- x86 and x86-64 (up to AVX512) on Windows, Linux, macOs, Android, and IOS simulator
- WebAssembly MVP and SIMD
- RISC-V
- ...
위와 같이 XNNPACK의 지원범위는 넓네요. ARM CPU, Intel CPU, Chrome과 같이 web에서 사용되는 WebAssembly 심지어 축소된 명령어 세트로만 설계된 RISC-V에도 XNNPACK이 사용가능합니다. (XNNPack이 구현되어있는 neural network operator는 공식 repo 참고하세요! CNN계열은 거의 다 있네요...) 다양한 device환경에서 모두 사용될 수 있다는 점에서 generality가 좋고 실제로 사용해보면 inference time성능이 매우 좋아집니다.
이번 글에서는 benchmark tool 를 통해 XNNPACK을 사용하였을 때와 아닐 때를 비교하며 inference time에 대한 성능비교를 해보겠습니다.
2. XNNPACK 성능 비교
2.1 Environment Setting
2.1.1 Docker environment
bazel build를 통해 TFLite모델을 benchmark할 수 있는 환경을 docker image로 만들어놓았습니다. 해당 benchmark tool을 통해 XNNPACK사용 했을 경우와 아닌경우의 inference time차이를 볼것이며 profiling기능까지 제공하므로 profile을 통해 각 모델에 대한 inference time에 대한 분석 또한 해보겠습니다.
docker image는 아래 명령어로 받을 수 있습니다.
docker pull da2so/tf_bazel:latest
해당 image를 다운받으셨다면 아래 명령어를 통해 container를 만들어 들어가서 benchmark tool을 실행 해봅시다!
# Option 1: GPU 있을 시
docker run -it -d --gpus '"device=0"' --ipc=host --name da2so_test -p 3322:3322 -v /test/:/usr/src/app da2so/tf_bazel:latest /bin/bash
# Option 2: GPU 없을 시
docker run -it -d --ipc=host --name da2so_test -p 3322:3322 -v /test/:/usr/src/app da2so/tf_bazel:latest /bin/bash
docker attach da2so_test
# in container
cd tensorflow_src
bazel-bin/tensorflow/lite/tools/benchmark/benchmark_model --help
정상적으로 동작했다면 아래와 같을 것입니다. 저는 GPU를 사용하는 option으로 docker container를 생성하였습니다.
2.1.2 Models
XNNPACK inference time성능 비교에 사용된 TFLite 모델은 다음과 같습니다.
- Classification
- MobileNetv2, v3 모두 depth multiplier 0.75사용
Model (data type) | Model size (MB) |
MobileNetv2 (FP32) | 10.6 |
MobileNetv2 (FP16) | 5.3 |
MobileNetv3 (FP32) | 16.0 |
MobileNetv3 (FP16) | 8.1 |
EfficientNetv2_B0 (FP32) | 28.5 |
EfficientNetv2_B0 (FP16) | 14.3 |
- Object detection
Model (data type) | Model size (MB) |
yolov5s (FP32) | 29.0 |
yolov5s (FP16) | 14.5 |
yolov7 (FP32) | 147.7 |
yolov7 (FP16) | 73.9 |
모든 모델은 여기서 다운받을 수 있습니다.
2.1.3 Device info
Inference에 사용되는 device정보는 다음과 같습니다.
- CPU: Intel(R) Xeon(R) Gold 5120 CPU @ 2.20GHz (56 core)
2.2 Benchmark tool로 inference time 측정 예시
Benchmark tool로 yolov5s (fp32) 모델의 inference time을 측정하는 예시를 보여드립니다. bazel-bin/tensorflow/lite/benchmark/benchmark_model
명령어로 모델의 inference time을 측정가능합니다. 아래에서는 XNNPACK을 사용하지 않았으며 warm up으로 10번 후, average inference time을 재기위해 100번 inference진행하였습니다.
위의 결과를 보시면 yolov5s의 model path, model size, inference time, memory footprint까지 출력되는 것을 알 수 있습니다. CPU로 측정된 yolov5s (fp32)의 average inference time은 513.534ms (0.5초정도) 인것을 확인가능합니다.
※ 참고로 use_gpu옵션을 주어 gpu acceleration을 할 수 있는 데 gpu acceleration은 Android 또는 iOS platform에서 사용가능하다고 하네요.
2.3 XNNPACK 성능비교
아래 명령어를 통해 위에서 언급드린 TFLite모델들에 대해 XNNPACK을 사용했을 경우와 아닌 경우에 대한 inference time 성능 비교를 해보겠습니다. 추가로 thread수를 늘렸을 때 성능또한 어떻게 변화하는 지 알아보도록 하죠!
bazel-bin/tensorflow/lite/tools/benchmark/benchmark_model \
--graph=${model_path} \
--use_xnnpack=true (or false) \
--warmup_runs=10 \
--num_runs=100 \
--num_threads=1 (or 2, 4)
2.3.1 Classifcation Results
아래는 thread수를 1기준으로 측정하였습니다.
Model (data type, model size) | USE_XNNPACK | Inference time (ms) |
MobileNetv2 (FP32, 10.6MB) | True | 11.746 ± 0.1 |
MobileNetv2 (FP32, 10.6MB) | False | 24.344 ± 2.5 |
MobileNetv2 (FP16, 5.3MB) | True | 11.745 ± 0.3 |
MobileNetv2 (FP16, 5.3MB) | False | 23.677 ± 1.5 |
MobileNetv3 (FP32, 16MB) | True | 10.346 ± 0.3 |
MobileNetv3 (FP32, 16MB) | False | 20.946 ± 1.1 |
MobileNetv3 (FP16, 8.1MB) | True | 10.444 ± 0.4 |
MobileNetv3 (FP16, 8.1MB) | False | 20.745 ± 1.3 |
EfficientNetv2_B0 (FP32, 28.5MB) | True | 38.183 ± 3.1 |
EfficientNetv2_B0 (FP32, 28.5MB) | False | 68.230 ± 3.2 |
EfficientNetv2_B0 (FP16, 14.3MB) | True | 37.895 ± 1.0 |
EfficientNetv2_B0 (FP16, 14.3MB) | False | 69.594 ± 2.7 |
위의 결과에서 분석 내용은 다음과 같습니다.
- XNNPACK을 사용하였을때 2배이상 inference 속도가 빨라짐을 확인
- FP32와 FP16간의 model size는 차이가 많이 나지만 실제 inference 속도는 거의 비슷함
- MobileNetv3가 MobileNetv2에 비해 model size는 더 크지만 inference 속도가 더 빠름
2.3.2 Object detection Results
Model (data type, model size) | USE_XNNPACK | Inference time (ms) |
yolov5s (FP32, 29.0MB) | True | 403.578 ± 5.5 |
yolov5s (FP32, 29.0MB) | False | 512.900 ± 19.9 |
yolov5s (FP16, 14.5MB) | True | 407.494 ± 18.5 |
yolov5s (FP16, 14.5MB) | False | 516.036 ± 34.6 |
yolov7 (FP32, 147.7MB) | True | 2420.893 ± 41.0 |
yolov7 (FP32, 147.7MB ) | False | 2199.132 ± 41.1 |
yolov7 (FP16, 73.9MB) | True | 2424.714 ± 41.3 |
yolov7 (FP16, 73.9MB) | False | 2232.653 ± 54.3 |
위의 결과에서 분석 내용은 다음과 같습니다.
- yolov5s 모델의 경우 XNNPACK을 사용했을 때 inference 속도가 빨라짐
- classification모델의 경우 2배정도 inference time이 줄었는데 모델이 커져서 XNNPACK의 효과가 작아진 건가..?
- yolov7 모델의 경우는 XNNPACK의 효과가 없는 것으로 보임
- 모델이 너무 커서 그런것인가..?
2.3.3 Thread 수에 따른 inference time results
thread 수에 따른 inference time을 비교하기 위해 yolov5s 모델 기준으로 측정해보았습니다.
Model (data type, model size) | USE_XNNPACK / Thread num | Inference time (ms) |
yolov5s (FP32, 29.0MB) | True / 1 | 403.578 ± 5.5 |
yolov5s (FP32, 29.0MB) | True / 2 | 228.207 ± 16.8 |
yolov5s (FP32, 29.0MB) | True / 4 | 142.095 ± 11.6 |
yolov5s (FP32, 29.0MB) | False / 1 | 1022.063 ± 7.5 |
yolov5s (FP32, 29.0MB) | False / 2 | 733.723 ± 17.7 |
yolov5s (FP32, 29.0MB) | False / 4 | 513.892 ± 15.0 |
yolov5s (FP16, 14.5MB) | True / 1 | 407.494 ± 18.5 |
yolov5s (FP16, 14.5MB) | True / 2 | 231.054 ± 10.7 |
yolov5s (FP16, 14.5MB) | True / 4 | 138.392 ± 8.2 |
yolov5s (FP16, 14.5MB) | False / 1 | 1020.223 ± 6.4 |
yolov5s (FP16, 14.5MB) | False / 2 | 734.001 ± 21.5 |
yolov5s (FP16, 14.5MB) | False / 4 | 506.902 ± 15.4 |
위의 결과에서 분석 내용은 다음과 같습니다.
- (A) XNNPACK을 사용하지 않고 thread를 4개를 쓴 경우가 (B) XNNPACK을 사용하고 thread수가 1일경우보다 inference time오래 걸림을 알 수 있음
- (A)'s inference time: 513.892 ± 15.0 (FP32), 506.902 ± 15.4 (FP16)
- (B)'s inference time: 403.578 ± 5.5 (FP32), 407.494 ± 18.5(FP16)
- XNNPACK을 사용하고 thread num이 4인경우가 가장 inference time 성능이 가장 좋음 (초록색)
'AI Engineering > TensorFlow' 카테고리의 다른 글
TensorFlow.js (4) YOLOv5 Live demo (7) | 2022.04.11 |
---|---|
TensorFlow.js (3) TensorFlow.js 변환 (0) | 2022.04.03 |
TensorFlow.js (2) - WebGL 기반 hand pose detection (2) | 2022.03.23 |
TensorFlow.js (1) - TensorFlow.js 이해 및 detection 예제 (1) | 2022.03.17 |
Mediapipe (2) - custom segmentation model with mediapipe (0) | 2022.03.14 |