8 / 24 · 실습
실습: 양자화 계약 실행
실수 −40을 같은 uint8 설정으로 양자화하면 코드와 역변환 값은 무엇인가요? 어떤 검사를 추가하겠습니까?
내용은 무료로 볼 수 있습니다. 수강 신청하면 학습 기록을 저장할 수 있어요.
목표와 준비
이 실습은 양자화 코드, 음수 절반 반올림, 포화와 정수 내적을 직접 실행합니다. 외부 패키지를 설치하지 않고 Node.js로 실행할 수 있는 작은 파일입니다. 새 빈 폴더에 quantize-lab.mjs를 만들고 아래 코드를 붙여 넣은 뒤 터미널에서 node quantize-lab.mjs를 실행하세요. Node가 없는 환경에서는 우선 손계산 표를 완성할 수 있습니다. 설치된 Digital Design Studio가 해당 파일을 만들고 열 수 있는 작업 흐름을 지원한다면 그 흐름에서 같은 파일을 수동으로 생성·열어 검토해도 됩니다. 이 안내는 자동 프로젝트 생성이나 DDS 내 실행을 검증했다는 뜻이 아닙니다.
결과를 먼저 예상하기
s=0.25,z=128인 입력 −0.625는 −2.5를 짝수 −2로 반올림해 126을 만듭니다. −0.375의 −1.5도 −2여서 126입니다. 0은 128이고 0.375와 0.625는 모두 130입니다. 40은 반올림과 zero point를 더하면 288이지만 uint8의 최댓값 255로 포화합니다. 출력의 첫 배열은 [126,126,128,130,130,255]여야 합니다. 이 여섯 경우는 음수 절반, 양수 절반, 0과 양의 범위 초과를 각각 검사합니다.
두 입력 코드 [130,126]은 중심값 [2,−2]입니다. 가중치 [3,−2]를 곱하면 정수 누적 10이고 입력·가중치 scale의 곱 0.125를 적용하면 1.25입니다. 출력 scale 0.25,z=128에서는 133입니다. 코드가 실수 0을 기준으로 중심화되었는지 확인하지 않으면 정수 내적이 138처럼 다른 수가 됩니다. 이 코드는 작은 예제의 정확한 반올림 계약을 보여 주며 임의의 모델을 가져오거나 평가하는 도구가 아닙니다.
실행 후 바꿔 볼 조건
먼저 그대로 실행해 모든 assertion이 통과하는지 확인합니다. 다음에 0.625를 0.875로 바꾸고 예상 코드를 계산한 뒤 assertion의 기대값도 바꿉니다. 3.5는 짝수 4로 반올림하므로 코드 132입니다. 기대값만 결과에 맞춰 고치지 말고 계산 근거를 함께 기록하세요. roundEven을 Math.round로 바꿔 음수 절반 검사가 실패하는지 확인하고 원래 함수로 되돌립니다. 의도적인 실패는 검사가 실제 계약을 감시한다는 근거가 됩니다.
이후 포화된 입력의 역변환 값을 계산합니다. 코드 255는 31.75를 나타내므로 원래 40과의 차이는 −8.25입니다. 이 오차는 격자 사이 반올림보다 큽니다. 입력 범위와 scale을 정할 때 정상 데이터와 드문 큰 값 사이의 선택이 생긴다는 것을 보여 줍니다. 정확도나 데이터 분포를 평가하려면 별도의 모델과 데이터가 필요합니다.
실행 코드
import assert from 'node:assert/strict';
// An exact tie is handled with nearest-even, including negative input.
export function roundEven(v) {
const f = Math.floor(v), d = v - f;
return d < 0.5 ? f : d > 0.5 ? f + 1 : f % 2 === 0 ? f : f + 1;
}
export const quantize = (x, s, z) => Math.min(255, Math.max(0, roundEven(x / s) + z));
const values = [-0.625, -0.375, 0, 0.375, 0.625, 40];
const codes = values.map(x => quantize(x, 0.25, 128));
assert.deepEqual(codes, [126, 126, 128, 130, 130, 255]);
assert.equal(roundEven(-1.5), -2);
assert.equal(roundEven(-2.5), -2);
const xq = [130, 126], wq = [3, -2];
const acc = xq.reduce((sum, x, i) => sum + (x - 128) * wq[i], 0);
assert.equal(acc, 10);
assert.equal(acc * 0.25 * 0.5, 1.25);
assert.equal(quantize(1.25, 0.25, 128), 133);
console.log(JSON.stringify({codes, acc, real: 1.25, output: 133}));직접 생각해 보기
실수 −40을 같은 uint8 설정으로 양자화하면 코드와 역변환 값은 무엇인가요? 어떤 검사를 추가하겠습니까?
해설 보기
−40/0.25+128=−32이므로 코드 0으로 포화합니다. 역변환은 (0−128)×0.25=−32입니다. quantize(−40,0.25,128)가 0인지 확인하는 assertion을 추가해 음의 포화도 검사합니다.