OwLite로 YOLOv5 모델 경량화하기 2/3 — Experiment 생성, Quantization option 적용하기

1편에 이어서, OwLite를 사용해 Experiment를 생성하고 Quantization option을 적용하는 과정을 소개합니다.

Sarang Kim
SqueezeBits Team Blog
14 min readSep 20, 2024

--

스퀴즈비츠에서 출시한 AI 경량화 툴킷OwLite는 AI 모델을 간편하게 경량화할 수 있도록 도와드립니다. 1편에 이어 OwLite를 활용하여 YOLOv5 모델을 경량화하는 과정을 소개할 예정인데요, 이번 글에서는 등록한 Baseline 모델에 다양한 경량화 옵션을 적용하고 가장 빠른 모델을 선택하는 과정을 보여드리겠습니다.

OwLite 사용 환경을 설정하고 Basline을 등록하는 방법은 1편을 참고해주세요!

Experiment 생성

OwLite에서는 여러 Experiment를 생성해 다양한 경량화 옵션을 비교할 수 있습니다. 먼저 프로젝트 페이지에서 등록한 Baseline의 경량화 옵션 파일(Compression config)을 생성해보겠습니다.

⊕ 버튼을 클릭해서 나타난 팝업에 Experiment 이름을 입력합니다

프로젝트 리스트 탭의 Baseline 행에서 가장 오른쪽에 있는 ⊕ 버튼을 누르면 Create experiment 팝업이 나타납니다. 나타난 팝업의 텍스트 박스에 생성하고 싶은 Experiment의 이름을 입력하고 Enter 버튼을 누르면 에디터 화면으로 진입합니다.

에디터 화면에 진입하면 모델의 그래프가 나타납니다

에디터 화면 중앙에서는 등록한 Baseline 모델의 ONNX 그래프를 확인할 수 있습니다. 화면에서 스크롤과 확대/축소가 가능하여 다양한 크기의 모델도 쉽게 확인할 수 있습니다.

Nodes breakdown을 켠 화면

왼쪽 탭의 Nodes breakdown에서 Benchmark latency 결과를 확인하면, 각 TensorRT 노드별 latency와 전체에서 차지하는 비율을 latency가 큰 순서대로 살펴볼 수 있습니다. 또한, 토글을 활성화하면 색상의 농도로 각 노드의 latency를 시각적으로 확인할 수 있습니다. 위 그림에서는 가장 진하게 표시된 Conv 노드가 다른 노드들보다 높은 latency를 차지하고 있음을 알 수 있습니다.

경량화 옵션 설정

1. Latency의 가장 큰 부분을 차지하는 Layer Quantize

모델의 어느 부분을 경량화 할지 결정하기 위해 Nodes breakdown에서 어느 노드가 가장 많은 latency를 차지하는지 확인해 볼까요?

Nodes breakdown 리스트 가장 위에 있는 노드를 클릭했습니다

Nodes breakdown 리스트의 가장 첫번째 노드는 Reshape 노드였고, YOLOv5 모델 하단의 Reshape 노드가 가장 큰 latency를 차지하고 있음을 알 수 있었습니다.

Nodes breakdown 리스트의 위에서 두번째에 있는 노드를 클릭했습니다

리스트에서 두 번째로 큰 latency를 차지하는 노드 역시 Reshape 노드임을 확인했습니다.

세번째로 큰 latency를 차지하고 있는 노드를 클릭했습니다

세 번째로 큰 latency를 차지하고 있는 노드에서 Conv Layer를 발견했습니다. 이 노드는 모델의 가장 앞 부분에 위치한 블록으로, 이를 경량화해보기로 했습니다.

노드를 클릭하면 경량화를 적용할 수 있는 팝업이 나타납니다

노드 블록을 클릭하여 나타나는 팝업에서 Compression 토글을 눌러 경량화를 적용한 후, 저장 버튼을 눌러 설정을 기록합니다. 그런 다음, 작업하던 파이썬 코드로 돌아가 앞서 작업한 quantize Experiment를 불러옵니다.

owl = owlite.init(project="object_detection", baseline="yolov5s", experiment="quantize")

기존에 Baseline을 등록했던 Init 함수에 experiment=“quantize” 부분을 추가함으로써 에디터에서 생성한 Experiment를 코드에 반영할 수 있습니다.

model = owl.convert(model.eval(), example_input)

이렇게 생성된 owl 인스턴스로 Convert 함수를 실행하면, 모델이 에디터에서 작업한 옵션대로 경량화 된 모델로 변환됩니다. Init 외의 코드는 Baseline을 등록할 때와 동일하므로, 더 이상의 수정 없이 train.py 코드를 실행하여 benchmark를 실행했습니다.

“quantize” Experiment가 추가된 project list 화면

quantize Experiment의 benchmark 결과를 확인해 보니, 경량화 이전의 Baseline모델보다 latency가 오히려 증가한 것을 확인했습니다.

Nodes breakdown의 노드에 마우스를 올리면 노드 이름 전체 정보를 볼 수 있습니다

quantize Experiment의 Nodes breakdown을 다시 확인해보니, 경량화로 인해 추가된 Quantizer의 latency가 해당 레이어를 Quantize해서 얻는 이득보다 커서 전체적으로 latency가 증가한 것으로 보였습니다.

2. Compress Conv Layers

이번에는 Conv 레이어 전체에 경량화 옵션을 적용하기 위해 conv_only라는 이름의 Experiment를 생성했습니다.

OpType이 Conv인 모든 layer에 Compression 을 적용합니다

에디터 왼쪽 탭의 OpType 설정을 통해 Conv 레이어 전체에 Compression 설정을 적용했습니다.

owl = owlite.init(project="object_detection", baseline="yolov5s", experiment="conv_only")

앞선 Experiment를 실행했던 train.py 코드에서 Init 함수에서 불러올 Experiment 이름을 수정해주고, 코드를 실행합니다.

프로젝트 리스트 화면에 conv_only Experiment 결과가 추가되었습니다

Baseline과 conv_only Experiment를 비교한 결과는 아래와 같았습니다:

1. 모델 사이즈가 3배 이상 지나치게 감소함.
2. 경량화 후에도 latency가 개선되지 않음.
3. mAP가 0으로, 모델의 기능이 유지되지 않음.

터미널에서 “not calibrated” 경고 메시지를 확인했습니다

Experiment를 Export할 때 터미널에 출력된 경고 메시지를 통해 모델의 기능이 유지되지 않은 이유를 알 수 있었습니다.

Compression config가 적용된 모델의 calibration을 수행하지 않았기 때문에 기능이 유지되지 않았던 것입니다. 의미 있는 실험 결과를 얻기 위해서는 경량화 후 PTQ (Post-Training Quantization) calibration 과정을 반드시 거쳐야 합니다.

1. 모델의 예측 성능: Calibration 과정은 모델의 step_size를 훈련 데이터와 유사한 분포로 조정해줍니다. 이를 통해 입력 데이터에 대해 더 정확한 예측을 할 수 있습니다. OwLite에서는 quantizer의 step_size를 1로 초기화하기 때문에, calibration을 수행하지 않으면 모델 성능이 저하될 수 있습니다.
2.
모델 크기와 latency: TensorRT는 ONNX 모델을 변환하는 과정에서 layer fusing 등의 최적화 작업을 진행합니다. 그러나 step_size가 실제 배포 환경과 다르게 설정되면, 모델의 크기와 latency에서 예상치 못한 결과가 나올 수 있습니다.

3. Calibrate Model

owl = owlite.init(project="object_detection", baseline="yolov5s", experiment="conv_only_calib", duplicate_from="conv_only")

Init 함수의 duplicate_from 옵션을 이용하면, 특정 Experiment의 경량화 옵션을 복제하여 Experiment를 생성할 수 있습니다. experiment에 새로 생성할 Experiment의 이름을, duplicate_from에 복제할 Experiment의 이름을 입력합니다. conv_only Experiment를 복제해서 conv_only_calib Experiment를 만들었습니다.

### OwLite ###
with owlite.calibrate(owlite_model):
for i, (imgs, _, _, _) in enumerate(train_loader):
if i > 0 and i >= 256 // batch_size:
break
imgs = imgs.float()/255
owlite_model(imgs.to(device))

Experiment 모델의 Convert한 후, 위의 calibrate 코드를 추가하여 모델 내 quantizer의 step_size를 업데이트했습니다.

train 코드에 calibrate 코드를 추가했습니다

이 과정에서 train 데이터셋을 활용하므로, 해당 코드를 train_loader 선언 후에 추가했습니다.

conv_only_calib experiment가 프로젝트 리스트에 추가되었습니다

Calibrate 과정을 수행한 결과, Baseline과 비슷한 수준의 mAP를 얻을 수 있었습니다. 하지만 Conv layer 전체를 경량화하는 OpType 설정만으로는 latency를 크게 개선할 수 없었습니다.

4. Recommended setting

경량화를 효과적으로 적용해 latency를 줄이려면 어떻게 해야 할까요?

OwLite는 사용자가 최적의 경량화 옵션을 적용할 수 있도록 Recommended Setting 기능을 제공합니다. 이 기능을 통해 각 모델의 latency 개선에 최적인 Compression config를 얻을 수 있습니다.

“recommend” Experiment의 에디터 화면

새로운 경량화 옵션을 적용하기 위해, recommend 라는 이름으로 새Experiment를 생성했습니다. 에디터 화면 왼쪽 상단에 있는 Tools 메뉴에서 Recommended Setting을 클릭한 후, 열린 팝업에서 Trust Me 버튼을 누르면 자동으로 적절한 quantization option이 적용됩니다.

Recommended setting이 적용된 에디터 화면입니다

이때, Recommended Setting이 적용되면 기존에 설정해 둔 경량화 옵션이 덮어씌워지니 유의해주세요! 필요하다면 Recommended Setting을 적용한 후에도 추가로 경량화 옵션을 조정할 수 있습니다.

owl = owlite.init(project="object_detection", baseline="yolov5s", experiment="recommend")
recommend experiment가 추가된 project list 화면

프로젝트 리스트에서 Recommended setting 을 적용한 모델이 Baseline 모델보다 latency가 개선되었음을 확인할 수 있었습니다. (16.088 ms -> 11.796 ms) 그러나 경량화를 통해 latency를 개선한 모델의 mAP가 Baseline 모델에 비해 소폭 하락했음을 확인했습니다. (33.3 mAP -> 31.8 mAP)

5. Calibration option 변경

모델마다 데이터 분포가 다르기 때문에, quantizer의 step size를 결정하는 알고리즘에 따라 모델의 정확도가 달라질 수 있습니다. 이에 따라 OwLite는 기본 설정인 AbsMax 외에도 MSE, Percentile, Entropy 등의 PTQ calibration 옵션을 지원합니다. 앞에서 경량화한 모델의 mAP를 향상시키기 위해 recommend Experiment를 복제하고, PTQ calibration 옵션을 MSE로 변경했습니다.

recommend Experiment를 복제해서 recommend_mse Experiment를 생성했습니다

생성한 recommend_mse Experiment의 에디터 화면에서 먼저 OpType 설정의 PTQ calibration 옵션을 MSE로 변경합니다. 이후, 에디터의 검색 기능을 사용해 각 레이어에 적용된 설정을 변경했습니다.

검색창의 SETTING 탭에 AbsMax를 검색해서 나온 결과를 선택했습니다

Cmd+F(Ctrl+F) 키를 눌러서 열린 검색 창의 SETTING 탭에서 ‘AbsMax’를 검색한 후 나온 모든 결과를 선택합니다. 이때 왼쪽에 나타나는 Layer 팝업에서 선택된 노드에 적용된 옵션 정보를 확인할 수 있습니다.

선택된 노드에 적용된 PTQ calibration 옵션을 변경하려고 했으나, input의 precision이 mixed로 설정되어 있어 옵션 변경이 비활성화된 상태였습니다. 각 OpType마다 input이 다르기 때문에, 같은 OpType끼리 차례로 PTQ calibration 옵션을 변경했습니다.

노드에 적용된 옵션을 OpType 별로 나눠 변경했습니다
owlite.init(project="object_detection", baseline="yolov5s", experiment="recommend_mse")
프로젝트 리스트에 recommend_mse Experiment가 추가되었습니다

MSE calibrator로 변경한 experiment에서 AbsMax calibrator를 사용했을 때보다 mAP가 향상된 결과를 얻을 수 있었습니다. (31.8 mAP -> 32.5 mAP)

이렇게 다양한 옵션을 적용하여 Baseline 모델의 latency를 줄이고, 성능 지표인 mAP는 Baseline에 가까운 경량화 모델을 얻을 수 있었습니다. 다음 편에서는 실제 배포를 전제로, Quantization-aware training을 활용하여 mAP를 베이스라인 수준으로 회복시키고 Dynamic batch size 모델을 생성하는 과정을 살펴보겠습니다!

지금 바로 OwLite를 사용해 보고 싶으시다면 여기를 방문하세요!

--

--