7.8. 텐서 I/O

엔진은 입력 측에서 단일 텐서를 받아 출력 측에서 하나 이상을 생성합니다. 이 텐서들은 numpy 장에서 소개한 형태, dtype, 디스크립터 어휘를 가진 ndarray 객체입니다. 그 형태와 dtype은 모델 파일에서 오며 input_shape / output_shapeinput_dtype / output_dtype 을 통해 보고됩니다.

7.8.1. 양자화

카메라가 실행하는 대부분의 신경망은 카메라의 RAM 및 연산 예산 안에 들어맞도록 양자화된 정수 텐서 – int8 또는 uint8 – 로 동작합니다. 양자화된 텐서는 텐서별 스케일과 제로 포인트를 통해 실수값을 표현하는 정수값을 담습니다:

\[\text{real} = \text{scale} \times (q - \text{zero_point})\]
\[q = \mathrm{round}(\text{real} / \text{scale}) + \text{zero_point}\]

스케일과 제로 포인트는 모델의 학습 시점 보정에서 비롯되며 모델 파일에 저장됩니다. 이들은 input_scale, input_zero_point, output_scale, output_zero_point 로 노출되며 – 각각 입력 또는 출력 텐서마다 하나의 항목을 갖는 리스트입니다.

ml.utils.quantize()ml.utils.dequantize() 는 지정된 출력 인덱스에 대해 이 공식을 적용합니다:

import ml.utils

real_tensor = ml.utils.dequantize(model, q_tensor, index=0)
q_tensor    = ml.utils.quantize(model, real_tensor, index=0)

두 함수 모두 주어진 인덱스의 출력 dtype이 이미 float인 경우 값을 변경하지 않고 반환하므로, 모델의 양자화 상태에 관계없이 호출이 안전합니다.

7.8.2. 출력 측에서 스크립트가 보는 것

predict() 가 반환하는 것은 후처리기가 등록되어 있는지에 따라 달라집니다.

후처리기가 없으면 엔진의 원시 정수 출력은 float로 자동 역양자화 되어 float ndarray 객체의 리스트로 반환됩니다. 스크립트는 바로 읽을 수 있는 실수값을 받습니다. 이것은 분류 신경망에 맞는 경로로, 분류 신경망의 단일 출력 텐서는 이미 애플리케이션이 순회하는 클래스별 신뢰도 점수의 리스트이므로 디코딩 단계가 필요 없습니다. 알 수 없는 모델을 빠르게 실행해 보거나 REPL에서 임시로 살펴보기에도 쉬운 경로입니다.

후처리기가 등록되어 있으면(생성자의 postprocess= 또는 predict 호출의 callback= 을 통해), 원시 양자화 텐서가 후처리기의 호출 가능 객체에 직접 넘겨집니다. 후처리기는 원시 양자화 텐서를 받으며 필요한 역양자화는 무엇이든 스스로 책임집니다.

이 구분은 성능 선택입니다. 자동 역양자화는 각 출력마다 새로운 float 텐서를 할당하고 모든 요소를 훑습니다. 각 텐서에서 몇 개의 값만 필요한 후처리기 – 신뢰도 점수에 임계값을 적용한 다음 살아남은 것들에 대해서만 경계 상자를 디코딩 – 는 나머지를 역양자화하는 비용을 건너뜁니다. ml.postprocessing 아래에 출하되는 경계 상자 디코더는 모두 이 경로를 택하며, ml.utils.threshold() 는 바로 이 경우를 위해 만들어졌습니다: 양자화된 점수 텐서를 받아 전체 텐서를 역양자화하지 않고 역양자화된 값이 실수값 임계값을 통과하는 인덱스를 반환합니다.