вторник, 17 февраля 2026 г.

Как работают нейросети

Недавно один разработчик нейросетей написал код на python содержащий всего 200 строк (+коменнтарии, то есть кода даже меньше) кода нейросети, которая как и все остальные нейросети - сначала обучается, а потом генерирует.  Вот статья откуда я про это узнал. Это хоть и маленькая нейросеть, но все же нейросеть, и она действительно генерирует то на чем обучилась. Разработчик предложил понять ее работу на основе генерации имен: он создал датасет (информация для обучения нейросети) -который является словарем имен состоящий из 32000 строк - каждая строка это отдельное имя. Нейросеть в процессе обучения генерирует случайное имя, и сверяет его со словарем, в процессе сверки обновляя свои параметры, чтобы понимать как лучше генерировать имена в дальнейшем. Пройдя 1000 циклов обучения, она имеет готовый массив чисел (об этом позже), на основании которого может сгенерировать 20 имен. Все это можно прогнать в онлайн на этой странице (просто нажмите генерировать), а выглядит все это примерно вот так:


обращаю внимание что страница сгенерирована нейросетью, я просто попросил ее создать такое для онлайн обучения. Можно обучить эту нейронку на своем словаре (датасете) и получить другие генерации близкие к тому что у вас есть в вашем датасете. например вот список городов РФ: https://boolkin.github.io/html/Vibe/microgpt/cities.txt Скачайте, скормите, посмотрите, поиграйтесь с настройками. Поидее кол-во циклов обучения улучшает нейросеть, но тут это работает не совсем понятно, но об этом ниже. Сейчас о том как это работает.

В общем-то с нейронками никаких чудес не бывает — это обычная математика. По-большому счету все что делают нейросети (привычные нам LLM или генераторы звуков и картинок) — это генерируют токены: слова, буквы, пиксели.
Все это они делают на основе обучения. Они научились тому, что если есть какая-то последовательность букв, то следующей с высокой вероятностью должна идти такая-то. Поэтому выдают текст, который в целом вполне осмысленный, хотя сама нейронка его почти не понимает. Она просто обучена на миллиардах текстов и вычисляет (предсказывает) следующие токены, которые встречались в похожих контекстах во время обучения.
И хотя мы видим при общении с нейросетью процесс генерации — текст создается на наших глазах, — ничего принципиально нового не создается. Пользователю выдают то, что уже было «известно» модели в виде закономерностей, просто сгруппированное в конкретной последовательности на основании математического ожидания. Сейчас мы все пользуемся уже обученными нейросетями — теми, что уже знают много зависимостей. Разработчики заранее провели обучение: скормили нейронке миллиарды текстов, чтобы та построила зависимости (веса) и в процессе генерации ответа обращалась к ним, выдавая осмысленные слова.
Чтобы понять этот процесс глубже, изучим программу MicroGPT. Она обучается на заданном списке имен и на основании выученного сможет сгенерировать новые имена. Тут возникает вопрос: как же так, ведь я говорил, что нового ничего не создается, а тут нейросеть придумывает новые имена? Секрет в том, что нейросеть выучила не сами имена наизусть, а правила их построения. Поэтому она может собрать новое сочетание букв, которого не было в списке, но которое выглядит как имя, потому что следует выученным принципам. В случае с MicroGPT модель маленькая и видит только имена, поэтому она генерирует похожие на имена последовательности, комбинируя изученные паттерны.
В общем, давайте чуть подробнее, как это работает внутри.
1. Токены В начале MicroGPT создает словарь токенов. Токены — это минимальная информация, которой оперирует нейросеть. Она выдает не текст, она выдает токены. В контексте MicroGPT токен — это одна буква. Конкретно как оно работает: есть датасет (словарь имен), состоящий из 32 000 слов-имен на английском языке. Там буквы английского алфавита — 26 штук. И есть еще переносы строк, символ окончания последовательности. Итого 27 токенов. Алгоритм MicroGPT проходится по словарю имен и добавляет в базу токенов все уникальные символы. Вот и получается, что добавляется все 26 букв + конец строки. Если брать русские слова — например, список городов России, то токенизатор добавит в массив 33 буквы + конец строки. (Нюанс: другие современные нейросети используют в качестве токенов целые слова или их части, и их словарь токенов может достигать 100+ тысяч единиц).
2. Параметры Дальше алгоритм наполняет нейросеть параметрами, потому что сами токены ничего не решают без «знаний». Знания хранятся именно в числах. Из статьи автора:
«Параметры — это знания модели. Это большой набор чисел с плавающей точкой, которые изначально случайны и постепенно оптимизируются в процессе обучения... В нашей крошечной модели — 4192 параметра. У GPT-2 — 1,6 миллиарда, у современных LLM — сотни миллиардов... Каждый параметр инициализируется малым случайным числом из гауссового распределения».
Именно эти параметры (веса) мы и видим в итоговом JSON-файле. Давайте разберем их структуру...


1. Входные слои (Embeddings)

wte (Word Token Embeddings): [ 27 items ] - 27 букв 27 токенов - Внутри каждого из 27 элементов лежит вектор из 16 чисел. (16 числе потому что размерность эмбеддинга (n_embd) =16 ). Вектор в математике задается координатами 2 числами на плоскости. Здесь 16 цифр - 16 мерное пространство. 

wpe (Word Position Embeddings): [ 16 items ] Позиционные кодировки. максимальная длина слова в нашем случае. Как работает: Трансформеры не знают порядка слов сами по себе. Этот слой добавляет информацию о том, где стоит буква (первая, вторая, пятая...).Размер: У вас задана максимальная длина фразы 16 символов. Значит, здесь 16 векторов (для позиции 0, позиции 1... до позиции 15). Внутри каждого тоже 16 чисел (n_embd помним)

Далее описание от нейронки: 

2. Выходной слой 

 lm_head (Language Model Head): [ 27 items ]

  • Что это: "Голова" модели, которая делает предсказание.
  • Как работает: Это обратная операция к wte. В конце работы сеть выдает вектор из 16 чисел. Этот слой умножает его на матрицу весов, чтобы получить 27 чисел (логитов).
  • Смысл: Эти 27 чисел превращаются в вероятности. Какое число самое большое — ту букву сеть и предсказывает как следующую. 

3. Слой трансформера (layer0)

У вас всего один слой (layer0), поэтому модель очень маленькая и быстрая, но не очень умная. Внутри слоя есть два основных механизма: Внимание (Attention) и MLP (Feed Forward).

Механизм Внимания (Attention)

Он позволяет сети смотреть на предыдущие буквы, чтобы понять контекст.
  • layer0.attn_wq (Query Weights): [ 16 items ]
    • Матрица весов для создания Запросов (Query). Превращает входной вектор (16 чисел) в вектор запроса (тоже 16 чисел).
  • layer0.attn_wk (Key Weights): [ 16 items ]
    • Матрица весов для создания Ключей (Key). Превращает входной вектор в вектор ключа.
  • layer0.attn_wv (Value Weights): [ 16 items ]
    • Матрица весов для создания Значений (Value). Превращает входной вектор в вектор значения (сама информация).
  • layer0.attn_wo (Output Weights): [ 16 items ]
    • Матрица весов для выхода из блока внимания. После того как механизм внимания собрал информацию от нужных букв, этот слой проецирует результат обратно в размерность 16, чтобы передать дальше.

Механизм MLP (Feed Forward Network)

Это "мышление" сети внутри слоя. Она обрабатывает информацию, полученную от механизма внимания. Обычно в трансформерах этот блок сначала расширяет данные, а потом сжимает.
  • layer0.mlp_fc1 (Fully Connected 1): [ 64 items ]
    • Это первый линейный слой. Он расширяет пространство признаков.
    • Обратите внимание: на входе было 16 чисел, а здесь 64 элемента. Это стандартный прием (обычно расширение в 4 раза: 16×4=64). Сеть ищет более сложные закономерности в этом увеличенном пространстве.
  • layer0.mlp_fc2 (Fully Connected 2): [ 16 items ]
    • Это второй линейный слой. Он сжимает данные обратно.
    • Из 64 чисел он снова делает 16 чисел, чтобы передать их либо в следующий слой трансформера (если бы он был), либо на выход (lm_head).

 то есть это базовая структура именно этой нейросети, которая в первом этапе наполняется случайными числами, а уже потом запускается «Цикл обучения» (Training Loop) - это по сути исправление весов и состоит он из из таких этапов:

  1. Выбор документа. Случайное слово с которым будем сравнивать предсказание.
  2. Прямой проход модели по токенам. Forward: Прогон данных через сеть (получение предсказаний).
  3. Вычисление величины потери. Loss: Расчет ошибки (сравнение предсказаний с правильными ответами из датасета).
  4. Обратное распространение (через градиенты). Backward: Расчет градиентов (понимание, как исправить веса).
  5.  Обновление параметров.Update: Обновление параметров (весов/векторов) 
Снова из статьи на хабре:

 После обучения можно генерировать новые имена. Параметры фиксированы, и мы просто запускаем прямой проход в цикле, подавая сгенерированный токен как следующий вход. 

Каждый экземпляр мы начинаем с токена BOS, который говорит модели: "начни новое имя". Модель выдает 27 логитов, мы преобразуем их в вероятности и случайным образом выбираем один токен в соответствии с этими вероятностями. Этот токен снова подается на вход как следующий, и мы повторяем процесс до тех пор, пока модель не сгенерирует токен BOS (означающий "я закончила") или пока не будет достигнута максимальная длина последовательности.

Параметр температура (temperature) контролирует степень случайности. Перед применением softmax мы делим логиты на значение температуры. Температура, равная 1,0, означает сэмплирование непосредственно из распределения, которое выучила модель. Более низкие значения температуры (например, 0,5 , как в данном случае) делают распределение более "острым" (вероятности сконцентрированы на наиболее вероятных вариантах), что приводит к более консервативному поведению модели, когда она с большей вероятностью выбирает свои лучшие варианты. При температуре, стремящейся к нулю, модель всегда будет выбирать самый вероятный токен (это называется жадным декодированием). Более высокие значения температуры, наоборот, сглаживают распределение, делая вывод более разнообразным, но потенциально менее связным.

 Вот так и происходит генерация ответа - случайный выбор токенов внутри нейросети. Хотя нет, не случайный - поддающийся правилам которым она научилась. Короче как-то так.

Ах да. 


 График loss при 1000 циклах обучения и при 10 000 - видно что потерь меньше, но все еще вроде как довольно мало. при 32000 вот такой список:

step 32000 / 32000 | loss 2.0509

--- инференс ---
Образец 1: aneyl
Образец 2: amalee
Образец 3: amilee
Образец 4: kaylann
Образец 5: samarie
Образец 6: shari
Образец 7: aruha
Образец 8: sharia
Образец 9: kana
Образец 10: aylia
Образец 11: jariyah
Образец 12: kari
Образец 13: ashalia
Образец 14: phamer
Образец 15: hastan
Образец 16: mami
Образец 17: dasten
Образец 18: aharan
Образец 19: mala
Образец 20: arisa 

PS. что я еще хотел добавить. Все оперируют терминами, токены, веса, векторы - голова кругом. Как это понять на примере не очень понятно, и вот тут можно заглянуть внутрь. Эта microgpt обучается, и имеет свою память грубо говоря - то что она знает, какие последовательности выучила она хранит в виде векторов (весов) и выглядеть они могут вот так, как в этом JSON файле. То есть четко видно что один вектор это массив чисел с плавающей точкой - 16 чисел, 16 измерений. Но опять же не все параметры, некоторые имеют размерность 64. Но смысл в том что это веса обученной модели - и если брать их за основу, то не нужно каждый раз проходить обучение. Поэтому современные нейросети работают быстро - запрос ответ - они уже знают на что ориентироваться, есть база параметров.

среда, 11 февраля 2026 г.

Делаю телеграм бота при помощи нейросети

Что-то у меня прям кучно пошло - буквально 5 последних записей так или иначе об этом. Возможно я бы и раньше все это дело распробовал, но на тот момент когда шумел Чат ГПТ от американцев, остальных слышно было не громко, а я принципиально не хотел пользоваться заблокированными в России сервисами. Зато потом мне на работе подсказали про китайский qwen, потом был deepseek, сейчас есть и российские нейронки, то есть уже выбор больше, хотя и сейчас +- больше на слуху американские заблокированные в России нейронки за которые требуют еще и денег. У меня подход принципиальный, и как показывает мой случай - он все же работает, как минимум готовые проекты работают и выполняют поставленную задачу, и вполне качественно на мой взгляд. Правда недавно убедился что платные не зря продвигают - эти штуку реально умнее. Недавно наткнулся на arena ai - там пользователь задает промпт, и это задание выдается двум анонимным нейросетям, которые предлагают свои решения, пользователь должен выбрать лучшее из двух, и тогда ему откроют названия рейронок которые это дело нагенерировали. И я очень удивился тому что одна нейронка смогла с первого запроса сделать именно то что мне нужно - я сделал промпт очень большой и подробный, после того как потранил несколько дней на создание игры в другой нейросети. В этом запросе постарался учесть все неопределенные нюансы с котороми сталкивался чтобы нейронка могла сразу понять и это получилось, я удивлен. Современные бесплатные версии которыми я пользуюсь на такое не способны пока что, приходится делать десятки итераций и исправлений чтобы получить достойный вариант. В целом меня это не сильно напрягает, но все же лучше меньше времени терять на такое, очевидно, поэтому да, если есть возможность юзать claude-opus-4-6, то делайте конечно, а я пока буду пользоваться китайцами - в целом как я и говорил за большее время они могут выдать не хуже.

Итак, как я и говорил, я решил сделать телеграм бота. Захотелось мне иметь быстрый доступ к некоторым специфичным знаниям и я в свое время проворачивал такой фокус на локальной машине - все нужные знания запихнул в SQLite БД и реализовал поиск с уточнениями в ней. Но то на локальной машине и в локальной сети, а смартфон в руке постоянно - нужен интернет сервис - телеграм бот для этого подходит идеально. Но для проверки захотелось сначала перегнать в БД базу ошибок из документации к приводам Митсубиси. Это была отдельная история. 

Документашка в pdf формате, благо с текстом. Распечатал нужные страница через Acrobat в pdf файл - просто тупо уменьшил объем, было 800 а стало 15 страниц. Потом в Акробате нашел опцию экспорта в excel - на каждой странице была таблица с одной ошибкой и описанием ее, всего грубо говоря 2 столбца и 5 строк первый столбец тупо заголовок  для текста во втором слобце важный текст. Экспорт прошел немного криво, пришлось повозиться. Я придумал как в полуавтомате перегнать в сводную таблицу: через поиск находишь слово и заменяешь его на такое же слово, но с заливкой ячейки. разные слова разные цвета. Еще как и говорил была проблема с крифизной экспорта - и часть ячеек была в других столбцах - пришлось скриптом объединять их. Причем прикольно придумал что можно записать макрос по объдинению ячеек, а потом повторить его нужное кол-во раз. В общем ячейки подготовлены, и поставил фильтр по цвету - таким образом в соседней ячейке оказались все нужные данные. Например: фильтр по цвету код ошибки - справа список кодов. выделяю все копирую в другую таблицу, называю столбец код ошибки. Дальше фильтр по описанию, справа все описания - копирую так же подряд, ставлю с колонкой код описание и вставляю туда скопированные описания и т.д. В итоге получилась сводная таблица. Долго мучился как перегнать в SQLite БД пробовал через экспорт csv, но так как там было куча переносо все работало очень плохо. А потом в SQLite Studio просто создал таблицу (визуально все довольно просто), а потом нажал там плюсик - добавить 48 строк (столько получилось в сводной таблице с ошибками) и тупо копировать из таблицы excel в таблицу SQLiteStudio. И все таблица готова, теперь нужно писать бота

А вот с написанием бота пришлось повозиться, но то опять же в рамках эксперимента - я придумал большой запрос и решил отправить его 3 нейронкам: qwen, chat.z.ai, deepseek - все три китайцы, все три бесплатны и без особых ограничений - deepseek расстроил сильно - давал ему несколько шансов но никак не заработало, присылал много раз ошибки, начинал заново с уточнениями и все без толку. Поэтому плюнул, и начал работать с z.ai и qwen - в общем первее чатбот запустился на qwen и поэтому продолжил там. Сделал рабочий продукт, относительно норм, но все же требующий кучу улучшений, поэтому я попросил написать промпт по этому проекту чтобы начать заново и протестировать нейронки снова. опять 3 и опять вернулся к 2. В этот раз опять с первого раза ничего не получалось, хотя я уже присылал даже кусок кода на основе которого нужно делать, но все было без толку - сыпалась куча ошибок и кажды раз я понимал что это пиздец какая долгая песня. Поэтому решил взять только один чат и работать с ним, а начать постепенно. Этот чат был z.ai - в нем уже делал что-то похожее по такой же технологии начинать с малого: взял пример из библиотеки и на его основе попросил сделать прогу. В этот раз сделал абсолютно так же: первый запрос:

Ты профессиональный программист. нужно написать телеграм бота на базе Telegram.bot библиотеки версии 22.9.0 вот пример кода который работает:

using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;

using var cts = new CancellationTokenSource();
var bot = new TelegramBotClient("YOUR_BOT_TOKEN", cancellationToken: cts.Token);
var me = await bot.GetMe();
bot.OnError += OnError;
bot.OnMessage += OnMessage;
bot.OnUpdate += OnUpdate;

Console.WriteLine($"@{me.Username} is running... Press Enter to terminate");
Console.ReadLine();
cts.Cancel(); // stop the bot

// method to handle errors in polling or in your OnMessage/OnUpdate code
async Task OnError(Exception exception, HandleErrorSource source)
{
Console.WriteLine(exception); // just dump the exception to the console
}

// method that handle messages received by the bot:
async Task OnMessage(Message msg, UpdateType type)
{
if (msg.Text == "/start")
{
await bot.SendMessage(msg.Chat, "Welcome! Pick one direction",
replyMarkup: new InlineKeyboardButton[] { "Left", "Right" });
}
}

// method that handle other types of updates received by the bot:
async Task OnUpdate(Update update)
{
if (update is { CallbackQuery: { } query }) // non-null CallbackQuery
{
await bot.AnswerCallbackQuery(query.Id, $"You picked {query.Data}");
await bot.SendMessage(query.Message!.Chat, $"User {query.From} clicked on {query.Data}");
}
}
тебе нужно добавить класс program, main и конфиг чтобы добавить туда токен и другие нужные в будущем конфиги. нужно подключиться к бд SQLite и вернуть пользователю какие таблицы есть там и какие в них столбцы, сколько всего записей. Microsoft.Data.Sqlite --version 10.0.2

специально указываю версии, чтобы работал с новыми, потому что знаю что бывают постоянные проблемы с этим. надо было сразу добавить название приложения и чтобы расписал как его собрать и запустить, но это прислал вторум запросом, он сделал. Была всего одна ошибка при компиляции - и это было здорово - по сути сделал с первого раза. Ошибку исправили, я запустил, дал еще пару замечаний по работе, которые быстро исправили (программа простая, я всегда так делаю сам от простого к сложному и на каждом этапе проверка) - все заработало. И уже следующим запросом я прислал большой промпт на котором тестировал до этого:

 пойдет, но на основе всего этого теперь нужно добавить другую логику, скидываю тз. повторяю - берешь все что сейчас работает и добавляешь новые функции. вот ТЗ:
Ты профессиональный программист. Нужно создать телеграм бота SQLiteChatBot на языке C# (dotnet) с технологией long polling, используя последние библиотекси. Бот должен искать отправляемый боту текст в заданной базе данных. Все настройки бота вынести в конфиг: токен, название БД, таблиц, столбцов, названия столбцов для вывода, то какие столбцы будут отображаться в выводе. Предусмотреть подключение нескольких БД с режимом переключения БД из чата. Все данные из БД нужно помещать в массив, под своими уникальными ID на основе которых будут отправляться текст пользователю в чат, по нажатию инлайн кнопки. 

Логика такая: пользователь вводит слово или несколько слов или их частей в чат и отправляет боту. Бот ищет в массиве (все базы и все таблицы и все столбцы и строки) первое слово, среди найденных ищет второе, потом третье, сужая таким образом количество найденных данных с (1000 до 50 и потом до 5, например). Результат найденных записей отправляется пользователю в виде нумерованного списка, если найденное количество записей не превышает 10 (настройка в конфиге). Под сообщением добавляются inline кнопки с номерами в соответствии с номерами в списке найденного. При нажатии на кнопку в чат отправляется уже полный текстс записи - (все остальные столбцы из таблицы). Изначально список вхождений формируется по названию одной колонки, либо двух (тоже настройка в конфиге), например в нашем случае это база данных содержащая ошибки приводов митсубиси errors.db, таблица Mitsubishi, колонки: Code; Name; Description; Object; Action - соответственно при поиске превышение тока - он должен выдать сначала сообщение-список: несколько кодов из колонки Code и Name которые в других столбцах содержат эти слова, под списком inline кнопки по клику на которой выдается информация по конкретному коду который был запрошен: это все колонки сразу. Между абзацами добавить пустую строку. Можно проставлять название колонки перед ним, либо сделать в конфиге свои названия для вывод в чат.

Делаем консольное приложение, чтобы просто запустить командой dotnet run. Сделать разделение для пользователей чтобы если баз несколько они могли бы искать параллельно не мешая друг другу, если переключаться между базами. Для этого создать базу для хранения настроек пользователя. Выходящее длинное сообщение разбивать на несколько с задержкой отправки (говорят чтобы не забанил телеграм за спам). Нужно сделать максимально просто, весь код не больше 3 файлов cs чтобы проще было копировать из чата. С минимальными зависимостями.

 Ну и дальше работа закипела - после этой строки он сгенерировал код, который собрался без проблем и уже работал поиск и все что нужно, я просто начал делать визуальные улучшения, которые можно было обговрить заранее, например то что таблицы не меняются и должны загружаться единоразово в память:

Все отлично! хочу чтобы кнопки выли в один ряд и по размеру не большие, минимальный размер, символ # оставляем (#1) Пусть в конфиге таблицы будут не Name а TableName, добавил вторую БД и 2 таблицы в ней - поиск выполняется отлично, но из новой базы не присылает документ, хотя присылает детали записи (ID: .....) - подозреваю проблема в ID. что если каждой записи в памяти присваивать свой уникальный id: БД-таблица-id в таблице - в каждой таблице есть своя колонка с Id. таблицы не изменяются никогда, базы не меняются - потому память всегда актуальна 

 и и еще сделать кнопки не в одну линию а в несколько разбивая по 5 кнопок, в одну линию они оказывается не переносятся сами по себе

давай добавим в конфиг пароль , и добавим в базу пользователей колонку access - true - доступ разрешен, false - запрещен, null - предложение ввести пароль 3 раза, ввел 3 раза неверно, то ставим запрет и возвращаем заглушку что нет доступа к базе. базу я буду удалять поэтому нужно просто пересоздать новую с новыми колонками. если доступ разрешен то доступны все функции

  В процессе экспериментов в прошлых ботах у меня осталась висеть клавиатура, я думаю при команде /start надо ее сбрасывать. await bot.SendMessage(chatId, "Removing keyboard", replyMarkup: new ReplyKeyboardRemove()); А смену БД организовать по команде /database, причем кнопки пожно подсвечивать галочкой ту которая уже используется

И все - всего лишь 10 итераций - это отличный результат. Конечно он стал таким потому что до этого я сделал подобных итераций с пару десятков других приложениях - подсказка про уникальные id, про клавиатуру, про пароль - реализация вязата с другого бота - мне понравилось как он сделал, хотя я там тоже довольно подробно расписал принцип. В общем такй бот вполне универсальный, можно добавить любую БД и таблицу и он будет там искать. Но теперь проблема в том что мне интересно запустить все это на сервере линукс, и поэтому надо юзать библиотеку питон. Но я думаю надо делать точно так же - скомпилисть минимальное приложение на питоне - а потом дать тз на полную функциональность. причем можно сразу учеть момент с кнопками (5 столбцов а названия с #) пароль только в конце - усложнения после базового функционала. ну в общем когда сделаю, будет новая статья) 

четверг, 5 февраля 2026 г.

Запускаю нейросети локально

 


По работе появилась идея, сделать чат бота в виде нейросети, который бы знал все наши нюансы работы и подсказывал бы что и как делать в той или иной ситуации - то есть задаешь вопрос простыми словами, а он говорит что можно сделать. для этого нужно скормить ему все журналы с ситуациями и инструкцими за несколько лет, чтобы он знал на что опираться. Все это это можно проделать только запустив нейронку локально. Изначально у меня вообще не было понимания как это делать, но пообщавшись опять же с нейронкой я кое-что понял, обзавелся своими нейронными связями, так сказать. Поэтому хочу поделиться важным опытом. 

Почему важным - потому что нейронка подсказывает не совсем то что может хорошо, она знает только то что в нее положили, на каких данных обучилась, причем от качества обучения тоже зависит - я знаю о чем говорю, я пытался обучить (вообще нет, это RAG, но почти тоже самое) ее своим знаниям и он плохо это понимает. В общем изначально меня повели в дебри, но то было еще и потому что задача стояла изначально совсем другая, сейчас я понимаю что нужно было начинать с вопроса запуска нейронки локально при моих вводных(конкретно ноут с виндой с картой 1650). Вот сейчас в онлайн режиме проверю свою догадку, посоветует ли лучший вариант или нет:

  Я бы хотел запустить нейросеть локально на своем ПК. у меня стоит на нем 2 системы windows 10 и ubuntu, предпочтительнее виндовз. Карта на ноуте 1650. хотелось бы узнать какие неросети LLM можно запустить чтобы работало быстро и хорошо

И она посоветовала то что мне нужно, я удивлен. Это нейросеть Zai - китайская и работает бесплатно. Я чаще пользуюсь qwen - но там у меня уже слишком много контекста в соседних чатах, думаю он опять поведет по ложному следу. В общем я дошел своими силами и теперь при помощи Zai до того что нужно использовать LM Studio - в ней автоматически предлагаются доступные модели которые будут работать хорошо, и в моем случае нейронка правильно ответила что для 4гб памяти лучше выбирать 4b - 4 млрд параметров. Но начну по порядку как я дошел до этого

Изначально так как я хотел скормить журналы с работы нейросети, она предложила использовать Питон и кучу разных библиотек, в питоне почему-то пошла по принципу компилирования библиотек для llamacpp - была куча ошибок, пришлось выкачивать гигабайты всякой хрени просто чтобы запустиьт нейронку. Потом я плюнул и спросил что-то проще, она посоветовала опять не LMstudio а ollama - по сути тоже норм, но там формат скаченной нейронки не gguf - сложнее перенести с машины на машину. В общем по итогу пришел к LM studio. Можно еще кстати довольно просто и главно это даже занимает меньше места и ресурсов запустить llamacpp из скомпилированных exeшников - качать последний релиз (vulkan) - и запускать gguf файл из cmd:

 llama-server -m "C:\путь до нейронки\Qwen3-4B-Instruct-2507-Q4_K_M.gguf" --jinja -c 4096 --host 0.0.0.0 --port 8080 --flash-attn on --kv-offload

 запускается вебсервер и по адресу 127.0.0.1:8080 - откроется чат с нейронкой. Я протестировал на своей системе vulkan, cuda12, cuda13, cpu - лучше всего вулкан, около 10токенов в секунду, отальные 5-7 - это довольно медленно. Возможно я не правильные флаги добавляю, позаимствовал их у одного знакомого. Надо проверить другие. 

Однако, я нестировал и LM studio, и ровно эта же модель выдавала уже 30-39 токенов в секунду (почему второй раз быстрее еще не понял) - это уже очень хороший результат - довольно быстро. На малых моделах 1,7b - скорость на моей карте была до 99т/с - это прям супер шустро, но получалась фигня - вот таблица тестов которые я проводил, у всех один запрос:

 мне нужна веб страница на html, css и js которую можно сохранить одним файлом index.html и открыть его в браузере. Приложение содержит три поля для ввода чисел и должно автоматически вычислять пропорцию: результат = (число3 * число2) / число1 сами поля распологаются в виде таблицы из двух строк и двух столбцов:
число1 - число2
число3 - результат

 если калькулятор считает правильно и выглядит так как я ожидал, то нейронка справилась и оценка хорошо. В скобках количество токенов в секунду. +- - дополнительные очки за скорость, визуал, либо снятие если кнопка посчитать а не авто посчет, хотя такое решается быстро уточняющими запросами, но тем не менее. остановился пока на qwen3 instruct. нужно проверить 


 UPD: в общем выяснилось что нужно запускать llamacpp с другими флагами, и тогда она дает те же 40 токенов, а то и больше. поэтому очень важно обратить на это внимание, но это лишь еще раз доказывает мое предположение, что для новичка без заморочек лучше LMstudio - это и запуск без заморочек, это и предложенные модели для вашей системы, кроме того чат в браузере тоже доступен, нужно в настройках сервера включить CORS - это важно. 

И да флаги для зупасука llama на моей машине выглядят так:

 llama-server -m C:\model\Qwen3-4B-Instruct-2507-Q4_K_M.gguf -ngl 99 -c 4096 --host 0.0.0.0 --port 8080

UPD2: добавил прикол в начале - классика жанра: могу печатать 1000 символов в минуту, но такая хрень получается. Не ожидал что нейронка может выдавать такой отборный бред. Это модель GLM4.7-Distill-LFM2.5-1.2B.i1-Q6_K - пожалуй для супер малых моделей нужно добавить свой тест -  но тот же lfm 2.5 в моем тесте выдал не супер ужасный результат - эта конечно никуда не годится

UPD3: конечно нужно выбирать правильные модели под свои задачи. пока что лучше всего qwen3, думаю покачаю еще пару штук и потестирую, потом потестирую в убунту, скажу результат, предположительно скорость должна быть выше. 

В общем убунту не сильно быстрее, llamacpp - те же +-40 токенов в секунду, причем независимо от от того запущена оболочка или нет. хотя может опять что-то не то делаю. Потому что выяснилось чтобы заработали cuda нужно ставить еще одну утилиту (CUDA Toolkit) (источник) а проверить смогут ли куда заработать или нет, есть такая команда: 

.\llama-server.exe --list-devices

У меня на винде с 13 версией эта команда сработала, выдает информацию что видит, но при запуске модели выдает ошибку и можель не запускается. Попробую через линукс. И еще раз скачаю последние версии.Вот что у меня показывает:

 C:\llama\cuda13>.\llama-server.exe --list-devices

ggml_cuda_init: found 1 CUDA devices:
  Device 0: NVIDIA GeForce GTX 1650, compute capability 7.5, VMM: yes
The following devices will have suboptimal performance due to a lack of tensor cores:
  Device 0: NVIDIA GeForce GTX 1650
Consider compiling with CMAKE_CUDA_ARCHITECTURES=61-virtual;80-virtual and DGGML_CUDA_FORCE_MMQ to force the use of the Pascal code for Turing.
load_backend: loaded CUDA backend from C:\llama\cuda13\ggml-cuda.dll
load_backend: loaded RPC backend from C:\llama\cuda13\ggml-rpc.dll
load_backend: loaded CPU backend from C:\llama\cuda13\ggml-cpu-haswell.dll
Available devices:
  CUDA0: NVIDIA GeForce GTX 1650 (4095 MiB, 3041 MiB free)

кстати им на винде есть команда nvidia-smi, а чтобы запустить в режиме сканирования нужно ввести

nvidia-smi -l 1

Добавляю более сложный тест нейросети, которым я занимался до этого и удивительно но есть нейросети, способные с первого раза сделать все очень красиво (claude-opus-4-6). Естественно локальные модели на такое вряд ли способны:

 нужно разработать игру mastermind для удобного игрового процесса на мобильном устройстве. нужно сделать 6 развноцветных кругов которые будут добавляться в игровую зону просто по клику на круге, заполняя игровую зону последовательно друг за другом, что означает что если щелкнул например красный круг первым, то он встает в угадываемую последовательность на первое место. 6 разноцветных кругов расположить в 2 строки по 3 в ряд. В верхней строке в правой части должна быть кнопка проверить, во второй строке кнопка убрать, чтобы убрать последний добавленный кружок. Внизу страницы кнопка новая игра и помощь с инструкцией к игре. Угадываемые последовательности цветов в игровой зоне нужно заполнять сверху вниз в игровой зоне, это означает что последняя угадываемая последовательность цветов должна находиться всегда внизу, прикреплена к нижнему краю игрового поля. Попытки пронумеровать и расположить так чтобы первая была вверху, последняя внизу. Нужно добавить полосу прокрутки в игровом поле чтобы можно было прокрутить до первой попытки. при победе выдавать сообщение с количеством попыток и просмотром правильной комбинации Нужно использовать только javascript html и css - все в одном файле чтобы запустить локально

если у кружки нет дна и у нее запаян верх, то можно ли пить из такой кружки?

понедельник, 2 февраля 2026 г.

Пробую разбираться в Множестве Мандельброта

Ну я тут снова осваиваю нейросети, и делаю с их помощью полезные штуки. В данном случае прогуливаясь по инету наткнулся статью где упоминалось про множество мандельброта, если помните или видели - это такая симпатичная штучка:



В статье была ссылка на английскую статью и пример кода на си. Я же попросил нейронку переписать код на JS чтобы в онлайн режиме смотреть что из этого выйдет. И что-то вышло. Полного понимания нет, но все-равно было интересно. Я попросил нейронку немного написать вступление и вот что она написала там:

Кто такой Мандельброт и зачем ему фракталы

Бенуа Мандельброт — польско-французский математик, который в 1970-х годах буквально изобрёл слово «фрактал». До него подобные структуры считались «монстрами» математики — слишком сложными, чтобы быть полезными. Но Мандельброт увидел в них порядок: береговые линии, облака, ветвление деревьев — всё это нельзя описать прямыми и окружностями, но можно приблизить фрактальной геометрией. Множество, названное его именем, стало визитной карточкой этой идеи — не потому что «красивое», а потому что показывает: хаос и порядок живут рядом.
Практическая польза? Не в том, чтобы рисовать обои для рабочего стола. Фрактальный анализ сегодня применяется в сжатии изображений, моделировании антенн, изучении турбулентности и даже в финансовой математике — там, где классические модели ломаются о сложность реального мира.
Ну все это лирика, важно то что это тупо математика - есть формула, которая закрашивает пиксели определенным цветом в зависимости от условий, упрощенно если кол-во итераций больше заданной то ярким, если меньше то менее ярким. Вот еще нейронка описала эту формулу для меня:

Множество Мандельброта — кратко

Множество Мандельброта — это набор комплексных чисел c, для которых последовательность, заданная формулой zₙ₊₁ = zₙ² + c при z₀ = 0, не уходит в бесконечность. На практике мы проверяем, не превысит ли модуль |zₙ| значение 2 за фиксированное число шагов.

Как строится изображение

Для каждого пикселя с целочисленными координатами (x, y), где 0 ≤ x < W и 0 ≤ y < H, вычисляется комплексное число:

c = cre + cim·i

где:

  • Вещественная часть:
    cre = 1.5 · (x − W/2) / (0.5 · zoom · W) + moveX
  • Мнимая часть:
    cim = (y − H/2) / (0.5 · zoom · H) + moveY

Затем выполняется итерационный процесс:
z₀ = 0 + 0·i
zₙ₊₁ = zₙ² + c

Итерации продолжаются, пока не выполнится одно из условий:

  • Модуль zₙ превысит 2;
  • Достигнуто максимальное число итераций MAX_ITER.

Модуль комплексного числа z = a + b·i вычисляется как:
|z| = √(a² + b²)
Пример: для z = -2 − i → |z| = √(4 + 1) = √5 ≈ 2.236.

Цвет определяется числом итераций n:
hue = (n % 256) × 360 / 256 → используется в hsl(hue, 100%, 50%).

Цветовой круг HSV: 0°=красный, 60°=жёлтый, 120°=зелёный, 180°=голубой, 240°=синий, 300°=фиолетовый.

Все это я смог проверить на практике, чуть позже добавлю ссылку для баловства в онлайне. Наиболее интересные фигуры множества Жюлиа.

https://boolkin.github.io/html/Vibe/mand+zhu.html - красивые генерации

https://boolkin.github.io/html/Vibe/mand-pix.html - попиксельный расчет

воскресенье, 14 сентября 2025 г.

Смена программы на табло BX-05 через WinCC

Максимально специфичный кейс, но пишу потому что приёмы которые тут используются, могут пригодиться и в будущем. Помогали опять нейросети, но все же по итогу все сам. Плохо то что не зная синтаксиса можно сделать небольшую ошибку и работать не будет, и не ясно потом почему, а нейронка накидывает суперсложные варианты, хотя и помогает с их реализацией. Но обо всем по порядку.

Имеется светодиодное табло, Onbon BX-05 - куда можно вывести любой текст, время, температуру. У табло есть свой вайфай, подключившись к которому в него можно заливать программы (экраны) через специально приложение на Андроид. Несколько лет назад я нарыл сайт и API на JAVA для этого табло, но тогда не разобрался сразу что экраны можно менять просто переключая программы, а не каждый раз записывая экран в EEPROM. Причем там написано что циклы записи в EEPROM ограничены (как и в любом другом оборудовании), а в моем случае переключение экрана предполагалось каждые 5 минут 24/7, то есть в таком темпе EEPROM сдох бы уже через год. Но в этот раз я целенаправленно искал такую опцию чтобы налету менять экран (программу) и нашел. На странице с документацией (JAVA - ONBON Docs (onbonbx.com)) есть такая строка

// 锁定指定节目 screen.lockProgram(programId, lockDuration); // 解除节目锁定 screen.unlockProgram(programId);

У меня уже были наработки в прошлый раз, я научился компилировать Java и запускать тестовый скрипт из командной строки, и добавив в него строку screen.lockProgram(1,0); научился включать в данном случае первую программу (пример onbon_bx05/SimpleCommand.java). Чтобы запустить Java программу нужно запустить команду 

java -cp lib/*;bin SimpleCommand

при этом в каталоге bin должны быть заранее скомпилированные классы. Компилил я их командой

javac -source 8 -target 8 -encoding UTF-8 -cp lib/* -d bin p1.java

мне было необходимо компилировать в 8 версию java для поддержки 32 битной винды. 

Интереснее то как запустить потом все это через WinCC. Как я и говорил ранее, можно было легко нагуглить и даже спросить у нейросети как создать vbs скрипт для переключения экрана, но почему-то он не пошел на WinCC сразу хотя из файла vbs переключение работало. А все дело в том что я забыл объявить переменные в самом начале через ключевое словоDim - виндовый интерпретатор игнорировал это и сам объявлял, а вот Винсисишный не захотел. И я потратил очень много времени чтобы запускать скрипты через C-action и внешние проги. И в итоге это не работало так как было нужно мне, а нужно было чтобы переключение происходило незаметно, без открытия окна консоли. Но в итоге все решилось довольно просто - исправил ошибку с объявлением переменных, и узнал что java может запускаться в скрытом режиме через команду javaw. 

В итоге создал такой глобальный скрипт:

Option Explicit
Function action
    Dim testprohod
    Set testprohod = HMIRuntime.Tags("testprohod")
    Dim WshShell,cmd
    Set WshShell = CreateObject("WScript.Shell")
    cmd = "javaw -cp ""C:\bx\bin;C:\bx\lib\*"" p"&testprohod.Read
    WshShell.Run cmd, 1
End Function

Этот скрипт запускает по триггеру - изменение тега testprohod - число от 1 до 5, например. Соответственно подготавливаются заранее java классы с названием p1, p2, p..., и кладутся в папку C:\bx\bin. Еще с чтением тега были проблемы -я забыл Read - без этого значение не читалось. Добавил Reafd и все заработало: теперь при каждом изменении тега меняется программа на табло, соответствующая тому номеру число которое есть в теге. Стрелочкой на скрине показана кнопка для выбора тега, при этом автоматом добавляется объявление и функция присваивание объекта тегу, значение которого потом считывается всторенной функцией Read


 Вот такой получился кейс - в нем и то как надо писать скрипты на WinCC и как добавилять абсолютные пути для java и vbs и как запускать триггеры. Сейчас переключение экранов бесшовное и незаметно пользователю

Кстати совсем забыл что что нейросеть посоветовала в конце использовать конструкцию 
Set WshShell = Nothing
чтобы освободить объект. 

вторник, 12 августа 2025 г.

Вайб кодинг

 Уже неделю наверное экспериментирую с нейросетями, делаю так чтобы они за меня писали программы, и должен признаться получается это у них даже лучше чем у меня, быстрее. Попробовал переделать те приложения что делал я, и чисто визуально они выглядят сильно лучше, хотя и функционал +- такой же, ну конечно засчет того что добавлять новый функции стало проще, добавлено и что-то новое. Есть и отрицательные стороны - код сложно назвать компактным, но правда опять же, если я не сипользовал в своей игре никаких стилей а от нейросети попросил визуально красивую игру, то конечно она накидает не мало стилей со всякими тенями, скруглениями, цветными кнопками, градиентами и прочим. Но и код один фиг не оптимизирован, но и в современных реалиях гнаться за килобайтами тоже глупо. Короче такие сумбурные размышления на тему того что не все так просто, хотя и все очень даже круто) 

нужно разработать игру mastermind для удобного игрового процесса на мобильном устройстве. нужно сделать 6 развноцветных кругов которые будут добавляться в игровую зону просто по клику на круге, заполняя игровую зону последовательно друг за другом, что означает что если щелкнул например красный круг первым, то он встает в угадываемую последовательность на первое место. 6 разноцветных кругов расположить в 2 строки по 3 в ряд. В верхней строке в правой части должна быть кнопка проверить, во второй строке кнопка убрать, чтобы убрать последний добавленный кружок. Внизу страницы кнопка новая игра и помощь с инструкцией к игре. Угадываемые последовательности цветов в игровой зоне нужно заполнять сверху вниз в игровой зоне, это означает что последняя угадываемая последовательность цветов должна находиться всегда внизу, прикреплена к нижнему краю игрового поля. Попытки пронумеровать и расположить так чтобы первая была вверху, последняя внизу. Нужно добавить полосу прокрутки в игровом поле чтобы можно было прокрутить до первой попытки. при победе выдавать сообщение с количеством попыток и просмотром правильной комбинации Нужно использовать только javascript html и css - все в одном файле чтобы запустить локально

Чтобы понимали о чем речь вот 2 проекта, мой и нейросетевой: визуально видно разницу хорошо, + добавлены еще и уровни сложности, а все сообщения выводятся в модальном окне. работал кстати в нейросети от алибабы - Qwen. 

На этой игре пытался тестить другие нейросети, должен сказать что они может и чуток получше, вероятно запросов придется сделать меньше чтобы получить нужный вариант, хотелось бы максимально приближенный к тому что получилос у меня в первый раз при помощи нейросети (за несколько часов и с десятка 2 уточнений) - расположение кнопок, цветовая схема, функционал как задумано. Допустим Lovable - там есть несколько запросов в день бесплатных и по такому запросу, с 4-мя уточнениями удалось воссоздать играбельную игру с нормальным визуалом. Qwen с таким же запросом в итоге все же не справился за даже 6 уточнений, но можно так пытать до бесконечности, поэтому пофиг. Хотя и не совсем - иногда нейросети тупо не понимают что ты видишь и не могут это починить. Я так пытался исправить некруглые кнопки, и хрен бы их исправил, потому что как и положено в css задан стиль для кнопки круглый, но Хром подставляет свой стиль, поэтому пришлось конкретно просить заменить кнопки на элемент div.

Вот этот запрос на голубом фоне - он не идеальный, нужно дорабатывать. Я думаю что нужно вносить свои названия для элемнетов дизайна чтобы оперировать с ними в будущем, потому что не всегда очевидно как описать этот элемент чтобы поменять его цвет или форму или размер, или сообщить об ошибке в нем. Например сейчас я бы ввел понятие панели управления, который бы попросил сделать единым блоком в конфигурации 3*2 кружка слева, справа 2 кнопки друг под другом. Опять же сразу просить темную тему если хочется именно такую. 

Ну и да ссылка на проекты от нейросети: https://github.com/boolkin/html


пятница, 30 мая 2025 г.

WinCC ошибка SQL

Как-то раз у нас на работе пропало питание и отключился комп, с запущенной на нем WinCC. После запуска компа WinCC отказалось запускать проект, ссылаясь на ошибку: «SQL сервер не может получить доступ к базе данных». После долгих мытарств пришло понимание что похерилась база данных самой WinCC, которая создается при ее установке. Находится такая она по пути C:\Program Files\Microsoft SQL Server\MSSQL10_50.WINCC\MSSQL\DATA и там лежит несколько файлов. Мы просто взяли такие же файлы с другой работающей WinCC такой же версии и заменили их на те что были повреждены, тупо все скопом. На всякий случай решил сохранить эти файлы на будущее, вдруг такая ситуация когда-нибудь повторится у нас или у кого еще.  Версия WinCC в данном случае была 7.2.0.2

Архив с файлами в папке DATA