8 / 24 · 實作
實作:執行量化契約
以相同 uint8 設定量化 −40。其編碼與反量化值各是多少?你會新增哪個斷言?
單元可免費閱讀,註冊課程即可儲存學習進度。
目標與準備
執行編碼映射、負數同距、飽和與中心化整數內積。此檔案需要 Node.js,不需要外部套件。在新的空資料夾建立 quantize-lab.mjs,複製下列程式碼並執行 node quantize-lab.mjs。沒有 Node 時,可手算完成預測表。若已安裝的 Digital Design Studio 支援此檔案型別的建立或開啟流程,你可在其中手動建立並檢視相同檔案。這些指示不代表 DDS 會自動建立專案或執行程式。
執行前先預測
尺度 0.25、零點 128 時,−0.625 成為同距 −2.5,捨入至偶數 −2,得到編碼 126。輸入 −0.375 也得到 126。零得到 128;0.375 與 0.625 都得到 130。輸入 40 原本會得到 288,因此 uint8 飽和將它改為 255。預測結果為 [126,126,128,130,130,255]。這些案例區分負數同距、正數同距、實數零與裁切。
將 [130,126] 中心化為 [2,−2]。使用權重 [3,−2],總和為十。合併尺度 0.125 代表實數 1.25;輸出尺度 0.25、零點 128 得到 133。程式是數值契約練習,而非模型匯入器或準確率基準測試。
先執行未修改的斷言,再將 0.625 替換為 0.875。修改預期值前,先預測同距 3.5 捨入至四,得到編碼 132。暫時將 roundEven 換成 Math.round,觀察負數同距斷言失敗,再還原。刻意失敗能證明測試有觀察到所需行為。
最後,將飽和編碼 255 反量化:它代表 31.75,相對於 40 的誤差是 −8.25。這遠大於一般半步距捨入上界。選擇尺度涉及範圍與解析度的取捨;量測模型準確率需要另外的模型與資料集。記錄你的預測、命令輸出與修改案例的推理。
可執行檔案
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}));自己試試看
以相同 uint8 設定量化 −40。其編碼與反量化值各是多少?你會新增哪個斷言?
查看解說
未限制的編碼為 −32,因此裁切為零。反量化為 (0−128)×0.25=−32。新增 quantize(−40,0.25,128) 等於零的斷言,以涵蓋負端飽和。