Skip to content

Commit b72d755

Browse files
committed
Merge branch 'master' into xsn/vision_2
2 parents b986af8 + 564804b commit b72d755

File tree

10 files changed

+165
-92
lines changed

10 files changed

+165
-92
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ Inference of Meta's [LLaMA](https://arxiv.org/abs/2302.13971) model (and others)
1616

1717
## Hot topics
1818

19-
- **Introducing GGUF-my-LoRA** https://github.com/ggerganov/llama.cpp/discussions/10123
19+
- **VS Code extension for FIM completions:** https://github.com/ggml-org/llama.vscode
20+
- Vim/Neovim plugin for FIM completions: https://github.com/ggml-org/llama.vim
21+
- Introducing GGUF-my-LoRA https://github.com/ggerganov/llama.cpp/discussions/10123
2022
- Hugging Face Inference Endpoints now support GGUF out of the box! https://github.com/ggerganov/llama.cpp/discussions/9669
2123
- Hugging Face GGUF editor: [discussion](https://github.com/ggerganov/llama.cpp/discussions/9268) | [tool](https://huggingface.co/spaces/CISCai/gguf-editor)
2224

common/chat-template.hpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,22 @@ class chat_template {
2525
// Meta-Llama-3.1-8B-Instruct's template expects arguments to be an object.
2626
// Most other templates (and OpenAI's API) expect the arguments object to be stringified.
2727
bool requires_object_arguments_ = false;
28+
bool requires_typed_content_ = false;
2829
bool supports_system_role_ = true;
2930
bool supports_parallel_tool_calls_ = false;
3031
std::string source_;
3132
std::string bos_token_;
3233
std::string eos_token_;
3334
std::shared_ptr<minja::TemplateNode> template_root_;
3435

35-
std::string try_render(
36+
std::string try_raw_render(
3637
const nlohmann::ordered_json & messages,
3738
const nlohmann::ordered_json & tools,
3839
bool add_generation_prompt,
3940
const nlohmann::ordered_json & extra_context = nlohmann::ordered_json()) const
4041
{
4142
try {
42-
auto prompt = apply(messages, tools, add_generation_prompt, extra_context);
43+
auto prompt = apply(messages, tools, add_generation_prompt, extra_context, /* adjust_inputs= */ false);
4344
// fprintf(stderr, "Prompt: %s\n", prompt.c_str());
4445
return prompt;
4546
} catch (const std::exception & e) {
@@ -60,7 +61,7 @@ class chat_template {
6061
supports_tools_ = source.find("tools") != std::string::npos;
6162

6263
auto renders_string_arguments =
63-
try_render({
64+
try_raw_render({
6465
{
6566
{"role", "user"},
6667
{"content", "Hey"}
@@ -81,7 +82,7 @@ class chat_template {
8182
}, {}, false).find("{\"code\": \"print") != std::string::npos;
8283
if (!renders_string_arguments) {
8384
auto renders_object_arguments =
84-
try_render({
85+
try_raw_render({
8586
{
8687
{"role", "user"},
8788
{"content", "Hey"}
@@ -106,10 +107,13 @@ class chat_template {
106107
}
107108
supports_parallel_tool_calls_ = source.find("tool_call_id") != std::string::npos;
108109

109-
supports_system_role_ = try_render({
110+
supports_system_role_ = try_raw_render({
110111
{{"role", "system"}, {"content", "<System Needle>"}},
111112
{{"role", "user"}, {"content", "Hey"}}
112113
}, {}, false).find("<System Needle>") != std::string::npos;
114+
115+
requires_typed_content_ = try_raw_render({{{"role", "user"}, {"content", "Hey"}}}, {}, false).find("Hey") == std::string::npos
116+
&& try_raw_render({{{"role", "user"}, {"content", {{{"type", "text"}, {"text", "Hey"}}}}}}, {}, false).find("Hey") != std::string::npos;
113117
}
114118

115119
const std::string & source() const { return source_; }
@@ -122,19 +126,34 @@ class chat_template {
122126
const nlohmann::ordered_json & messages,
123127
const nlohmann::ordered_json & tools,
124128
bool add_generation_prompt,
125-
const nlohmann::ordered_json & extra_context = nlohmann::ordered_json()) const
129+
const nlohmann::ordered_json & extra_context = nlohmann::ordered_json(),
130+
bool adjust_inputs = true) const
126131
{
127132
json actual_messages;
128133

129134
// First, "fix" messages so they have a chance to be rendered correctly by the template
130135

131-
if (requires_object_arguments_ || !supports_system_role_ || !supports_tools_) {
136+
if (adjust_inputs && (requires_object_arguments_ || !supports_system_role_ || !supports_tools_ || requires_typed_content_)) {
132137
actual_messages = json::array();
133138

139+
auto add_message = [&](const json & msg) {
140+
if (requires_typed_content_ && msg.contains("content") && !msg.at("content").is_null() && msg.at("content").is_string()) {
141+
actual_messages.push_back({
142+
{"role", msg.at("role")},
143+
{"content", {{
144+
{"type", "text"},
145+
{"text", msg.at("content")},
146+
}}},
147+
});
148+
} else {
149+
actual_messages.push_back(msg);
150+
}
151+
};
152+
134153
std::string pending_system;
135154
auto flush_sys = [&]() {
136155
if (!pending_system.empty()) {
137-
actual_messages.push_back({
156+
add_message({
138157
{"role", "user"},
139158
{"content", pending_system},
140159
});
@@ -217,7 +236,7 @@ class chat_template {
217236
}
218237
}
219238
}
220-
actual_messages.push_back(message);
239+
add_message(message);
221240
}
222241
flush_sys();
223242
} else {

common/minja.hpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ enum SpaceHandling { Keep, Strip, StripSpaces, StripNewline };
693693

694694
class TemplateToken {
695695
public:
696-
enum class Type { Text, Expression, If, Else, Elif, EndIf, For, EndFor, Set, EndSet, Comment, Macro, EndMacro, Filter, EndFilter };
696+
enum class Type { Text, Expression, If, Else, Elif, EndIf, For, EndFor, Generation, EndGeneration, Set, EndSet, Comment, Macro, EndMacro, Filter, EndFilter };
697697

698698
static std::string typeToString(Type t) {
699699
switch (t) {
@@ -712,6 +712,8 @@ class TemplateToken {
712712
case Type::EndMacro: return "endmacro";
713713
case Type::Filter: return "filter";
714714
case Type::EndFilter: return "endfilter";
715+
case Type::Generation: return "generation";
716+
case Type::EndGeneration: return "endgeneration";
715717
}
716718
return "Unknown";
717719
}
@@ -788,6 +790,14 @@ struct EndForTemplateToken : public TemplateToken {
788790
EndForTemplateToken(const Location & location, SpaceHandling pre, SpaceHandling post) : TemplateToken(Type::EndFor, location, pre, post) {}
789791
};
790792

793+
struct GenerationTemplateToken : public TemplateToken {
794+
GenerationTemplateToken(const Location & location, SpaceHandling pre, SpaceHandling post) : TemplateToken(Type::Generation, location, pre, post) {}
795+
};
796+
797+
struct EndGenerationTemplateToken : public TemplateToken {
798+
EndGenerationTemplateToken(const Location & location, SpaceHandling pre, SpaceHandling post) : TemplateToken(Type::EndGeneration, location, pre, post) {}
799+
};
800+
791801
struct SetTemplateToken : public TemplateToken {
792802
std::string ns;
793803
std::vector<std::string> var_names;
@@ -2149,7 +2159,7 @@ class Parser {
21492159
static std::regex comment_tok(R"(\{#([-~]?)(.*?)([-~]?)#\})");
21502160
static std::regex expr_open_regex(R"(\{\{([-~])?)");
21512161
static std::regex block_open_regex(R"(^\{%([-~])?[\s\n\r]*)");
2152-
static std::regex block_keyword_tok(R"((if|else|elif|endif|for|endfor|set|endset|block|endblock|macro|endmacro|filter|endfilter)\b)");
2162+
static std::regex block_keyword_tok(R"((if|else|elif|endif|for|endfor|generation|endgeneration|set|endset|block|endblock|macro|endmacro|filter|endfilter)\b)");
21532163
static std::regex non_text_open_regex(R"(\{\{|\{%|\{#)");
21542164
static std::regex expr_close_regex(R"([\s\n\r]*([-~])?\}\})");
21552165
static std::regex block_close_regex(R"([\s\n\r]*([-~])?%\})");
@@ -2229,6 +2239,12 @@ class Parser {
22292239
} else if (keyword == "endfor") {
22302240
auto post_space = parseBlockClose();
22312241
tokens.push_back(std::make_unique<EndForTemplateToken>(location, pre_space, post_space));
2242+
} else if (keyword == "generation") {
2243+
auto post_space = parseBlockClose();
2244+
tokens.push_back(std::make_unique<GenerationTemplateToken>(location, pre_space, post_space));
2245+
} else if (keyword == "endgeneration") {
2246+
auto post_space = parseBlockClose();
2247+
tokens.push_back(std::make_unique<EndGenerationTemplateToken>(location, pre_space, post_space));
22322248
} else if (keyword == "set") {
22332249
static std::regex namespaced_var_regex(R"((\w+)[\s\n\r]*\.[\s\n\r]*(\w+))");
22342250

@@ -2330,6 +2346,13 @@ class Parser {
23302346
throw unterminated(**start);
23312347
}
23322348
children.emplace_back(std::make_shared<ForNode>(token->location, std::move(for_token->var_names), std::move(for_token->iterable), std::move(for_token->condition), std::move(body), for_token->recursive, std::move(else_body)));
2349+
} else if (dynamic_cast<GenerationTemplateToken*>(token.get())) {
2350+
auto body = parseTemplate(begin, it, end);
2351+
if (it == end || (*(it++))->type != TemplateToken::Type::EndGeneration) {
2352+
throw unterminated(**start);
2353+
}
2354+
// Treat as a no-op, as our scope is templates for inference, not training (`{% generation %}` wraps generated tokens for masking).
2355+
children.emplace_back(std::move(body));
23332356
} else if (auto text_token = dynamic_cast<TextTemplateToken*>(token.get())) {
23342357
SpaceHandling pre_space = (it - 1) != begin ? (*(it - 2))->post_space : SpaceHandling::Keep;
23352358
SpaceHandling post_space = it != end ? (*it)->pre_space : SpaceHandling::Keep;
@@ -2397,6 +2420,7 @@ class Parser {
23972420
|| dynamic_cast<EndFilterTemplateToken*>(token.get())
23982421
|| dynamic_cast<EndIfTemplateToken*>(token.get())
23992422
|| dynamic_cast<ElseTemplateToken*>(token.get())
2423+
|| dynamic_cast<EndGenerationTemplateToken*>(token.get())
24002424
|| dynamic_cast<ElifTemplateToken*>(token.get())) {
24012425
it--; // unconsume the token
24022426
break; // exit the loop

examples/main/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,9 @@ These options help improve the performance and memory usage of the LLaMA models.
310310

311311
### Batch Size
312312

313-
- `-b N, --batch-size N`: Set the batch size for prompt processing (default: `2048`). This large batch size benefits users who have BLAS installed and enabled it during the build. If you don't have BLAS enabled ("BLAS=0"), you can use a smaller number, such as 8, to see the prompt progress as it's evaluated in some situations.
313+
- `-ub N`, `--ubatch-size N`: Physical batch size. This is the maximum number of tokens that may be processed at a time. Increasing this value may improve performance during prompt processing, at the expense of higher memory usage. Default: `512`.
314314

315-
- `-ub N`, `--ubatch-size N`: physical maximum batch size. This is for pipeline parallelization. Default: `512`.
315+
- `-b N`, `--batch-size N`: Logical batch size. Increasing this value above the value of the physical batch size may improve prompt processing performance when using multiple GPUs with pipeline parallelism. Default: `2048`.
316316

317317
### Prompt Caching
318318

examples/run/run.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ class Opt {
147147
if (handle_option_with_value(argc, argv, i, context_size) == 1) {
148148
return 1;
149149
}
150-
} else if (options_parsing && (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--ngl") == 0)) {
150+
} else if (options_parsing &&
151+
(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "-ngl") == 0 || strcmp(argv[i], "--ngl") == 0)) {
151152
if (handle_option_with_value(argc, argv, i, ngl) == 1) {
152153
return 1;
153154
}
@@ -194,7 +195,7 @@ class Opt {
194195
"Options:\n"
195196
" -c, --context-size <value>\n"
196197
" Context size (default: %d)\n"
197-
" -n, --ngl <value>\n"
198+
" -n, -ngl, --ngl <value>\n"
198199
" Number of GPU layers (default: %d)\n"
199200
" --temp <value>\n"
200201
" Temperature (default: %.1f)\n"
@@ -634,20 +635,20 @@ class LlamaData {
634635
return path.substr(pos + 1);
635636
}
636637

637-
int remove_proto(std::string & model_) {
638-
const std::string::size_type pos = model_.find("://");
638+
int rm_until_substring(std::string & model_, const std::string & substring) {
639+
const std::string::size_type pos = model_.find(substring);
639640
if (pos == std::string::npos) {
640641
return 1;
641642
}
642643

643-
model_ = model_.substr(pos + 3); // Skip past "://"
644+
model_ = model_.substr(pos + substring.size()); // Skip past the substring
644645
return 0;
645646
}
646647

647648
int resolve_model(std::string & model_) {
648649
int ret = 0;
649650
if (string_starts_with(model_, "file://") || std::filesystem::exists(model_)) {
650-
remove_proto(model_);
651+
rm_until_substring(model_, "://");
651652

652653
return ret;
653654
}
@@ -656,13 +657,16 @@ class LlamaData {
656657
const std::vector<std::string> headers = { "--header",
657658
"Accept: application/vnd.docker.distribution.manifest.v2+json" };
658659
if (string_starts_with(model_, "hf://") || string_starts_with(model_, "huggingface://")) {
659-
remove_proto(model_);
660+
rm_until_substring(model_, "://");
661+
ret = huggingface_dl(model_, headers, bn);
662+
} else if (string_starts_with(model_, "hf.co/")) {
663+
rm_until_substring(model_, "hf.co/");
660664
ret = huggingface_dl(model_, headers, bn);
661665
} else if (string_starts_with(model_, "ollama://")) {
662-
remove_proto(model_);
666+
rm_until_substring(model_, "://");
663667
ret = ollama_dl(model_, headers, bn);
664668
} else if (string_starts_with(model_, "https://")) {
665-
download(model_, headers, bn, true);
669+
ret = download(model_, headers, bn, true);
666670
} else {
667671
ret = ollama_dl(model_, headers, bn);
668672
}

examples/server/server.cpp

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,6 +1433,10 @@ struct server_queue {
14331433
} else {
14341434
queue_tasks.push_back(std::move(task));
14351435
}
1436+
// if this is cancel task make sure to clean up pending tasks
1437+
if (task.type == SERVER_TASK_TYPE_CANCEL) {
1438+
cleanup_pending_task(task.id_target);
1439+
}
14361440
condition_tasks.notify_one();
14371441
return task.id;
14381442
}
@@ -1450,6 +1454,10 @@ struct server_queue {
14501454
} else {
14511455
queue_tasks.push_back(std::move(task));
14521456
}
1457+
// if this is cancel task make sure to clean up pending tasks
1458+
if (task.type == SERVER_TASK_TYPE_CANCEL) {
1459+
cleanup_pending_task(task.id_target);
1460+
}
14531461
}
14541462
condition_tasks.notify_one();
14551463
return 0;
@@ -1544,6 +1552,20 @@ struct server_queue {
15441552
}
15451553
}
15461554
}
1555+
1556+
private:
1557+
void cleanup_pending_task(int id_task) {
1558+
// no need lock because this is called exclusively by post()
1559+
auto rm_func = [id_task](const server_task & task) {
1560+
return task.id_target == id_task;
1561+
};
1562+
queue_tasks.erase(
1563+
std::remove_if(queue_tasks.begin(), queue_tasks.end(), rm_func),
1564+
queue_tasks.end());
1565+
queue_tasks_deferred.erase(
1566+
std::remove_if(queue_tasks_deferred.begin(), queue_tasks_deferred.end(), rm_func),
1567+
queue_tasks_deferred.end());
1568+
}
15471569
};
15481570

15491571
struct server_response {
@@ -1579,6 +1601,12 @@ struct server_response {
15791601

15801602
std::unique_lock<std::mutex> lock(mutex_results);
15811603
waiting_task_ids.erase(id_task);
1604+
// make sure to clean up all pending results
1605+
queue_results.erase(
1606+
std::remove_if(queue_results.begin(), queue_results.end(), [id_task](const server_task_result_ptr & res) {
1607+
return res->id == id_task;
1608+
}),
1609+
queue_results.end());
15821610
}
15831611

15841612
void remove_waiting_task_ids(const std::unordered_set<int> & id_tasks) {
@@ -1598,7 +1626,7 @@ struct server_response {
15981626
return !queue_results.empty();
15991627
});
16001628

1601-
for (int i = 0; i < (int) queue_results.size(); i++) {
1629+
for (size_t i = 0; i < queue_results.size(); i++) {
16021630
if (id_tasks.find(queue_results[i]->id) != id_tasks.end()) {
16031631
server_task_result_ptr res = std::move(queue_results[i]);
16041632
queue_results.erase(queue_results.begin() + i);
@@ -1615,12 +1643,6 @@ struct server_response {
16151643
server_task_result_ptr recv_with_timeout(const std::unordered_set<int> & id_tasks, int timeout) {
16161644
while (true) {
16171645
std::unique_lock<std::mutex> lock(mutex_results);
1618-
bool cr_res = condition_results.wait_for(lock, std::chrono::seconds(timeout), [&]{
1619-
return !queue_results.empty();
1620-
});
1621-
if (!cr_res) {
1622-
return nullptr;
1623-
}
16241646

16251647
for (int i = 0; i < (int) queue_results.size(); i++) {
16261648
if (id_tasks.find(queue_results[i]->id) != id_tasks.end()) {
@@ -1629,6 +1651,11 @@ struct server_response {
16291651
return res;
16301652
}
16311653
}
1654+
1655+
std::cv_status cr_res = condition_results.wait_for(lock, std::chrono::seconds(timeout));
1656+
if (cr_res == std::cv_status::timeout) {
1657+
return nullptr;
1658+
}
16321659
}
16331660

16341661
// should never reach here
@@ -1772,6 +1799,9 @@ struct server_context {
17721799
// force F16 KV cache for the draft model for extra performance
17731800
cparams_dft.type_k = GGML_TYPE_F16;
17741801
cparams_dft.type_v = GGML_TYPE_F16;
1802+
1803+
// the context is not needed - we will create one for each slot
1804+
llama_init_dft.context.reset();
17751805
}
17761806

17771807
chat_templates = common_chat_templates_from_model(model, params_base.chat_template);
@@ -2373,8 +2403,8 @@ struct server_context {
23732403

23742404
server_task task(SERVER_TASK_TYPE_CANCEL);
23752405
task.id_target = id_task;
2376-
cancel_tasks.push_back(task);
23772406
queue_results.remove_waiting_task_id(id_task);
2407+
cancel_tasks.push_back(task);
23782408
}
23792409
// push to beginning of the queue, so it has highest priority
23802410
queue_tasks.post(cancel_tasks, true);

0 commit comments

Comments
 (0)