diff --git a/CMakeLists.txt b/CMakeLists.txt index dd29efb..6c16806 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,18 @@ cmake_minimum_required(VERSION 3.20) project(Xenith) -set(CMAKE_CXX_STANDARD 17) # В Makefile указан c++17 +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Опции компиляции из твоего Makefile -# Для Debug сборки CLion обычно сам добавляет -O0 -g, но можно форсировать if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -fsanitize=address,undefined") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "-fsanitize=address,undefined") else() - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -ffast-math -funroll-loops") + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ffast-math -funroll-loops") endif() -# Добавляем предупреждения add_compile_options(-Wall -Wextra -Wno-unused-parameter) -# Список исходных файлов из твоего Makefile set(SOURCES main.cpp xenith/core/model.cpp diff --git a/README.md b/README.md index 1cdf6e0..b8e8f32 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,6 @@ Трансформер на чистом C++: обучение и генерация текста на CPU, без внешних зависимостей. Всё в одном бинарнике. -``` -make # собрать -> bin/xenith -./bin/xenith --help -``` - ## Что внутри Архитектура — как у LLaMA: pre-norm, RMSNorm, RoPE, SwiGLU, связанные @@ -28,15 +23,15 @@ make # собрать -> bin/xenith ```bash # 1) собрать модель из своего текста -./bin/xenith new models/my.xnh --corpus data.txt \ +./bin/Xenith new models/my.xnh --corpus data.txt \ --vocab 512 --embd 128 --layers 6 --heads 8 --ctx 256 # 2) обучить -./bin/xenith train models/my.xnh --corpus data.txt \ +./bin/Xenith train models/my.xnh --corpus data.txt \ --out models/my_trained.xnh --steps 5000 --batch 16 --lr 3e-4 # 3) сгенерировать -./bin/xenith gen models/my_trained.xnh --prompt "Привет" --n 200 --temp 0.8 +./bin/Xenith gen models/my_trained.xnh --prompt "Привет" --n 200 --temp 0.8 ``` ## Команды @@ -105,9 +100,9 @@ make # собрать -> bin/xenith ### info / gradcheck / bench ```bash -./bin/xenith info models/my.xnh # конфигурация и словарь -./bin/xenith gradcheck # градиенты против численных -./bin/xenith bench models/my.xnh # скорость +./bin/Xenith info models/my.xnh # конфигурация и словарь +./bin/Xenith gradcheck # градиенты против численных +./bin/Xenith bench models/my.xnh # скорость ``` `gradcheck` стоит запускать после любой правки в `model.cpp` / `backward.cpp` — diff --git a/main.cpp b/main.cpp index 5b6e342..2f9a9cf 100644 --- a/main.cpp +++ b/main.cpp @@ -77,12 +77,13 @@ static void usage() { xenith <команда> [опции] КОМАНДЫ - new создать новую модель из корпуса - train обучить существующую модель - gen сгенерировать текст - info показать конфигурацию модели - gradcheck проверить градиенты численно - bench замерить скорость форварда и шага обучения + new создать новую модель из корпуса + train обучить существующую модель + gen сгенерировать текст + info показать конфигурацию модели + gradcheck проверить градиенты численно + bench замерить скорость форварда и шага обучения + ollama запустьтить сервер с api ollama ПРИМЕРЫ xenith new model.xnh --corpus data.txt --vocab 512 --embd 64 --layers 4 --heads 4 @@ -131,6 +132,10 @@ static void usage() { --no-stream не печатать в процессе --batch "a;b;c" несколько промптов через ; --show-tokens показать id токенов + +ОПЦИИ ollama + --port PORT порт на котором будет открыт сервер + --conf NAME.conf )"); } @@ -297,6 +302,53 @@ static int cmd_bench(const Args& a) { return run_bench(ck, a.geti("iters", 20), a.geti("block", 64)); } +static int cmd_ollama(const Args& a) { + if (a.pos.empty()) { fprintf(stderr, "gen: укажите файл модели\n"); return 1; } + Checkpoint ck; + std::string err; + if (!load_checkpoint(a.pos[0], ck, err)) { fprintf(stderr, "gen: %s\n", err.c_str()); return 1; } + + GenConfig gc; + gc.max_new_tokens = a.geti("n", 200); + gc.temperature = a.getf("temp", 0.8f); + gc.top_k = a.geti("top-k", 40); + gc.top_p = a.getf("top-p", 0.95f); + gc.seed = a.geti("seed", -1); + gc.stream = !a.has("no-stream"); + + if (a.has("batch")) { + std::vector prompts; + std::string s = a.get("batch"); + size_t start = 0; + while (start <= s.size()) { + size_t p = s.find(';', start); + if (p == std::string::npos) { prompts.push_back(s.substr(start)); break; } + prompts.push_back(s.substr(start, p - start)); + start = p + 1; + } + gc.stream = false; + std::vector outs = generate_batch(ck.params, ck.tok, prompts, gc); + for (size_t i = 0; i < outs.size(); ++i) { + printf("=== промпт %zu: %s\n%s\n\n", i + 1, prompts[i].c_str(), outs[i].c_str()); + } + return 0; + } + + std::string prompt = a.get("prompt", ""); + if (a.pos.size() > 1) prompt = a.pos[1]; + + std::vector ids; + std::string text = generate(ck.params, ck.tok, prompt, gc, &ids); + + if (a.has("show-tokens")) { + printf("\n--- токены (%zu) ---\n", ids.size()); + for (size_t i = 0; i < ids.size(); ++i) + printf("%d ", ids[i]); + printf("\n"); + } + return 0; +} + int main(int argc, char** argv) { if (argc < 2) { usage(); return 1; } const std::string cmd = argv[1]; @@ -309,6 +361,7 @@ int main(int argc, char** argv) { if (cmd == "info") return cmd_info(a); if (cmd == "gradcheck") return cmd_gradcheck(a); if (cmd == "bench") return cmd_bench(a); + if (cmd == "ollama") return cmd_bench(a); fprintf(stderr, "неизвестная команда: %s\n\n", cmd.c_str()); usage(); diff --git a/models/my.xnh b/models/my.xnh new file mode 100644 index 0000000..11bbee0 Binary files /dev/null and b/models/my.xnh differ