Digital & RustWolf
Digital Digital
Привет, RustWolf. Тут я присмотрел один микропроцессор семидесятых годов, думаю, попробую на нём нейросеть небольшую собрать. Представь себе, базовый ИИ на железе, которое десятилетиями не используется. Думал, тебе должно понравиться, учитывая твою любовь к ностальгии и инновациям. Как тебе идея?
RustWolf RustWolf
Нейронная сеть на микропроцессоре семидесятых? Это все равно, что ракетный двигатель в карманных часах вставить. Чип задохнется от одного умножения, не говоря уже о обратном распространении. Если не найдешь запасную микросхему памяти и блок питания, который не спалит все, лучше придерживайся старой доброй логики для ИИ. Могу помочь с настройкой таймингов, но не жди, что запустишь TensorFlow в жестяной коробке.
Digital Digital
Ясно, понял тебя. Эти чипы не для глубокого обучения, это мы и понимаем, но зато это добавляет изюминку. Давай попробуем начать с самой простой сети, с фиксированной точкой, типа нескольких перцептронов, и посмотрим, насколько мы сможем выжать время цикла. Если будет тормозить – урежем до простого логического движка для вычислений. В любом случае, я поищу схемы, и мы посмотрим, потянет ли железо хотя бы один проход. Скажи, какие ресурсы у тебя есть под рукой.
RustWolf RustWolf
Звучит как неплохой прототип. У меня валяется несколько старых руководств в подвале: техдокументация на процессор, несколько примеров на ассемблере и копия книги "Низковольтный фиксированный арифметический процессор" за восемьдесят восьмой. Могу быстро написать простенький алгоритм, который выполнит один проход менее чем за миллисекунду, если сеть будет состоять из пяти весов. Если тактовая частота продолжит глючить, можно отказаться от умножений и использовать таблицу поиска. Давай покопаюсь в архиве, и нарисуем схему времени. Не будем усложнять – достаточно просто показать, что идея работает, пока кремний не придет в негодность.
Digital Digital
Отлично, план хороший. Держи его простым – может, трёхслойный MLP с пятью весами всего. Дай знать, какие значения цикла получатся. Я набросаю простой цикл прямого прохода, и мы подкрутим множитель, если время не хватит. Если всё равно будет слишком жёстко, будем использовать таблицу соответствий. Заставим старый кремний работать почти как современное оборудование.
RustWolf RustWolf
Хорошо, давай посмотрим, что у тебя получилось. С трёхслойной сетью, использующей всего пять скалярных весов, получится примерно шесть операций умножения-сложения (по одной на вес) плюс несколько сложений для смещений. На процессоре типа 8080 с частотой 4 МГц это примерно 30–35 циклов на один проход, то есть около 8–9 микросекунд. Достаточно, чтобы система не тормозила, но если ты используешь функцию активации сложнее, чем просто проверку знака, придётся заменить её на таблицу поиска или аппроксимацию ReLU. Держи рутину лаконичной – загрузи все веса в регистры один раз, а потом проходи по умножениям входных данных на скрытые, суммируй, и затем переходи к проходу скрытых данных на выход. Это поможет снизить количество циклов. Если возникнет узкое место, просто убери функцию активации и используй линейную часть для демонстрации. Давай выровняем регистры.
Digital Digital
Вот примерная схема распределения регистров для ядра в стиле 8080, работающего на частоте 4 МГц. **Регистры** R0–R4 – содержат пять весов (W0–W4) R5 – смещение для скрытого узла (B1) R6 – смещение для выходного узла (B2) R7 – аккумулятор для суммы скрытого узла R8 – аккумулятор для суммы выходного узла R9 – временный результат умножения R10–R11 – входные значения (X0–X1) **Псевдокод** ``` LOAD R0, W0 LOAD R1, W1 LOAD R2, W2 LOAD R3, W3 LOAD R4, W4 LOAD R5, B1 LOAD R6, B2 LOAD R10, X0 LOAD R11, X1 ; скрытый узел CLEAR R7 MUL R0, R10 ; R9 = W0*X0 ADD R7, R9 MUL R1, R11 ; R9 = W1*X1 ADD R7, R9 ADD R7, R5 ; + смещение ; выходной узел CLEAR R8 MUL R2, R10 ; R9 = W2*X0 ADD R8, R9 MUL R3, R11 ; R9 = W3*X1 ADD R8, R9 MUL R4, R7 ; R9 = W4*скрытый ADD R8, R9 ADD R8, R6 ; + смещение ; результат в R8 ``` Примерно 30–35 циклов. Если возникнут проблемы, просто исключи умножение скрытого узла на выходной (W4) и выводи линейную сумму. Сообщи, сколько циклов реально получается при запуске.