t27.aiEnglish

Потеря в битах

Вы узнаете

Как потеря -log2(p) оценивает догадку в битах и почему безошибочная догадка должна стоить ровно 0.

Запись ещё не готова: она ждёт команд tri test и tri mutate plant из gHashTag/t27#7400, которые запись запускает, а до тех пор виджет ниже -- заглушка без запуска. Обучение начинается с числа, которое говорит, насколько неверной была догадка. gft_nll.t27 берёт p, вероятность, которую модель дала верному классу, и возвращает -log2(p): p = 1.0 стоит 0, p = 0.5 стоит 1 бит, а p = 0.25 стоит 2. on_comb — это neg(log2v(p)), и neg переворачивает бит знака, но для 0 возвращает 0. Одна строка заголовка всё ещё говорит, что на выходе log2(x); код возвращает его с обратным знаком. Браузер пропускает все 3 теста, потому что его исполнитель пока не знает assert_eq; нативный t27c запускает все 3, все проходят, ни один не пустой. Запись заставляет neg возвращать 65536 для 0, ноль с поставленным битом знака, и падает ровно один тест, perfect. Каждый байт в записи напечатала команда; инсценирован только набор текста.

Попробуйте

Найдите в записи изменённую строку и упавший тест; затем найдите в спеке строку заголовка, где сказано, что на выходе log2(x), и сравните её с on_comb.

Открыть интерактивный урок →

gft_nll.t27: recording pending
gft_nll.t27: recording pending ↗

Recording pending: waits on tri test and tri mutate plant from gHashTag/t27#7400. Until then this page is a placeholder and shows no run.

specs/ternary/gft_nll.t27

module GftNll;
// #1764 + GF-T: GF-T negative-log-likelihood (cross-entropy loss for a one-hot
// label) -- given the softmax probability p of the true class, returns the loss
// -log2(p) as a positive GF-T16. Composes the verified gft_log2 primitive with a
// sign flip. log2(x) = (o-40) + log2(1+m/512); the fractional part is
// a Q16 quartic in m, then the integer+fraction real value is normalized
// (fixed->GF-T, flat priority-encoder -> yosys-synthesizable) into a signed GF-T16.
// Accuracy: <=0.008 abs vs true log2 (output-quantization limited). x<=0 saturates.
//
// Input: x positive GF-T16 (u32). Output: log2(x) as signed GF-T16 (u32).

// arithmetic floor-shift by 9 (the poly has negative coefficients, and the
// generated Verilog `>>` on a signed reg is LOGICAL -> would fill 0 for negatives;
// this reproduces Python's floor(x/512) using only non-negative shifts).
fn asr9(v: i32) -> i32 {
    if (v >= 0) { return v >> 9; }
    return 0 - (((0 - v) + 511) >> 9);
}
// round(65536 * log2(1+m/512)) for m in [0,511], Q Horner with rounded shifts.
fn log2_frac(m: i32) -> i32 {
    var p : i32 = 0 - 5528;
    p = asr9(p * m + 256) + 21224;
    p = asr9(p * m + 256) + (0 - 44443);
    p = asr9(p * m + 256) + 94274;
    p = asr9(p * m + 256);
    return p;
}

// encode a positive Q16.16 magnitude `mag` (value = mag/2^16) as a GF-T16 with the
// given sign. Flat left-normalization so the leading 1 lands at bit 30.
fn encode(sign: i32, mag: i32) -> u32 {
    if (mag == 0) { return 0; }
    var acc : i32 = mag;
    var e : i32 = 0;
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    if (acc < 1073741824) { acc = acc << 1; e = e + 1; }
    // acc now in [2^30, 2^31): mantissa = round((acc - 2^30) / 2^21), off = 54 - e.
    var mant : i32 = ((acc - 1073741824) + 1048576) >> 21;
    var off : i32 = 54 - e;
    if (mant >= 512) { mant = 0; off = off + 1; }
    if (off < 1) { off = 1; mant = 0; }
    if (off > 80) { off = 80; mant = 511; }
    return ((sign << 16) | (off << 9) | mant) as u32;
}

fn log2v(x: u32) -> u32 {
    if (x == 0) { return ((1 << 16) | (80 << 9) | 511) as u32; }
    if ((x >> 16) == 1) { return ((1 << 16) | (80 << 9) | 511) as u32; }
    var o : i32 = ((x >> 9) & 127) as i32;
    var m : i32 = (x & 511) as i32;
    var intpart : i32 = o - 40;
    var frac : i32 = log2_frac(m);
    var val : i32 = (intpart << 16) + frac;
    if (val == 0) { return 0; }
    if (val < 0) { return encode(1, 0 - val); }
    return encode(0, val);
}
fn neg(v: u32) -> u32 {
    if (v == 0) { return 0; }
    return v ^ 65536;
}
// cross-entropy loss for one class: -log2(p), p a probability in (0,1].
fn on_comb(p: u32) -> u32 {
    return neg(log2v(p));
}

// p = 1.0 -> loss 0 (perfect prediction).
test perfect { assert_eq(on_comb(20480), 0); }
// p = 0.5 -> loss -log2(0.5) = +1.0 (0x5000).
test half { assert_eq(on_comb(19968), 20480); }
// p = 0.25 -> loss 2.0 (0x5200).
test quarter { assert_eq(on_comb(19456), 20992); }
endmodule

Открыть спеку урока в плеере ↗

Все уроки