Блог
[ни один урок не обучает сеть; тесты 15 новых уроков идут в записях нативного t27c, а не в браузере; 35 из 127 мутантов выживают и не разобраны; только программа, без платы] Курс t27 теперь — два курса по 27 уроков, 9 модулей по 3 урока (записи уроков с 13 по 21 ждут t27#7400): «С нуля до чипа» о программировании FPGA и «ИИ-числа на t27», который начинается с 6 переехавших уроков и добавляет ещё 21, до маленькой тернарной сети. Каждый из последних 15 уроков подкладывает в спеку ошибку в одну строку и показывает единственный названный тест, который падает. По 14 их функциям tri mutate spec сделала 127 мутантов, и тесты убили 92.

Курс t27 разросся до 33 уроков в 11 модулях: 27 о программировании FPGA, потом 6 о форматах чисел для ИИ. Это две темы в одном курсе, и ссылкой на него нельзя было поделиться ни одной темой отдельно. Теперь это два курса по 27 уроков, и в каждом курсе 9 модулей по 3 урока. Курс 1, «С нуля до чипа», оставляет себе уроки FPGA и свой адрес. Курс 2, «ИИ-числа на t27», начинается с 6 переехавших уроков и добавляет ещё 21, до маленькой тернарной сети. Каждый урок открывает свой виджет и одну спеку t27, а каждый из последних 15 уроков подкладывает в спеку одну ошибку и показывает тот единственный тест, который её ловит.
27 — это 3 x 3 x 3, форма слова TRI-27, и каждый курс — это 9 модулей по 3 урока, всего 27 уроков. Когда теме нужно больше 27 уроков, она становится вторым курсом, связанным с предыдущим: последний урок курса 1 заканчивается ссылкой на урок 1 курса 2, а урок 1 курса 2 ссылается обратно. У каждого курса свой адрес в приложении, своя страница под t27.ai/learn/, своя карточка для превью и своя строка в карте сайта, поэтому каждым можно поделиться отдельно.
Ни одна ссылка, работавшая до разделения, не сломалась. Страница урока остаётся по адресу t27.ai/learn/<урок>/, в каком бы курсе урок ни был. В приложении старый адрес переехавшего урока, #/course/<урок>, теперь открывает его по адресу #/ai-numbers/<урок>. Прогресс — один список в вашем браузере для обоих курсов, поэтому урок, отмеченный пройденным до разделения, остаётся пройденным и после.
| Уроки | Часть | Чему учит |
|---|---|---|
| 1-3 | Лаборатория: наши исследования | Свой формат чисел, честная таблица результатов и таблицы модели, перемноженные на плате. |
| 4-6 | ИИ-числа: блок MX | Как ИИ-чипы хранят веса в нескольких битах: один общий масштаб на блок, сам байт масштаба и что один выброс делает с соседями. |
| 7-9 | Тернарные веса | Веса, которые бывают только минус масштаб, ноль или плюс масштаб, пять правил, которые должен пройти тернарный алфавит, и прогон тестов, который ничего не проверил. |
| 10-12 | Тернарный формат Ternary Network Float | Правило, которое компилятор проверяет до запуска любого теста, и 17-битное число с плавающей точкой, порядок которого — четыре сбалансированных трита. |
| 13-15 | Арифметика чисел со знаком | Умножить два числа со знаком, сложить их, когда знаки разные, и сделать то и другое сразу в умножении с накоплением. |
| 16-18 | Части нейрона | ReLU с изломом в нуле, степень двойки для softmax и argmax, который называет ответ. |
| 19-21 | Обучение на ошибке | Потеря, которая оценивает неверную догадку в битах, один шаг, который сдвигает вес против градиента, и скрытый слой, который нужен XOR. |
| 22-24 | BitNet: тернарные сети | Порог, который сжимает сумму обратно до трёх значений, один нейрон, который становится другой функцией при смене весов, и нейрон, который читает входы по 27 тритов за раз. |
| 25-27 | Тернарный MAC как чип | Скалярное произведение 27 тритов как провода без регистра, та же сумма, которую регистр копит на каждом такте, и небольшая целая сеть в конце курса. |
Курс 1 сохраняет свои 27 уроков в 9 модулях по 3: чип, числа в железе, ваша программа на t27, внутри t27c, от спеки к железу, читаем синтез, размещение, трассировка и тайминг, битстрим и на плате.
Уроки с 13 по 27 разбирают каждый одну спеку из тернарного каталога t27. Виджет каждого — запись терминала на нашей лабораторной машине, где нативный компилятор t27c и Zig гоняют тесты, которые браузер пока не умеет запускать. Запись показывает важные строки и гоняет тесты спеки. Потом tri mutate plant меняет одну строку, снова гоняет тесты и проходит, только если упал ровно названный тест, а git diff показывает, что файл вернулся к прежнему виду. Во всех 15 падает ровно один названный тест.
Записи уроков с 13 по 21 ещё не готовы. Их девяти спекам (gft_smul, gft_sadd, gft_signed_mac, gft_relu, gft_exp2, gft_argmax4, gft_nll, gft_sgd_step и gft_xornet) нужны команды tri test и tri mutate plant из t27#7400, который ещё не смержен. До тех пор каждый из этих уроков открывает страницу-заглушку, где сказано, что запись ещё не готова, и нет никакого запуска; текст урока говорит то же. Уроки с 22 по 27 открывают свои записи уже сейчас.
| Урок | Спека | Тесты | Подложенная ошибка | Единственный упавший тест |
|---|---|---|---|---|
| 13 Знак — это один бит | gft_smul.t27 | 3 | знак произведения всегда 0 | m2 |
| 14 Разные знаки — вычитание | gft_sadd.t27 | 3 | складывает величины, когда знаки разные | a2 |
| 15 Умножить, потом сложить | gft_signed_mac.t27 | 4 | знак ставится через OR, а не XOR | pp |
| 16 Излом в нуле | gft_relu.t27 | 4 | отрицательные входы проходят насквозь | negz |
| 17 Два в степени x | gft_exp2.t27 | 4 | теряет минус у k для отрицательного x | em1 |
| 18 Выбрать наибольшее | gft_argmax4.t27 | 4 | > становится >= для двух положительных оценок | tie_low |
| 19 Потеря в битах | gft_nll.t27 | 3 | neg превращает 0 в ноль с поставленным битом знака | perfect |
| 20 Один шаг вниз по склону | gft_sgd_step.t27 | 3 | умножает g на само себя, а не на eta | ascend |
| 21 XOR нужен излом | gft_xornet.t27 | 4 | нет relu у одного скрытого нейрона | x00 |
| 22 Обратно в три значения | activation_quantizer.t27 | 7 | > становится >= на пороге | quantize_boundary_hi |
| 23 Тот же нейрон, другие веса | bitnet_majority.t27 | 12 | один вес из P становится Z | maj_p_n_n |
| 24 Нейрон по кускам | bitnet_neuron_nchunk.t27 | 11 | цикл читает один кусок, а не все | neuron_zero_chunks |
| 25 Скалярное произведение из проводов | comb_ternary_dot.t27 | 4 | N на P даёт +1 | dot_all_n_x_all_p |
| 26 Складывать на каждом такте | stream_ternary_mac.t27 | 4 | P в a читается как N | dot_all_p_x_all_p |
| 27 Целая сеть | bitnet_mlp.t27 | 4 | третий скрытый трит попадает не в тот бит | pack3_zzz |
Одна подложенная ошибка показывает, что тест умеет падать. О тестах, которые никто не написал, она говорит мало. Поэтому каждая запись заканчивается командой tri mutate spec: она делает в функции урока все однострочные изменения, которые знает, и считает, сколько из них заметили тесты.
По 14 функциям из 15 tri mutate spec сделала 127 мутантов. 92 убиты, каждый — упавшим тестом, 35 выжили; ни один не завис и ни один не перестал собираться. Восемь функций убили всех мутантов. Шесть — нет:
| Спека | Функция | Мутанты | Убиты | Выжили |
|---|---|---|---|---|
| gft_exp2.t27 | on_comb | 34 | 17 | 17 |
| gft_sadd.t27 | sadd | 18 | 10 | 8 |
| gft_smul.t27 | smul | 16 | 12 | 4 |
| gft_argmax4.t27 | gt | 9 | 6 | 3 |
| comb_ternary_dot.t27 | tmul | 7 | 5 | 2 |
| gft_relu.t27 | on_comb | 5 | 4 | 1 |
Выживший — это изменение в одну строку, которого не замечает ни один тест. Либо не хватает теста, либо изменение не меняет того, что возвращает функция. В таких спеках встречаются оба случая. В gft_relu.t27 строку 11, if (x == 0) { return 0; }, можно удалить, не изменив ни одного результата, потому что строка 13 возвращает x, а x уже 0. Какой из 35 выживших какого рода, пока не разобрано; начинать стоит с gft_exp2.t27, где при 4 тестах 17 выживших. Для gft_xornet.t27 подсчёт не напечатал итога вовсе, поэтому она не вошла в суммы.
Пока делались записи, нашлись две проблемы в инструментах. tri test печатал зелёную строку, не запустив ни одного теста, так что запись с ним ничего не доказывала. Пул-реквест t27#7400 заставляет его гонять тесты и падать, если хоть один упал или не прошёл ни один, и добавляет tri mutate plant: она подкладывает ошибку, требует, чтобы упали ровно названные тесты, и сверяет хеш файла до и после. t27c test-report по-прежнему выходит с кодом 0, когда тест падает, поэтому каждый вердикт в этих записях читается из его текста (t27#7370).
Перед тем как писать, мы прочитали страницы 16 других источников, которые учат тернарным сетям, квантованным сетям на FPGA или сети с нуля либо строят их; читали 7 октября 2026 года. В таблице оставлено 11 из них.
| Источник | Вид | Тернарные веса | Где работает | Какие тесты за ним |
|---|---|---|---|---|
| The Era of 1-bit LLMs, S. Ma et al. (2024) | статья | да, определение BitNet b1.58 | GPU | перплексия и точность против LLaMA |
| bitnet.cpp, Microsoft | библиотека вывода | да | CPU, а с 2025 года и GPU | набор тестов не назван |
| Fine-tuning LLMs to 1.58bit, Hugging Face (2024) | статья в блоге | да, квантователь шаг за шагом | GPU | бенчмарки и кривые потерь |
| A Visual Guide to Quantization, M. Grootendorst (2024) | иллюстрированная статья | да, с разобранными числами | статичные рисунки | нет, кода там нет |
| Ternary Weight Encoder, binarycon.com | интерактивная страница | упаковывает веса, которые уже тернарные | ваш браузер | не указаны |
| FINN, AMD Research | компилятор и блокноты | бинарные и квантованные; тернарные на прочитанных страницах не названы | платы FPGA; симуляция на Python, C++ и RTL | да: каждый этап против эталона |
| TernaryCore (2026) | библиотека на Verilog | да: MAC, скалярное произведение, умножение матриц | симуляция; платы Arty A7-100T и Tang Nano 9k | число пройденных тестов стенда и RTL против Python; тесты не названы |
| TeLLMe, Y. Qiao et al. (arXiv:2504.16266) | статья | да, веса 1,58 бита | FPGA Kria KV260 | проверка правильности не описана |
| micrograd и Neural Networks: Zero to Hero, A. Karpathy | библиотека и видеокурс | нет | Python | градиенты сверяются с PyTorch |
| MiniTorch, S. Rush | учебная библиотека | нет | Python и модуль на CUDA | модульные тесты и тесты свойств, которые должен пройти ученик |
| nand2tetris, Project 2 | курс и книга | нет | симулятор железа на компьютере | тестовый скрипт и файл сравнения на каждую микросхему |
| Этот курс, уроки с 13 по 27 | курс | да: скалярное произведение 27 тритов, MAC и маленькая сеть | спеки в вашем браузере; тесты в записях нативного t27c | да: 74 теста, одна подложенная ошибка на урок, 127 мутантов |
Каждый из них делает то, чего этот курс не делает. Статья о BitNet, bitnet.cpp и статья Hugging Face работают в масштабе настоящих моделей, от 700M до 70B параметров, с измеренными ускорениями; ни один урок здесь не касается обученной модели. FINN превращает обученные сети в ускорители на FPGA и проверяет каждый этап в симуляции, а TeLLMe запускает целую тернарную языковую модель на FPGA для периферийных устройств. Ближе всех TernaryCore: открытый Verilog, который идёт от тернарного MAC к скалярному произведению и к умножению матриц, с тестами, и работает на настоящих платах. В micrograd, MiniTorch и nand2tetris ученик сам строит каждую часть против тестов.
Чего мы не нашли ни на одной из этих страниц, так это формы этих уроков: одна подложенная ошибка в одну строку на урок, которая роняет ровно один названный тест, после чего файл возвращается к прежнему виду. Ближе всего nand2tetris и MiniTorch: там собственная ошибка ученика роняет их тесты, но ошибку не подкладывают и не показывают. Это узкое утверждение о прочитанных страницах, а не обо всех курсах на свете. И тесты этих 15 уроков пока не идут в вашем браузере; они идут в записях.
Поработаем вместе
Я аудирую RTL и строю независимые побитово точные модели, затем провожу результат через синтез и, когда это полезно, проверяю на плате Artix-7. Первый модуль проверки — бесплатно.