habrahabr

Отчёт о запуске DeepSeek-R1 на Xeon 6132 c 768 ГБ памяти

  • суббота, 8 февраля 2025 г. в 00:00:12
https://habr.com/ru/articles/879846/

Спойлер для экономии времени читающих — я просто скачаю DeepSeek и запущу его через llama.cpp, на какую-либо научную новизну этот пост совершенно не претендует. Зачем это на хабре, если там всего одна команда? Просто в комментариях к посту «Мануал по запуску полной модели DeepSeek-R1 локально» я спросил «имеет ли смысл попробовать на том железе, что у меня есть», и меня попросили это сделать, ну и некоторое количество «плюсиков» говорит о том, что кому-нибудь это будет интересно, ну а раз паззл сложился — о том и пост, просто развёрнутое продолжение, алаверды, так сказать, к предыдущему оратору. И да, я абсолютный дилетант в LLM, это первая «пристрелка», так что «туториалом» оформлять пост не буду, там могут быть неточности. Если кому интересны подробности — можно продолжить чтение.

Второй спойлер — да, это работает. Но очень медленно. Но работает.

Железо

Упражняться я буду вот на такой конфигурации:
HP z8 G4 рабочая станция примерно пятилетней давности в практически стоковом варианте.
Два процессора Xeon Gold 6132, 768 GB памяти DDR4, терабайтный NVMe SSD Samsung.
.
CPU-z выдаёт мне 10000+ попугаев:

Память набрана плашками по 64 ГБ, их там двенадцать штук:

Бенчмарк памяти и кэша я уже в комментах показывал, вынесу сюда тоже:

Видеокарт там две — NVidia Quadro K4200 да AMD Radeon Pro WX 9100, но использоваться как GPU они не будут (смысла в общем нет).

Диск:

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

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

Скачиваем DeepSeek

Я бы мог просто написать «скачайте DeepSeek R1 Q8_0», но тут есть небольшой нюанс. Дело в том, что на работе у меня все искусственные интеллекты старательно заблокированы злым админом, охраняющим интеллектуальную собственность. У меня нет онлайн доступа ни к ChatGPT, ни к Perplexity, ни к DeepSeek, равно как все дропбоксы, гуглодрайвы, онлайн заметочники — блокировано решительно всё. Причём не только на уровне прокси, но также фактически осуществляется MITM подменой сертификатов, поэтому скачать с Hugging Face/Unsloth AI я ничего не могу, получая отлуп 500. Издержки работы в большой компании. Обходить защиты — чревато, ибо Большой Брат неустанно бдит, так что качать я буду дома. А дома у меня всего-навсего 100 Мбит (хоть и оптоволокно), так что процесс не быстрый (планируйте как минимум сутки).

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

Вот как-то так это делается через sparse-checkout:

git clone -n --depth=1 --filter=tree:0 https://huggingface.co/unsloth/DeepSeek-R1-GGUF
cd DeepSeek-R1-GGUF
git sparse-checkout set --no-cone /DeepSeek-R1-Q8_0
git checkout

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

Лирическое отступление — если вы хотите временно отказаться от обновлений и возможных сопутствующих перезагрузок, то просто включите Metered connection (по-немецки Getaktete Verbindung) для сетевого адаптера, это самый наипростейший способ достичь бесконечного аптайма на компе, постоянно воткнутом в интернет.

Я это сделал, и выполнив команды второй раз, обнаружил, что «докачки» там нет и в помине, git начал качать с нуля (это видно в lfs кэше, там сначала файлы складываются во временную папку). Тут я вспомнил, что у меня валяется древний QNAP NAS, там есть качалка, но тут меня ждала другая засада — раз в сутки провайдер сбрасывает соединение, при этом NAS на это нервно реагировал, вываливал ошибку и начинал скачку снова. С торрентами он худо-бедно справлялся, а вот с https — нет. Я уже хотел было отказаться от затеи, но вы же понимаете — если я во всеуслышание напишу вот прямо здесь, что не смог скачать семьсот гиг, то надо мной будет ржать весь хабр, и я буду подвергнут публичному остракизму, так что пришлось расчехлить менеджер закачек, которым я не пользовался уже много лет.

Я это всё к тому, что если захотите скачать на слабом канале — заранее проверьте, что вы можете уверенно докачивать при обрыве соединения.

Ладно, хватит длинного вступления, короче — вот репозиторий DeepSeek-R1-GGUF, вот модель DeepSeek-R1-Q8_0, а под спойлером — прямые ссылки на список файлов, которые можно скормить любому менеджеру, я пользовался JDownloader 2.

DeepSeek-R1.Q8_0-000??-of-00015.gguf
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00001-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00002-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00003-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00004-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00005-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00006-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00007-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00008-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00009-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00010-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00011-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00012-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00013-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00014-of-00015.gguf?download=true
https://huggingface.co/unsloth/DeepSeek-R1-GGUF/resolve/main/DeepSeek-R1-Q8_0/DeepSeek-R1.Q8_0-00015-of-00015.gguf?download=true

Плюс использования менеджера ещё и в том, что днём я могу уменьшить скорость, чтобы не доставлять неудобств домашним, а ночью «открывать кран» на всю катушку.

Пока идёт скачивание, чтоб было не скучно — могу предложить загадку, как раз про это.

Во второй половине девяностых, мы, новоиспечённые выпускники физтеха, порой собирались вместе, распивали крепкие спиртные напитки и иногда смотрели фильмы на видеокассетах. В числе наиболее популярных был фильм, который мы, подрабатывающие программистами, ласково называли не иначе как «это наше кино, про эти, про ГИГАБАЙТЫ!» Угадайте, о каком фильме, выпущенном в середине девяностых, шла речь? Потом спросим у DeepSeek.

Как бы то ни было, через пару дней и ночей на терабайтном диске у меня лежали пятнадцать заветных GGUF файлов. Бережно неся их на работу, испытал странное ощущение — это что же, у меня в руках почти вся взвешенная квинтэссенция знаний человечества?! Мда...

Запускаем.

Вообще говоря существует несколько способов «запустить» DeepSeek локально — LM Studio, Ollama, llama.cpp и OpenVINO, часть из них я почерпнул из комментов, за что спасибо. Я попробовал навскидку все, но без фанатизма.

Самый наипростейший, вероятно — LM Studio. Актуальная версия на момент написания поста — 0.3.9. Я попробовал поставить дома, всё без проблем, как демка скачивается простенькая DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf на четыре с половиной гига, что позволяет запустить это дело даже на моём древнем ноуте (32 ГБ, проц. i7-4940MX). Я попробовал — даже работает, но очень медленно. Файлы моделей по умолчанию лежат в %USERPROFILE%\.lmstudio\models\lmstudio-community, там они в поддиректориях типа \DeepSeek-R1-Distill-Qwen-7B-GGUF.

Я закинул на диск инсталлятор, но вот на hp z8 прилетела и уселась птичка обломинго — «тестовая» Qwen 7B хоть и загружалась, но вываливалась в «неизвестную ошибку» после первого же промпта, а с таким трудом выкачанная Q8_0 отказалась загружаться вовсе, сославшись на нехватку ресурсов (выгрузку в GPU я отключил, не помогло). Дальше я мучить её пока не стал и отложил красивую игрушку в сторону.

Ollama в основном рассчитана на то, что скачивать модель вы будете через неё же (что невозможно в моём случае, а перекачивать дома всё ещё раз — тут уж извините),

Welcome to Ollama!
Run your first model:

        ollama run llama3.2

PS C:\Windows\System32> ollama run deepseek-r1:1.5b
pulling manifest
pulling aabd4debf0c8... 100% ▕████████████████████████████████▏ 1.1 GB
pulling 369ca498f347... 100% ▕████████████████████████████████▏  387 B
pulling 6e4c38e1172f... 100% ▕████████████████████████████████▏ 1.1 KB
verifying sha256 digest, writing manifest, success
>>> hi!
<think>

</think>

Hello! How can I assist you today? 😊

так то оно работает, а вот как «подоткнуть» ей уже заранее скачанные файлы GGUF — тут чуть сложнее. То есть место-то где они должны лежать, я знаю: %USERPROFILE%\.ollama\models, но там модель надо кидать в папку \blobs, при этом переименовать файл в sha256-<хеш>, кроме того, надо добавить конфигурационный файл в \manifests\registry\.ollama.ai\library\deepseek-r1, в общем тут надо «приготовить» модель через
"ollama create DeepSeekR1 -f DeepSeek-R1.gguf", но перед этим вам придётся смержить все пятнадцать файлов вместе через "gguf-split --merge DeepSeek-R1.Q8_0-00001-of-00015.gguf DeepSeek-R1.gguf", и в общем ну его в топку такие упражнения.

А вот с llama.cpp всё получилось, и очень просто. Я было приготовился долго и нудно собирать это дело из исходников, но делать это не надо, там есть готовые сборки под Windows. Поскольку у меня железка на Xeon с поддержкой AVX512, вот эту версию я и скачал для начала.

Короче, тупо забрасываем файлы модели и содержимое архива с утилитами в одну папку (да прямо в корень диска F:\ в моём случае)

И запускаем

llama-cli.exe -m DeepSeek-R1.Q8_0-00001-of-00015.gguf -p "Hi!" -n 4096

Всё.

Все параметры командной строки (на английском, под спойлером). их там овердофига:

llama-cli.exe -h
example usage:

  text generation:     llama-cli.exe -m your_model.gguf -p "Hi!" -n 128
  chat (conversation): llama-cli.exe -m your_model.gguf -p "Hello!" -cnv

----- common params -----

-h,    --help, --usage                  print usage and exit
--version                               show version and build info
--verbose-prompt                        print a verbose prompt before generation (default: false)
-t,    --threads N                      number of threads to use during generation (default: -1)
                                        (env: LLAMA_ARG_THREADS)
-tb,   --threads-batch N                number of threads to use during batch and prompt processing (default:
                                        same as --threads)
-C,    --cpu-mask M                     CPU affinity mask: arbitrarily long hex. Complements cpu-range
                                        (default: "")
-Cr,   --cpu-range lo-hi                range of CPUs for affinity. Complements --cpu-mask
--cpu-strict <0|1>                      use strict CPU placement (default: 0)
--prio N                                set process/thread priority : 0-normal, 1-medium, 2-high, 3-realtime
                                        (default: 0)
--poll <0...100>                        use polling level to wait for work (0 - no polling, default: 50)
-Cb,   --cpu-mask-batch M               CPU affinity mask: arbitrarily long hex. Complements cpu-range-batch
                                        (default: same as --cpu-mask)
-Crb,  --cpu-range-batch lo-hi          ranges of CPUs for affinity. Complements --cpu-mask-batch
--cpu-strict-batch <0|1>                use strict CPU placement (default: same as --cpu-strict)
--prio-batch N                          set process/thread priority : 0-normal, 1-medium, 2-high, 3-realtime
                                        (default: 0)
--poll-batch <0|1>                      use polling to wait for work (default: same as --poll)
-c,    --ctx-size N                     size of the prompt context (default: 4096, 0 = loaded from model)
                                        (env: LLAMA_ARG_CTX_SIZE)
-n,    --predict, --n-predict N         number of tokens to predict (default: -1, -1 = infinity, -2 = until
                                        context filled)
                                        (env: LLAMA_ARG_N_PREDICT)
-b,    --batch-size N                   logical maximum batch size (default: 2048)
                                        (env: LLAMA_ARG_BATCH)
-ub,   --ubatch-size N                  physical maximum batch size (default: 512)
                                        (env: LLAMA_ARG_UBATCH)
--keep N                                number of tokens to keep from the initial prompt (default: 0, -1 =
                                        all)
-fa,   --flash-attn                     enable Flash Attention (default: disabled)
                                        (env: LLAMA_ARG_FLASH_ATTN)
-p,    --prompt PROMPT                  prompt to start generation with
                                        if -cnv is set, this will be used as system prompt
--no-perf                               disable internal libllama performance timings (default: false)
                                        (env: LLAMA_ARG_NO_PERF)
-f,    --file FNAME                     a file containing the prompt (default: none)
-bf,   --binary-file FNAME              binary file containing the prompt (default: none)
-e,    --escape                         process escapes sequences (\n, \r, \t, \', \", \\) (default: true)
--no-escape                             do not process escape sequences
--rope-scaling {none,linear,yarn}       RoPE frequency scaling method, defaults to linear unless specified by
                                        the model
                                        (env: LLAMA_ARG_ROPE_SCALING_TYPE)
--rope-scale N                          RoPE context scaling factor, expands context by a factor of N
                                        (env: LLAMA_ARG_ROPE_SCALE)
--rope-freq-base N                      RoPE base frequency, used by NTK-aware scaling (default: loaded from
                                        model)
                                        (env: LLAMA_ARG_ROPE_FREQ_BASE)
--rope-freq-scale N                     RoPE frequency scaling factor, expands context by a factor of 1/N
                                        (env: LLAMA_ARG_ROPE_FREQ_SCALE)
--yarn-orig-ctx N                       YaRN: original context size of model (default: 0 = model training
                                        context size)
                                        (env: LLAMA_ARG_YARN_ORIG_CTX)
--yarn-ext-factor N                     YaRN: extrapolation mix factor (default: -1.0, 0.0 = full
                                        interpolation)
                                        (env: LLAMA_ARG_YARN_EXT_FACTOR)
--yarn-attn-factor N                    YaRN: scale sqrt(t) or attention magnitude (default: 1.0)
                                        (env: LLAMA_ARG_YARN_ATTN_FACTOR)
--yarn-beta-slow N                      YaRN: high correction dim or alpha (default: 1.0)
                                        (env: LLAMA_ARG_YARN_BETA_SLOW)
--yarn-beta-fast N                      YaRN: low correction dim or beta (default: 32.0)
                                        (env: LLAMA_ARG_YARN_BETA_FAST)
-dkvc, --dump-kv-cache                  verbose print of the KV cache
-nkvo, --no-kv-offload                  disable KV offload
                                        (env: LLAMA_ARG_NO_KV_OFFLOAD)
-ctk,  --cache-type-k TYPE              KV cache data type for K
                                        allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
                                        (default: f16)
                                        (env: LLAMA_ARG_CACHE_TYPE_K)
-ctv,  --cache-type-v TYPE              KV cache data type for V
                                        allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1
                                        (default: f16)
                                        (env: LLAMA_ARG_CACHE_TYPE_V)
-dt,   --defrag-thold N                 KV cache defragmentation threshold (default: 0.1, < 0 - disabled)
                                        (env: LLAMA_ARG_DEFRAG_THOLD)
-np,   --parallel N                     number of parallel sequences to decode (default: 1)
                                        (env: LLAMA_ARG_N_PARALLEL)
--rpc SERVERS                           comma separated list of RPC servers
                                        (env: LLAMA_ARG_RPC)
--mlock                                 force system to keep model in RAM rather than swapping or compressing
                                        (env: LLAMA_ARG_MLOCK)
--no-mmap                               do not memory-map model (slower load but may reduce pageouts if not
                                        using mlock)
                                        (env: LLAMA_ARG_NO_MMAP)
--numa TYPE                             attempt optimizations that help on some NUMA systems
                                        - distribute: spread execution evenly over all nodes
                                        - isolate: only spawn threads on CPUs on the node that execution
                                        started on
                                        - numactl: use the CPU map provided by numactl
                                        if run without this previously, it is recommended to drop the system
                                        page cache before using this
                                        see https://github.com/ggerganov/llama.cpp/issues/1437
                                        (env: LLAMA_ARG_NUMA)
-dev,  --device <dev1,dev2,..>          comma-separated list of devices to use for offloading (none = don't
                                        offload)
                                        use --list-devices to see a list of available devices
                                        (env: LLAMA_ARG_DEVICE)
--list-devices                          print list of available devices and exit
-ngl,  --gpu-layers, --n-gpu-layers N   number of layers to store in VRAM
                                        (env: LLAMA_ARG_N_GPU_LAYERS)
-sm,   --split-mode {none,layer,row}    how to split the model across multiple GPUs, one of:
                                        - none: use one GPU only
                                        - layer (default): split layers and KV across GPUs
                                        - row: split rows across GPUs
                                        (env: LLAMA_ARG_SPLIT_MODE)
-ts,   --tensor-split N0,N1,N2,...      fraction of the model to offload to each GPU, comma-separated list of
                                        proportions, e.g. 3,1
                                        (env: LLAMA_ARG_TENSOR_SPLIT)
-mg,   --main-gpu INDEX                 the GPU to use for the model (with split-mode = none), or for
                                        intermediate results and KV (with split-mode = row) (default: 0)
                                        (env: LLAMA_ARG_MAIN_GPU)
--check-tensors                         check model tensor data for invalid values (default: false)
--override-kv KEY=TYPE:VALUE            advanced option to override model metadata by key. may be specified
                                        multiple times.
                                        types: int, float, bool, str. example: --override-kv
                                        tokenizer.ggml.add_bos_token=bool:false
--lora FNAME                            path to LoRA adapter (can be repeated to use multiple adapters)
--lora-scaled FNAME SCALE               path to LoRA adapter with user defined scaling (can be repeated to use
                                        multiple adapters)
--control-vector FNAME                  add a control vector
                                        note: this argument can be repeated to add multiple control vectors
--control-vector-scaled FNAME SCALE     add a control vector with user defined scaling SCALE
                                        note: this argument can be repeated to add multiple scaled control
                                        vectors
--control-vector-layer-range START END
                                        layer range to apply the control vector(s) to, start and end inclusive
-m,    --model FNAME                    model path (default: `models/$filename` with filename from `--hf-file`
                                        or `--model-url` if set, otherwise models/7B/ggml-model-f16.gguf)
                                        (env: LLAMA_ARG_MODEL)
-mu,   --model-url MODEL_URL            model download url (default: unused)
                                        (env: LLAMA_ARG_MODEL_URL)
-hf,   -hfr, --hf-repo <user>/<model>[:quant]
                                        Hugging Face model repository; quant is optional, case-insensitive,
                                        default to Q4_K_M, or falls back to the first file in the repo if
                                        Q4_K_M doesn't exist.
                                        example: unsloth/phi-4-GGUF:q4_k_m
                                        (default: unused)
                                        (env: LLAMA_ARG_HF_REPO)
-hfd,  -hfrd, --hf-repo-draft <user>/<model>[:quant]
                                        Same as --hf-repo, but for the draft model (default: unused)
                                        (env: LLAMA_ARG_HFD_REPO)
-hff,  --hf-file FILE                   Hugging Face model file. If specified, it will override the quant in
                                        --hf-repo (default: unused)
                                        (env: LLAMA_ARG_HF_FILE)
-hfv,  -hfrv, --hf-repo-v <user>/<model>[:quant]
                                        Hugging Face model repository for the vocoder model (default: unused)
                                        (env: LLAMA_ARG_HF_REPO_V)
-hffv, --hf-file-v FILE                 Hugging Face model file for the vocoder model (default: unused)
                                        (env: LLAMA_ARG_HF_FILE_V)
-hft,  --hf-token TOKEN                 Hugging Face access token (default: value from HF_TOKEN environment
                                        variable)
                                        (env: HF_TOKEN)
--log-disable                           Log disable
--log-file FNAME                        Log to file
--log-colors                            Enable colored logging
                                        (env: LLAMA_LOG_COLORS)
-v,    --verbose, --log-verbose         Set verbosity level to infinity (i.e. log all messages, useful for
                                        debugging)
-lv,   --verbosity, --log-verbosity N   Set the verbosity threshold. Messages with a higher verbosity will be
                                        ignored.
                                        (env: LLAMA_LOG_VERBOSITY)
--log-prefix                            Enable prefx in log messages
                                        (env: LLAMA_LOG_PREFIX)
--log-timestamps                        Enable timestamps in log messages
                                        (env: LLAMA_LOG_TIMESTAMPS)


----- sampling params -----

--samplers SAMPLERS                     samplers that will be used for generation in the order, separated by
                                        ';'
                                        (default: penalties;dry;top_k;typ_p;top_p;min_p;xtc;temperature)
-s,    --seed SEED                      RNG seed (default: -1, use random seed for -1)
--sampling-seq, --sampler-seq SEQUENCE
                                        simplified sequence for samplers that will be used (default: edkypmxt)
--ignore-eos                            ignore end of stream token and continue generating (implies
                                        --logit-bias EOS-inf)
--temp N                                temperature (default: 0.8)
--top-k N                               top-k sampling (default: 40, 0 = disabled)
--top-p N                               top-p sampling (default: 0.9, 1.0 = disabled)
--min-p N                               min-p sampling (default: 0.1, 0.0 = disabled)
--xtc-probability N                     xtc probability (default: 0.0, 0.0 = disabled)
--xtc-threshold N                       xtc threshold (default: 0.1, 1.0 = disabled)
--typical N                             locally typical sampling, parameter p (default: 1.0, 1.0 = disabled)
--repeat-last-n N                       last n tokens to consider for penalize (default: 64, 0 = disabled, -1
                                        = ctx_size)
--repeat-penalty N                      penalize repeat sequence of tokens (default: 1.0, 1.0 = disabled)
--presence-penalty N                    repeat alpha presence penalty (default: 0.0, 0.0 = disabled)
--frequency-penalty N                   repeat alpha frequency penalty (default: 0.0, 0.0 = disabled)
--dry-multiplier N                      set DRY sampling multiplier (default: 0.0, 0.0 = disabled)
--dry-base N                            set DRY sampling base value (default: 1.75)
--dry-allowed-length N                  set allowed length for DRY sampling (default: 2)
--dry-penalty-last-n N                  set DRY penalty for the last n tokens (default: -1, 0 = disable, -1 =
                                        context size)
--dry-sequence-breaker STRING           add sequence breaker for DRY sampling, clearing out default breakers
                                        ('\n', ':', '"', '*') in the process; use "none" to not use any
                                        sequence breakers
--dynatemp-range N                      dynamic temperature range (default: 0.0, 0.0 = disabled)
--dynatemp-exp N                        dynamic temperature exponent (default: 1.0)
--mirostat N                            use Mirostat sampling.
                                        Top K, Nucleus and Locally Typical samplers are ignored if used.
                                        (default: 0, 0 = disabled, 1 = Mirostat, 2 = Mirostat 2.0)
--mirostat-lr N                         Mirostat learning rate, parameter eta (default: 0.1)
--mirostat-ent N                        Mirostat target entropy, parameter tau (default: 5.0)
-l,    --logit-bias TOKEN_ID(+/-)BIAS   modifies the likelihood of token appearing in the completion,
                                        i.e. `--logit-bias 15043+1` to increase likelihood of token ' Hello',
                                        or `--logit-bias 15043-1` to decrease likelihood of token ' Hello'
--grammar GRAMMAR                       BNF-like grammar to constrain generations (see samples in grammars/
                                        dir) (default: '')
--grammar-file FNAME                    file to read grammar from
-j,    --json-schema SCHEMA             JSON schema to constrain generations (https://json-schema.org/), e.g.
                                        `{}` for any JSON object
                                        For schemas w/ external $refs, use --grammar +
                                        example/json_schema_to_grammar.py instead


----- example-specific params -----

--no-display-prompt                     don't print prompt at generation (default: false)
-co,   --color                          colorise output to distinguish prompt and user input from generations
                                        (default: false)
--no-context-shift                      disables context shift on inifinite text generation (default:
                                        disabled)
                                        (env: LLAMA_ARG_NO_CONTEXT_SHIFT)
-ptc,  --print-token-count N            print token count every N tokens (default: -1)
--prompt-cache FNAME                    file to cache prompt state for faster startup (default: none)
--prompt-cache-all                      if specified, saves user input and generations to cache as well
--prompt-cache-ro                       if specified, uses the prompt cache but does not update it
-r,    --reverse-prompt PROMPT          halt generation at PROMPT, return control in interactive mode
-sp,   --special                        special tokens output enabled (default: false)
-cnv,  --conversation                   run in conversation mode:
                                        - does not print special tokens and suffix/prefix
                                        - interactive mode is also enabled
                                        (default: auto enabled if chat template is available)
-no-cnv, --no-conversation              force disable conversation mode (default: false)
-i,    --interactive                    run in interactive mode (default: false)
-if,   --interactive-first              run in interactive mode and wait for input right away (default: false)
-mli,  --multiline-input                allows you to write or paste multiple lines without ending each in '\'
--in-prefix-bos                         prefix BOS to user inputs, preceding the `--in-prefix` string
--in-prefix STRING                      string to prefix user inputs with (default: empty)
--in-suffix STRING                      string to suffix after user inputs with (default: empty)
--no-warmup                             skip warming up the model with an empty run
-gan,  --grp-attn-n N                   group-attention factor (default: 1)
                                        (env: LLAMA_ARG_GRP_ATTN_N)
-gaw,  --grp-attn-w N                   group-attention width (default: 512)
                                        (env: LLAMA_ARG_GRP_ATTN_W)
--jinja                                 use jinja template for chat (default: disabled)
                                        (env: LLAMA_ARG_JINJA)
--chat-template JINJA_TEMPLATE          set custom jinja chat template (default: template taken from model's
                                        metadata)
                                        if suffix/prefix are specified, template will be disabled
                                        only commonly used templates are accepted (unless --jinja is set
                                        before this flag):
                                        list of built-in templates:
                                        chatglm3, chatglm4, chatml, command-r, deepseek, deepseek2, deepseek3,
                                        exaone3, falcon3, gemma, gigachat, glmedge, granite, llama2,
                                        llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, megrez, minicpm,
                                        mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, monarch,
                                        openchat, orion, phi3, phi4, rwkv-world, vicuna, vicuna-orca, zephyr
                                        (env: LLAMA_ARG_CHAT_TEMPLATE)
--chat-template-file JINJA_TEMPLATE_FILE
                                        set custom jinja chat template file (default: template taken from
                                        model's metadata)
                                        if suffix/prefix are specified, template will be disabled
                                        only commonly used templates are accepted (unless --jinja is set
                                        before this flag):
                                        list of built-in templates:
                                        chatglm3, chatglm4, chatml, command-r, deepseek, deepseek2, deepseek3,
                                        exaone3, falcon3, gemma, gigachat, glmedge, granite, llama2,
                                        llama2-sys, llama2-sys-bos, llama2-sys-strip, llama3, megrez, minicpm,
                                        mistral-v1, mistral-v3, mistral-v3-tekken, mistral-v7, monarch,
                                        openchat, orion, phi3, phi4, rwkv-world, vicuna, vicuna-orca, zephyr
                                        (env: LLAMA_ARG_CHAT_TEMPLATE_FILE)
--simple-io                             use basic IO for better compatibility in subprocesses and limited
                                        consoles

example usage:

  text generation:     llama-cli.exe -m your_model.gguf -p "I believe the meaning of life is" -n 128

  chat (conversation): llama-cli.exe -m your_model.gguf -p "You are a helpful assistant" -cnv


Первый момент, который я обнаружил — при предложенном параметре -n 256 вывод останавливался «на полуслове», не доходя до конца (это количество токенов — number of tokens to predict), я увеличил его до 4096 и процесс пошёл. Можно вообще не указывать, но есть риск того, что её поток сознания не остановится.

Если кому интересен полный лог старта, то вот:

llama-cli.exe -m DeepSeek-R1.Q8_0-00001-of-00015.gguf ...

Far Manager, version 3.0.6000.0 x64
Copyright © 1996-2000 Eugene Roshal, Copyright © 2000-2022 Far Group

F:>llama-cli.exe -m DeepSeek-R1.Q8_0-00001-of-00015.gguf -p "Hi!" -n 4096
build: 4628 (cde38332) with MSVC 19.42.34436.0 for x64
main: llama backend init
main: load the model and apply lora adapter, if any
llama_model_loader: additional 14 GGUFs metadata loaded.
llama_model_loader: loaded meta data with 48 key-value pairs and 1025 tensors from DeepSeek-R1.Q8_0-00001-of-00015.gguf (version GGUF V3 (latest))
llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output.
llama_model_loader: - kv 0: general.architecture str
= deepseek2
llama_model_loader: - kv 1: general.type str
= model
llama_model_loader: - kv 2: general.name str
= DeepSeek R1 BF16
llama_model_loader: - kv 3: general.quantized_by str
= Unsloth
llama_model_loader: - kv 4: general.size_label str
= 256x20B
llama_model_loader: - kv 5: general.repo_url str
= https://huggingface.co/unsloth
llama_model_loader: - kv 6: deepseek2.block_count u32
= 61
llama_model_loader: - kv 7: deepseek2.context_length u32
= 163840
llama_model_loader: - kv 8: deepseek2.embedding_length u32
= 7168
llama_model_loader: - kv 9: deepseek2.feed_forward_length u32
= 18432
llama_model_loader: - kv 10: deepseek2.attention.head_count u32
= 128
llama_model_loader: - kv 11: deepseek2.attention.head_count_kv u32
= 128
llama_model_loader: - kv 12: deepseek2.rope.freq_base f32
= 10000.000000
llama_model_loader: - kv 13: deepseek2.attention.layer_norm_rms_epsilon f32
= 0.000001
llama_model_loader: - kv 14: deepseek2.expert_used_count u32
= 8
llama_model_loader: - kv 15: general.file_type u32
= 7
llama_model_loader: - kv 16: deepseek2.leading_dense_block_count u32
= 3
llama_model_loader: - kv 17: deepseek2.vocab_size u32
= 129280
llama_model_loader: - kv 18: deepseek2.attention.q_lora_rank u32
= 1536
llama_model_loader: - kv 19: deepseek2.attention.kv_lora_rank u32
= 512
llama_model_loader: - kv 20: deepseek2.attention.key_length u32
= 192
llama_model_loader: - kv 21: deepseek2.attention.value_length u32
= 128
llama_model_loader: - kv 22: deepseek2.expert_feed_forward_length u32
= 2048
llama_model_loader: - kv 23: deepseek2.expert_count u32
= 256
llama_model_loader: - kv 24: deepseek2.expert_shared_count u32
= 1
llama_model_loader: - kv 25: deepseek2.expert_weights_scale f32
= 2.500000
llama_model_loader: - kv 26: deepseek2.expert_weights_norm bool
= true
llama_model_loader: - kv 27: deepseek2.expert_gating_func u32
= 2
llama_model_loader: - kv 28: deepseek2.rope.dimension_count u32
= 64
llama_model_loader: - kv 29: deepseek2.rope.scaling.type str
= yarn
llama_model_loader: - kv 30: deepseek2.rope.scaling.factor f32
= 40.000000
llama_model_loader: - kv 31: deepseek2.rope.scaling.original_context_length u32
= 4096
llama_model_loader: - kv 32: deepseek2.rope.scaling.yarn_log_multiplier f32
= 0.100000
llama_model_loader: - kv 33: tokenizer.ggml.model str
= gpt2
llama_model_loader: - kv 34: tokenizer.ggml.pre str
= deepseek-v3
llama_model_loader: - kv 35: tokenizer.ggml.tokens arr[str,129280] = ["<|begin▁of▁sentence|>", "<�...
llama_model_loader: - kv 36: tokenizer.ggml.token_type arr[i32,129280] = [3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
llama_model_loader: - kv 37: tokenizer.ggml.merges arr[str,127741] = ["Ġ t", "Ġ a", "i n", "Ġ Ġ", "h e...
llama_model_loader: - kv 38: tokenizer.ggml.bos_token_id u32
= 0
llama_model_loader: - kv 39: tokenizer.ggml.eos_token_id u32
= 1
llama_model_loader: - kv 40: tokenizer.ggml.padding_token_id u32
= 128815
llama_model_loader: - kv 41: tokenizer.ggml.add_bos_token bool
= true
llama_model_loader: - kv 42: tokenizer.ggml.add_eos_token bool
= false
llama_model_loader: - kv 43: tokenizer.chat_template str
= {% if not add_generation_prompt is de...
llama_model_loader: - kv 44: general.quantization_version u32
= 2
llama_model_loader: - kv 45: split.no u16
= 0
llama_model_loader: - kv 46: split.count u16
= 15
llama_model_loader: - kv 47: split.tensors.count i32
= 1025
llama_model_loader: - type f32: 361 tensors
llama_model_loader: - type q8_0: 664 tensors
print_info: file format = GGUF V3 (latest)
print_info: file type = Q8_0
print_info: file size = 664.29 GiB (8.50 BPW)
load: special_eos_id is not in special_eog_ids - the tokenizer config may be incorrect load: special tokens cache size = 819
load: token to piece cache size = 0.8223 MB
print_info: arch = deepseek2
print_info: vocab_only = 0
print_info: n_ctx_train = 163840
print_info: n_embd = 7168
print_info: n_layer = 61
print_info: n_head = 128
print_info: n_head_kv = 128
print_info: n_rot = 64
print_info: n_swa = 0
print_info: n_embd_head_k = 192
print_info: n_embd_head_v = 128
print_info: n_gqa = 1
print_info: n_embd_k_gqa = 24576
print_info: n_embd_v_gqa = 16384
print_info: f_norm_eps = 0.0e+00
print_info: f_norm_rms_eps = 1.0e-06
print_info: f_clamp_kqv = 0.0e+00
print_info: f_max_alibi_bias = 0.0e+00
print_info: f_logit_scale = 0.0e+00
print_info: n_ff = 18432
print_info: n_expert = 256
print_info: n_expert_used = 8
print_info: causal attn = 1
print_info: pooling type = 0
print_info: rope type = 0
print_info: rope scaling = yarn
print_info: freq_base_train = 10000.0
print_info: freq_scale_train = 0.025
print_info: n_ctx_orig_yarn = 4096
print_info: rope_finetuned = unknown
print_info: ssm_d_conv = 0
print_info: ssm_d_inner = 0
print_info: ssm_d_state = 0
print_info: ssm_dt_rank = 0
print_info: ssm_dt_b_c_rms = 0
print_info: model type = 671B
print_info: model params = 671.03 B
print_info: general.name = DeepSeek R1 BF16
print_info: n_layer_dense_lead = 3
print_info: n_lora_q = 1536
print_info: n_lora_kv = 512
print_info: n_ff_exp = 2048
print_info: n_expert_shared = 1
print_info: expert_weights_scale = 2.5
print_info: expert_weights_norm = 1
print_info: expert_gating_func = sigmoid
print_info: rope_yarn_log_mul = 0.1000
print_info: vocab type = BPE
print_info: n_vocab = 129280
print_info: n_merges = 127741
print_info: BOS token = 0 '<|begin▁of▁sentence|>'
print_info: EOS token = 1 '<|end▁of▁sentence|>'
print_info: EOT token = 1 '<|end▁of▁sentence|>'
print_info: PAD token = 128815 '<|PAD▁TOKEN|>'
print_info: LF token = 201 'Ċ'
print_info: FIM PRE token = 128801 '<|fim▁begin|>'
print_info: FIM SUF token = 128800 '<|fim▁hole|>'
print_info: FIM MID token = 128802 '<|fim▁end|>'
print_info: EOG token = 1 '<|end▁of▁sentence|>'
print_info: max token length = 256
load_tensors: offloading 0 repeating layers to GPU
load_tensors: offloaded 0/62 layers to GPU
load_tensors: CPU_Mapped model buffer size = 45565.90 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 46661.11 MiB
load_tensors: CPU_Mapped model buffer size = 28077.60 MiB
llama_init_from_model: n_seq_max = 1
llama_init_from_model: n_ctx = 4096
llama_init_from_model: n_ctx_per_seq = 4096
llama_init_from_model: n_batch = 2048
llama_init_from_model: n_ubatch = 512
llama_init_from_model: flash_attn = 0
llama_init_from_model: freq_base = 10000.0
llama_init_from_model: freq_scale = 0.025
llama_init_from_model: n_ctx_per_seq (4096) < n_ctx_train (163840) -- the full capacity of the model will not be utilized
llama_kv_cache_init: kv_size = 4096, offload = 1, type_k = 'f16', type_v = 'f16', n_layer = 61, can_shift = 0
llama_kv_cache_init: CPU KV buffer size = 19520.00 MiB
llama_init_from_model: KV self size = 19520.00 MiB, K (f16): 11712.00 MiB, V (f16): 7808.00 MiB
llama_init_from_model: CPU output buffer size = 0.49 MiB
llama_init_from_model: CPU compute buffer size = 1186.01 MiB
llama_init_from_model: graph nodes = 5025
llama_init_from_model: graph splits = 1
common_init_from_params: KV cache shifting is not supported for this model, disabling KV cache shifting
common_init_from_params: setting dry_penalty_last_n to ctx_size = 4096
common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable)
main: llama threadpool init, n_threads = 28
main: chat template is available, enabling conversation mode (disable it with -no-cnv) main: chat template example:
You are a helpful assistant

<|User|>Hello<|Assistant|>Hi there<|end▁of▁sentence|><|User|>How are you?<|Ass
istant|>

system_info: n_threads = 28 (n_threads_batch = 28) / 28 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | AVX512 = 1 | LLAMAFILE = 1 | OPENMP = 1 | AARCH64_REPACK = 1 |

main: interactive mode on.
sampler seed: 526007933
sampler params:
repeat_last_n = 64, repeat_penalty = 1.000, frequency_penalty = 0.000, presence_penalty = 0.000
dry_multiplier = 0.000, dry_base = 1.750, dry_allowed_length = 2, dry_penalty_last_n = 4096
top_k = 40, top_p = 0.950, min_p = 0.050, xtc_probability = 0.000, xtc_threshold = 0.100, typical_p = 1.000, temp = 0.800
mirostat = 0, mirostat_lr = 0.100, mirostat_ent = 5.000
sampler chain: logits -> logit-bias -> penalties -> dry -> top-k -> typical -> top-p -> min-p -> xtc -> temp-ext -> dist
generate: n_ctx = 4096, n_batch = 2048, n_predict = 4096, n_keep = 1

== Running in interactive mode. ==

  • Press Ctrl+C to interject at any time.

  • Press Return to return control to the AI.

  • To return control without starting a new line, end your input with '/'.

  • If you want to submit another line, end your input with ''.

Hi!

«Работаем»

Ну вот прям «работой» это назвать сложно, потому что это всё отчаянно медленно.

Сразу после запуска модель целиком в память не грузится (точнее не «коммитится»), она как бы «догружается» при общении и количество занятой памяти растёт по мере работы, выходя на «плато» после двух-трёх промптов.

При первом «холодном» старте до появления приглашения проходит почти две минуты, дальше она радует нас примерно токеном в секунду.

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

Как видите, память заполнилась примерно на треть после старта и чуть более чем наполовину после первого промпта.

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

Вот вывод «как есть»:

Can you please provide C code of Runge Kutta Method for (x-y)/(x+y)?

Hi, DeepSeek!

Hi! How can I assist you today?

Can you please provide C code of Runge Kutta Method for (x-y)/(x+y)?

Certainly! The Runge-Kutta method is a numerical technique used to solve ordinary differential equations (ODEs). For the differential equation dy/dx = (x - y)/(x + y), we can apply the 4th-order Runge-Kutta method (RK4). Here's a C code implementation:

#include <stdio.h>
#include <math.h>

// Define the differential equation dy/dx = (x - y)/(x + y)
double f(double x, double y) {
    return (x - y) / (x + y);
}

// 4th-order Runge-Kutta method
void rungeKutta4(double x0, double y0, double h, double x_target) {
    double x = x0;
    double y = y0;
    double k1, k2, k3, k4;

    printf("Initial conditions: x = %lf, y = %lf\n", x, y);

    while (x < x_target) {
        if (x + h > x_target) {
            h = x_target - x; // Adjust step to reach x_target exactly
        }

        k1 = h * f(x, y);
        k2 = h * f(x + h/2, y + k1/2);
        k3 = h * f(x + h/2, y + k2/2);
        k4 = h * f(x + h, y + k3);

        y = y + (k1 + 2*k2 + 2*k3 + k4)/6;
        x = x + h;

        printf("x = %lf, y = %lf\n", x, y);
    }
}

int main() {
    double x0 = 1.0;   // Initial x
    double y0 = 0.0;   // Initial y
    double h = 0.1;    // Step size
    double x_target = 2.0; // Target x value

    rungeKutta4(x0, y0, h, x_target);
    return 0;
}

Important Notes:

  1. Initial Conditions: The current example uses x0=1.0, y0=0.0, step size h=0.1, and integrates up to x_target=2.0. Adjust these values as needed.

  2. Division by Zero: The function f(x,y) will have a division by zero if x + y = 0. Ensure your initial conditions and step size avoid this scenario.

  3. Adaptive Step Size: For better accuracy, you might want to implement adaptive step size control, but this example uses a fixed step size for simplicity.

  4. Output: The code prints the solution at each step. Modify the printf statements as needed for your use case.

Let me know if you need further clarification!

На всё про всё у неё ушло десять минут реального времени (проверку корректности решения оставим за кадром). Процессор, как видите, был занят чуть больше чем на половину. Тут надо заметить, что у меня был включён гипертрединг (ну или гиперпоточность), так что сегодня утром первым делом я его отключил и повторил эксперимент, и да, отключение НТ уверенно кладёт стрелку нашего спидометра на ограничитель, теперь все ядра активно заняты (кстати, конкретно этот hp вовсе не ревёт при этом как самолёт, идущий на взлёт, что приятно):

По скорости сильных изменений в производительности я не заметил, примерно тоже самое, токен в секунду или около того. Но гораздо интереснее тут другое. Шёл второй день экспериментов, я и пожелал модели доброго утра (я обычно вежливый, да, в том числе с ИИ). Она очень обрадовалась, просветлела (даже несмотря на то, что я ошибся в имени), и на мой стандартный вопрос про Рунге-Кутта пустилась в пространные размышления о смысле жизни на сорок минут (время в гифке выше).

И вот тут как раз возник тот «ага!» момент, о котором много где упоминали, когда модель выдаёт что-то типа "Wait, but the step function can be part of the loop. Alternatively, write a function that takes x, y, h, and returns the new y..."

Вообще я считаю, что выданная простыня вполне заслуживает того, чтобы быть приведённой полностью.

Очень много букв

Good morning, DeppSeek!

Okay, the user greeted me with "Good morning, DeppSeek!" Let me start by acknowledging their greeting and setting a friendly tone. Maybe I should respond with a cheerful good morning and ask how I can assist them today. Since they might need help with something specific, I should keep the response open-ended to encourage them to share their request. I'll make sure to keep it concise and welcoming.

Good morning! � How can I assist you today? Whether it's brainstorming ideas, solving
a problem, or just chatting, I'm here to help! Let me know what's on your mind. �

Please provide C code for Runge Kutta method for (x-y)/(x+y)

Okay, the user is asking for C code that implements the Runge-Kutta method for the differential equation given by (x - y)/(x + y). Let me start by recalling what the Runge-Kutta method is. The fourth-order Runge-Kutta (RK4) method is a numerical technique used to solve ordinary differential equations (ODEs) with a given initial condition. It's more accurate than Euler's method because it uses multiple intermediate steps to approximate the solution over each interval.

First, I need to confirm the ODE the user wants to solve. The function provided is (x - y)/(x + y). Typically, ODEs are expressed as dy/dx = f(x, y), so I'll assume that the differential equation here is dy/dx = (x - y)/(x + y). That makes sense.

Next, I should outline the RK4 method. The RK4 method computes the next value y_{n+1} using the current value y_n and the weighted average of four increments:

k1 = h * f(x_n, y_n)
k2 = h * f(x_n + h/2, y_n + k1/2)
k3 = h * f(x_n + h/2, y_n + k2/2)
k4 = h * f(x_n + h, y_n + k3)

Then, y_{n+1} = y_n + (k1 + 2k2 + 2k3 + k4)/6

So, in the C code, I'll need to implement this formula.

The user wants a C program. Let me structure the code step by step. The code should include the necessary headers, define the function f(x, y) corresponding to the ODE, and implement the RK4 step as a function. Then, in the main function, set the initial conditions, step size h, number of steps, and loop through each step to compute the solution.

Wait, initial conditions are needed. Since the user didn't specify them, I should choose a default initial value, say x0, y0, and a range for x. Let's assume the user wants to start at some x0 (like 0) with y0, and compute up to a certain point. But since the user didn't specify, perhaps the code should take initial values, step size, and number of steps as inputs or define them as constants. To make it simple, maybe hardcode initial x and y, step size h, and the number of steps. Then, in the code comments, mention that these can be adjusted.

Also, need to be cautious about division by zero in the function (x + y) could be zero. The code should handle cases where x + y is zero, but since the user hasn't specified error handling, perhaps just note that in the comments.

Let me outline the code:

  1. Include standard headers (stdio.h, math.h if needed, but here maybe not necessary). 2. Define the function f(x, y) which returns (x - y)/(x + y).

  2. Implement the RK4 step function that takes current x, y, step h, computes k1-k4, updates y.

  3. In main, set initial x0, y0, h, number of steps.

  4. Loop over the steps, compute each step, print x and y.

But let's test this with an example. Suppose initial x0 is 1, y0 is 1, h=0.1, and compute a few steps. Wait, but if x0=1 and y0=1, then x + y = 2, so the function is (1-1)/2 = 0. So the first step would compute k1 to k4 based on that. However, if x and y start at 0, the denominator is zero. So need to ensure the initial values don't cause division by zero. So perhaps in the code example, choose x0=1, y0=2, just to have a safe starting point.

Alternatively, ask the user for input. But since the user didn't specify, it's better to hardcode values and mention in comments to adjust them.

Another point: in the code, when computing x, since the ODE is dy/dx = f(x,y), each step advances x by h. So in the main loop, after each step, x increases by h.

Putting it all together:

The code will have:

  • Function definition for f(x, y)

  • A function to perform one RK4 step

  • Main function with loop

Wait, but the step function can be part of the loop. Alternatively, write a function that takes x, y, h, and returns the new y.

Yes, that's better. So:

double rungeKuttaStep(double x, double y, double h) {
    compute k1, k2, k3, k4
    return y + (k1 + 2*k2 + 2*k3 + k4)/6;
}

But since each k depends on evaluations at different points, need to compute them step by step.

So here's the step-by-step code:

#include <stdio.h>

double f(double x, double y) {
    return (x - y) / (x + y);
}

void rungeKutta4(double *x, double *y, double h) {
    double k1 = h * f(*x, *y);
    double k2 = h * f(*x + h/2, *y + k1/2);
    double k3 = h * f(*x + h/2, *y + k2/2);
    double k4 = h * f(*x + h, *y + k3);

    *y += (k1 + 2*k2 + 2*k3 + k4) / 6;
    *x += h;
}

int main() {
    double x0 = 1.0;  // Initial x
    double y0 = 2.0;  // Initial y
    double h = 0.1;    // Step size
    int steps = 10;    // Number of steps

    printf("Initial conditions: x = %f, y = %f\n", x0, y0);
    printf("Step size: %f\n", h);
    printf("Number of steps: %d\n\n", steps);

    for (int i = 0; i < steps; i++) {
        rungeKutta4(&x0, &y0, h);
        printf("Step %d: x = %f, y = %f\n", i+1, x0, y0);
    }

    return 0;
}

Wait, no: in each call to rungeKutta4, x is incremented by h. But the loop in main is called steps times, so after each step, x increases by h. That's correct.

Wait, in the initial code, x0 starts at 1.0. Then, after the first call to rungeKutta4, x0 becomes 1.0 + h (since *x +=h). So the first step's x is 1.1, and the y is updated. That's correct.

But in RK4, when you compute k1, you use x_n, then k2 and k3 use x_n + h/2, and k4 uses x_n + h. Then, after all, x increments by h. So that's accurate.

Now, let's check if the function f is correctly implemented. Yes, (x - y)/(x + y).

But wait, the user wrote the differential equation as (x - y)/(x + y). So dy/dx = (x - y)/(x + y). The code correctly returns that.

Potential issues: division by zero when x + y is zero. But the example initial conditions x0=1.0 and y0=2.0 avoid that. The user may need to adjust initial conditions accordingly.

Also, the code prints after each step, showing x and y.

But the user might want to integrate over a specific interval. Let's see: if h=0.1 and steps=10, x goes from 1.0 to 1.0 + 10*0.1=2.0.

Yes. So the code as written is correct.

I should test this code to ensure there are no syntax errors. Let me see:

  • The function rungeKutta4 takes pointers to x and y, modifies them in place.

  • The main function loops steps times, each time calling the function and printing.

  • The f function is correctly defined.

Yes, this should compile and run.

However, in the main loop, the initial print is before the loop, so the initial x and y are printed, then the loop starts. But the first call to rungeKutta4 modifies x0 and y0 to the next step. Then, the first printed step is after the first update. So the first printed step is Step 1: x=1.1, y= updated value.

If the user wants to see the values at each step including the initial, maybe the code should print before updating. But in the code as written, the initial conditions are printed once, then the loop starts, updates, and prints the new x and y each time. So the output shows the progression from the initial step onwards. That's okay.

Alternatively, adjust the code to print after each step, which is what is done here.

I think this code should work. Therefore, the answer should include this code with explanations of the parameters and a note about potential division by zero.

Here's a C implementation of the 4th-order Runge-Kutta method for the differential equation dy/dx = (x - y)/(x + y):

#include <stdio.h>

// Define the differential equation dy/dx = (x - y)/(x + y)
double f(double x, double y) {
    return (x - y)/(x + y);
}

// Performs one iteration of RK4 method
void rk4_step(double *x, double *y, double h) {
    double k1 = h * f(*x, *y);
    double k2 = h * f(*x + h/2, *y + k1/2);
    double k3 = h * f(*x + h/2, *y + k2/2);
    double k4 = h * f(*x + h, *y + k3);

    *y += (k1 + 2*k2 + 2*k3 + k4)/6;
    *x += h;
}

int main() {
    // Initial conditions
    double x0 = 1.0;    // Initial x-value
    double y0 = 0.5;    // Initial y-value
    double h = 0.1;     // Step size
    int steps = 10;     // Number of steps

    printf("Starting at: x = %.2f, y = %.2f\n", x0, y0);
    printf("Step size: %.2f\n", h);
    printf("Number of steps: %d\n\n", steps);

    for(int i = 1; i <= steps; i++) {
        rk4_step(&x0, &y0, h);
        printf("Step %2d: x = %.3f, y = %.6f\n", i, x0, y0);
    }

    return 0;
}

Key components:

  1. f(x, y) - Implements the differential equation

  2. rk4_step() - Performs one RK4 iteration

  3. main() - Controls the simulation with parameters:

    • Initial conditions (x0, y0)

    • Step size (h)

    • Number of steps

Notes:

  • Adjust x0, y0, h, and steps as needed

  • Be cautious when x + y = 0 (potential division by zero)

  • Accuracy depends on step size h (smaller h = more precision)

  • Output shows x/y values at each step

To use this program:

  1. Compile with any C compiler (e.g., gcc rk4.c -o rk4)

  2. Run the executable

  3. Modify initial values for different starting conditions

Would you like me to explain any part in more detail or modify specific aspects of the implementation?

Насколько этот опус лучше того, что был приведён выше, это уже другой вопрос, но разительным образом отличающийся ответ от предыдущего при почти идентичном промпте — это любопытный момент (параметры запуска я, ясное дело, никак не менял).

Кстати, о параметрах. Есть два режима запуска.

Первый вот такой, он называется "Text generation":

llama-cli.exe -m your_model.gguf -p "Hi!" -n 4096

А второй с ключом -cnv — "Сhat (conversation)"

llama-cli.exe -m your_model.gguf -p "Hello!" -cnv

Первый используется в том случае, если искуственный интеллект пишет за вас диссертацию, а второй — если он используется в качестве собеседника (чат-бота). При этом инструкция говорит, что модель должна быть «заточена» под этот режим. В принципе вы можете попросить её саму рассказать об отличиях, она напишет, что в Чат режиме можно использовать структурированные реплики с метками (например, [INST], <<SYS>>), останавливать её токенами конца диалога (например, </s>) и что то там ещё.

Я попробовал и так и сяк и основное отличие, которое заметил, это то, что объяснения в режиме «чат общения» сопровождаются готовыми формулами в TeX формате, выглядит это вот так, если я вставлю вывод прямо в редактор хабра:


Explanation:

  1. Function f: Implements the differential equation

( \frac{dy}{dx} = \frac{x - y}{x + y} ).
  1. RK4 Method:

    • Takes initial conditions (x0, y0), step size h, and target x_target.

    • Iteratively computes the next y using the RK4 formulas:

      k_1 = h \cdot f(x_n, y_n),k_2 = h \cdot f(x_n + \frac{h}{2}, y_n + \frac{k_1}{2}),k_3 = h \cdot f(x_n + \frac{h}{2}, y_n + \frac{k_2}{2}),k_4 = h \cdot f(x_n + h, y_n + k_3),y_{n+1} = y_n + \frac{1}{6}(k_1 + 2k_2 + 2k_3 + k_4).

...

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

Ну а так — русский вроде знает:

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

В стихах тоже может, по-немецки в том числе. Похоже, моя исходящая деловая корреспонденция станет несколько разнообразнее.

Короче у меня под столом завёлся личный секретарь, хоть и чутка тормознутый. Гугль, википедия, вольфрам математика, словарь, корректор в одном флаконе, да ещё и на разных языках. Если вы хотите его (или её) о чём-нибудь спросить — не стесняйтесь, задавайте вопросы в комментах, я с удовольствием передам ваши вопросы и опубликую ответы.

При завершении работы выдаёт статистику, около одного токена в секунду:

llama_perf_sampler_print: sampling time = 52.33 ms / 209 runs (0.25 ms per token,  3993.66 tokens per second)
llama_perf_context_print: load time = 89790.30 ms
llama_perf_context_print: prompt eval time = 87115.12 ms / 112 tokens (777.81 ms per token, 1.29 tokens per second)
llama_perf_context_print: eval time = 1883493.69 ms / 1777 runs (1059.93 ms per token,     0.94 tokens per second)
llama_perf_context_print: total time = 3136520.40 ms / 1889 tokens

Кому не нравится консоль, можно запустить и вот так:

llama-server.exe -m DeepSeek-R1.Q8_0-00001-of-00015.gguf --port 8082

Эта штука поднимет веб сервер (по умолчанию на порту 8080, но он у меня занят, так что 8082), будет красивее:

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

Производительность

Она, конечно удручает. Безусловно, более быстрая память типа DDR5 слегка улучшит ситуацию. В идеале надо иметь быструю GPU память, но пяток адаптеров типа NVIDIA H200, у которых по 141 ГБ памяти с пропускной способностью под пять терабайт в секунду сразу отправят нас в мир шестизначных ценников.

Что по этой конфигурации, то там можно ещё немного попытаться подкрутить в BIOS.

Некоторый потенцал, возможно, кроется в NUMA:

Пока что там не всё хорошо, но общественность этим уже озаботилась, на гитхабе висит открытый тикет — Feature Request: NUMA-aware MoE Expert Allocation for Improved Performanc #11333. Вообще когда мы упираемся в пропускную способность памяти — как отметили в комментах к изначальному посту с точки зрения эффективности не очень хорошо иметь два процессора, конкурирующих за общую память (хотя эффективная работа с двенадцатиканальной памятью на двухпроцессорной системе вкупе с NUMA — это отдельная тема, требующая дотошной проверки и бенчмарков).

По параметрам запуска я сильно не лазал, возможно там тоже что-то можно подкрутить.

Можно пересобрать всё из исходников и посмотреть, где проседает производительность и пройтись по «горячим точкам», да хоть тем же Intel VTune.

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

Некоторая надежда на OpenVINO, по идее там примерно вот так можно запуститься, если из Питона:

import openvino_genai
# will run the model on CPU, GPU, or NPU are possible options
pipe = openvino_genai.LLMPipeline("F:\<Тут Модель>", "CPU")
print(pipe.generate("The answer to life, the universe, and everything?", max_new_tokes =4096)

Но напрямую gguf не поддерживается, там конвертировать надо, пока не брался. Если кто-нибудь уже делал подход к этому снаряду — напишите, пожалуйста в комментах.

AVX-512 — тоже отдельная тема, бывает и так, что код, черезчур активно использующий эти инструкции, начинает притормаживать из-за того, что процессор снижает частоту (ему слишком много транзисторов одномоментно переключать бывает сложновато и он греется), кроме того разные компиляторы отличаются эффективностью кодогенерации, можно попробовать пересобрать, скажем Intel OneAPI.

Если брать не такие увесистые модели, то, конечно, всё работает резвее, но и «качество» вывода падает — для того же Рунге-Кутта описание алгоритма ещё выдаётся, а вот исходный код — уже нет (хотя есть «coder» модели, заточенные как раз под написание кода, надо будет попробовать).

Но в общем и целом впечатляет, это да.

А, совсем забыл,

ответ на загадку про фильм

Hello, DeepSeek!

Greetings! I'm DeepSeek-R1, an artificial intelligence assistant created by DeepSeek.
For comprehensive details about our models and products, we invite you to consult our official documentation.

Can you please suggest the title of the Movie from mid 90s about Gigabytes?

The movie you're thinking of from the mid-90s that involves gigabytes and hacking is likely "Hackers" (1995). It prominently features themes of computer hacking, data, and includes references to large amounts of data (gigabytes), though its portrayal of technology is stylized and not entirely accurate. Another possibility is "The Net" (1995), which revolves around cyber-threats and data manipulation. Both films capture the tech-centric paranoia of that era! Let me know if you'd like more details. �

No, I mean Movie about transferring large volumes of the data

Ah, got it! The mid-90s movie centered around transferring large volumes of data—specifically gigabytes—is "Sneakers" (1992). While it’s slightly earlier than the mid-90s, it’s often associated with that era and involves a team of security experts tasked with stealing a "black box" device capable of decrypting any system, which ties into data transmission and security. If you’re looking for something strictly mid-90s, "Johnny Mnemonic" (1995) features a protagonist who carries sensitive data (160GB!) in his brain implant, navigating a cyberpunk world to deliver it. Either could fit your description! �

Со второй попытки — бинго! Речь шла про киберпанковский «Джонни-мнемоник» c Киану Ривзом. Триста c лишним гигабайт, о которых там речь, казались нам чудовищным объёмом в то время. Времена меняются, прогресс идёт.

Всем добра!