Потеря в битах
Вы узнаете
Как потеря -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.

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
Все уроки
Модуль 1 · Лаборатория: наши исследования
Свой формат чисел, честная таблица результатов и таблицы модели, перемноженные на плате.
Модуль 2 · ИИ-числа: блок MX
Как ИИ-чипы хранят веса в нескольких битах: один общий масштаб на блок, сам байт масштаба и что один выброс делает с соседями.
Модуль 3 · Тернарные веса
Веса, которые бывают только минус масштаб, ноль или плюс масштаб, пять правил, которые должен пройти тернарный алфавит, и прогон тестов, который ничего не проверил.
Модуль 4 · Тернарный формат Ternary Network Float
Правило, которое компилятор проверяет до запуска любого теста, и 17-битное число с плавающей точкой, порядок которого — четыре сбалансированных трита.
Модуль 5 · Арифметика чисел со знаком
Умножить два числа со знаком, сложить их, когда знаки разные, и сделать то и другое сразу в умножении с накоплением.
Модуль 6 · Части нейрона
ReLU с изломом в нуле, степень двойки для softmax и argmax, который называет ответ.
Модуль 7 · Обучение на ошибке
Потеря, которая оценивает неверную догадку в битах, один шаг, который сдвигает вес против градиента, и скрытый слой, который нужен XOR.
Модуль 8 · BitNet: тернарные сети
Порог, который сжимает сумму обратно до трёх значений, один нейрон, который становится другой функцией при смене весов, и нейрон, который читает входы по 27 тритов за раз.
Модуль 9 · Тернарный MAC как чип
Скалярное произведение 27 тритов как провода без регистра, та же сумма, которую регистр копит на каждом такте, и небольшая целая сеть в конце курса.