Skip to content

Commit 487674f

Browse files
ServeurpersoComngxsonpersonalmountains
authored
common: fix --override-kv to support comma-separated values (#18056)
* common: fix --override-kv to support comma-separated values * Update common/arg.cpp Co-authored-by: Xuan-Son Nguyen <thichthat@gmail.com> * common: deprecate repeated arguments, suggest comma-separated values * common: add comma escape support for --override-kv * common: optimize duplicate detection with insert().second Co-authored-by: personalmountains <46615898+personalmountains@users.noreply.github.com> * common: migrate all repeated args to comma-separated syntax --------- Co-authored-by: Xuan-Son Nguyen <thichthat@gmail.com> Co-authored-by: personalmountains <46615898+personalmountains@users.noreply.github.com>
1 parent acec774 commit 487674f

File tree

1 file changed

+89
-29
lines changed

1 file changed

+89
-29
lines changed

common/arg.cpp

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context
420420
}
421421
};
422422

423+
std::set<std::string> seen_args;
424+
423425
for (int i = 1; i < argc; i++) {
424426
const std::string arg_prefix = "--";
425427

@@ -430,6 +432,9 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context
430432
if (arg_to_options.find(arg) == arg_to_options.end()) {
431433
throw std::invalid_argument(string_format("error: invalid argument: %s", arg.c_str()));
432434
}
435+
if (!seen_args.insert(arg).second) {
436+
LOG_WRN("DEPRECATED: argument '%s' specified multiple times, use comma-separated values instead (only last value will be used)\n", arg.c_str());
437+
}
433438
auto & tmp = arg_to_options[arg];
434439
auto opt = *tmp.first;
435440
bool is_positive = tmp.second;
@@ -750,6 +755,8 @@ bool common_params_to_map(int argc, char ** argv, llama_example ex, std::map<com
750755
}
751756
};
752757

758+
std::set<std::string> seen_args;
759+
753760
for (int i = 1; i < argc; i++) {
754761
const std::string arg_prefix = "--";
755762

@@ -760,6 +767,9 @@ bool common_params_to_map(int argc, char ** argv, llama_example ex, std::map<com
760767
if (arg_to_options.find(arg) == arg_to_options.end()) {
761768
throw std::invalid_argument(string_format("error: invalid argument: %s", arg.c_str()));
762769
}
770+
if (!seen_args.insert(arg).second) {
771+
LOG_WRN("DEPRECATED: argument '%s' specified multiple times, use comma-separated values instead (only last value will be used)\n", arg.c_str());
772+
}
763773
auto opt = *arg_to_options[arg];
764774
std::string val;
765775
if (opt.value_hint != nullptr) {
@@ -1226,13 +1236,15 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
12261236
).set_examples({LLAMA_EXAMPLE_COMPLETION, LLAMA_EXAMPLE_CLI, LLAMA_EXAMPLE_DIFFUSION}));
12271237
add_opt(common_arg(
12281238
{"--in-file"}, "FNAME",
1229-
"an input file (repeat to specify multiple files)",
1239+
"an input file (use comma-separated values to specify multiple files)",
12301240
[](common_params & params, const std::string & value) {
1231-
std::ifstream file(value);
1232-
if (!file) {
1233-
throw std::runtime_error(string_format("error: failed to open file '%s'\n", value.c_str()));
1241+
for (const auto & item : string_split<std::string>(value, ',')) {
1242+
std::ifstream file(item);
1243+
if (!file) {
1244+
throw std::runtime_error(string_format("error: failed to open file '%s'\n", item.c_str()));
1245+
}
1246+
params.in_files.push_back(item);
12341247
}
1235-
params.in_files.push_back(value);
12361248
}
12371249
).set_examples({LLAMA_EXAMPLE_IMATRIX}));
12381250
add_opt(common_arg(
@@ -1969,9 +1981,11 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
19691981
).set_examples(mmproj_examples).set_env("LLAMA_ARG_MMPROJ_OFFLOAD"));
19701982
add_opt(common_arg(
19711983
{"--image", "--audio"}, "FILE",
1972-
"path to an image or audio file. use with multimodal models, can be repeated if you have multiple files\n",
1984+
"path to an image or audio file. use with multimodal models, use comma-separated values for multiple files\n",
19731985
[](common_params & params, const std::string & value) {
1974-
params.image.emplace_back(value);
1986+
for (const auto & item : string_split<std::string>(value, ',')) {
1987+
params.image.emplace_back(item);
1988+
}
19751989
}
19761990
).set_examples({LLAMA_EXAMPLE_MTMD, LLAMA_EXAMPLE_CLI}));
19771991
add_opt(common_arg(
@@ -2218,12 +2232,39 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
22182232
}
22192233
));
22202234
add_opt(common_arg(
2221-
{"--override-kv"}, "KEY=TYPE:VALUE",
2222-
"advanced option to override model metadata by key. may be specified multiple times.\n"
2223-
"types: int, float, bool, str. example: --override-kv tokenizer.ggml.add_bos_token=bool:false",
2235+
{"--override-kv"}, "KEY=TYPE:VALUE,...",
2236+
"advanced option to override model metadata by key. to specify multiple overrides, either use comma-separated or repeat this argument.\n"
2237+
"types: int, float, bool, str. example: --override-kv tokenizer.ggml.add_bos_token=bool:false,tokenizer.ggml.add_eos_token=bool:false",
22242238
[](common_params & params, const std::string & value) {
2225-
if (!string_parse_kv_override(value.c_str(), params.kv_overrides)) {
2226-
throw std::runtime_error(string_format("error: Invalid type for KV override: %s\n", value.c_str()));
2239+
std::vector<std::string> kv_overrides;
2240+
2241+
std::string current;
2242+
bool escaping = false;
2243+
2244+
for (const char c : value) {
2245+
if (escaping) {
2246+
current.push_back(c);
2247+
escaping = false;
2248+
} else if (c == '\\') {
2249+
escaping = true;
2250+
} else if (c == ',') {
2251+
kv_overrides.push_back(current);
2252+
current.clear();
2253+
} else {
2254+
current.push_back(c);
2255+
}
2256+
}
2257+
2258+
if (escaping) {
2259+
current.push_back('\\');
2260+
}
2261+
2262+
kv_overrides.push_back(current);
2263+
2264+
for (const auto & kv_override : kv_overrides) {
2265+
if (!string_parse_kv_override(kv_override.c_str(), params.kv_overrides)) {
2266+
throw std::runtime_error(string_format("error: Invalid type for KV override: %s\n", kv_override.c_str()));
2267+
}
22272268
}
22282269
}
22292270
));
@@ -2237,33 +2278,50 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
22372278
));
22382279
add_opt(common_arg(
22392280
{"--lora"}, "FNAME",
2240-
"path to LoRA adapter (can be repeated to use multiple adapters)",
2281+
"path to LoRA adapter (use comma-separated values to load multiple adapters)",
22412282
[](common_params & params, const std::string & value) {
2242-
params.lora_adapters.push_back({ std::string(value), 1.0, "", "", nullptr });
2283+
for (const auto & item : string_split<std::string>(value, ',')) {
2284+
params.lora_adapters.push_back({ item, 1.0, "", "", nullptr });
2285+
}
22432286
}
22442287
// we define this arg on both COMMON and EXPORT_LORA, so when showing help message of export-lora, it will be categorized as "example-specific" arg
22452288
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_EXPORT_LORA}));
22462289
add_opt(common_arg(
2247-
{"--lora-scaled"}, "FNAME", "SCALE",
2248-
"path to LoRA adapter with user defined scaling (can be repeated to use multiple adapters)",
2249-
[](common_params & params, const std::string & fname, const std::string & scale) {
2250-
params.lora_adapters.push_back({ fname, std::stof(scale), "", "", nullptr });
2290+
{"--lora-scaled"}, "FNAME:SCALE,...",
2291+
"path to LoRA adapter with user defined scaling (format: FNAME:SCALE,...)\n"
2292+
"note: use comma-separated values",
2293+
[](common_params & params, const std::string & value) {
2294+
for (const auto & item : string_split<std::string>(value, ',')) {
2295+
auto parts = string_split<std::string>(item, ':');
2296+
if (parts.size() != 2) {
2297+
throw std::invalid_argument("lora-scaled format: FNAME:SCALE");
2298+
}
2299+
params.lora_adapters.push_back({ parts[0], std::stof(parts[1]), "", "", nullptr });
2300+
}
22512301
}
22522302
// we define this arg on both COMMON and EXPORT_LORA, so when showing help message of export-lora, it will be categorized as "example-specific" arg
22532303
).set_examples({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_EXPORT_LORA}));
22542304
add_opt(common_arg(
22552305
{"--control-vector"}, "FNAME",
2256-
"add a control vector\nnote: this argument can be repeated to add multiple control vectors",
2306+
"add a control vector\nnote: use comma-separated values to add multiple control vectors",
22572307
[](common_params & params, const std::string & value) {
2258-
params.control_vectors.push_back({ 1.0f, value, });
2308+
for (const auto & item : string_split<std::string>(value, ',')) {
2309+
params.control_vectors.push_back({ 1.0f, item, });
2310+
}
22592311
}
22602312
));
22612313
add_opt(common_arg(
2262-
{"--control-vector-scaled"}, "FNAME", "SCALE",
2314+
{"--control-vector-scaled"}, "FNAME:SCALE,...",
22632315
"add a control vector with user defined scaling SCALE\n"
2264-
"note: this argument can be repeated to add multiple scaled control vectors",
2265-
[](common_params & params, const std::string & fname, const std::string & scale) {
2266-
params.control_vectors.push_back({ std::stof(scale), fname });
2316+
"note: use comma-separated values (format: FNAME:SCALE,...)",
2317+
[](common_params & params, const std::string & value) {
2318+
for (const auto & item : string_split<std::string>(value, ',')) {
2319+
auto parts = string_split<std::string>(item, ':');
2320+
if (parts.size() != 2) {
2321+
throw std::invalid_argument("control-vector-scaled format: FNAME:SCALE");
2322+
}
2323+
params.control_vectors.push_back({ std::stof(parts[1]), parts[0] });
2324+
}
22672325
}
22682326
));
22692327
add_opt(common_arg(
@@ -2353,13 +2411,15 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
23532411
).set_env("HF_TOKEN"));
23542412
add_opt(common_arg(
23552413
{"--context-file"}, "FNAME",
2356-
"file to load context from (repeat to specify multiple files)",
2414+
"file to load context from (use comma-separated values to specify multiple files)",
23572415
[](common_params & params, const std::string & value) {
2358-
std::ifstream file(value, std::ios::binary);
2359-
if (!file) {
2360-
throw std::runtime_error(string_format("error: failed to open file '%s'\n", value.c_str()));
2416+
for (const auto & item : string_split<std::string>(value, ',')) {
2417+
std::ifstream file(item, std::ios::binary);
2418+
if (!file) {
2419+
throw std::runtime_error(string_format("error: failed to open file '%s'\n", item.c_str()));
2420+
}
2421+
params.context_files.push_back(item);
23612422
}
2362-
params.context_files.push_back(value);
23632423
}
23642424
).set_examples({LLAMA_EXAMPLE_RETRIEVAL}));
23652425
add_opt(common_arg(

0 commit comments

Comments
 (0)