run-with-preset.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/env python3
  2. import logging
  3. import argparse
  4. import os
  5. import subprocess
  6. import sys
  7. import yaml
  8. logger = logging.getLogger("run-with-preset")
  9. CLI_ARGS_LLAMA_CLI_PERPLEXITY = [
  10. "batch-size", "cfg-negative-prompt", "cfg-scale", "chunks", "color", "ctx-size", "escape",
  11. "export", "file", "frequency-penalty", "grammar", "grammar-file", "hellaswag",
  12. "hellaswag-tasks", "ignore-eos", "in-prefix", "in-prefix-bos", "in-suffix",
  13. "interactive", "interactive-first", "keep", "logdir", "logit-bias", "lora", "lora-base",
  14. "low-vram", "main-gpu", "mirostat", "mirostat-ent", "mirostat-lr", "mlock",
  15. "model", "multiline-input", "n-gpu-layers", "n-predict", "no-mmap", "no-mul-mat-q",
  16. "np-penalize-nl", "numa", "ppl-output-type", "ppl-stride", "presence-penalty", "prompt",
  17. "prompt-cache", "prompt-cache-all", "prompt-cache-ro", "repeat-last-n",
  18. "repeat-penalty", "reverse-prompt", "rope-freq-base", "rope-freq-scale", "rope-scale", "seed",
  19. "simple-io", "tensor-split", "threads", "temp", "tfs", "top-k", "top-p", "typical",
  20. "verbose-prompt"
  21. ]
  22. CLI_ARGS_LLAMA_BENCH = [
  23. "batch-size", "low-vram", "model", "mul-mat-q", "n-gen", "n-gpu-layers",
  24. "n-prompt", "output", "repetitions", "tensor-split", "threads", "verbose"
  25. ]
  26. CLI_ARGS_LLAMA_SERVER = [
  27. "alias", "batch-size", "ctx-size", "embedding", "host", "lora", "lora-base",
  28. "low-vram", "main-gpu", "mlock", "model", "n-gpu-layers", "n-probs", "no-mmap", "no-mul-mat-q",
  29. "numa", "path", "port", "rope-freq-base", "timeout", "rope-freq-scale", "tensor-split",
  30. "threads", "verbose"
  31. ]
  32. description = """Run llama.cpp binaries with presets from YAML file(s).
  33. To specify which binary should be run, specify the "binary" property (llama-cli, llama-perplexity, llama-bench, and llama-server are supported).
  34. To get a preset file template, run a llama.cpp binary with the "--logdir" CLI argument.
  35. Formatting considerations:
  36. - The YAML property names are the same as the CLI argument names of the corresponding binary.
  37. - Properties must use the long name of their corresponding llama.cpp CLI arguments.
  38. - Like the llama.cpp binaries the property names do not differentiate between hyphens and underscores.
  39. - Flags must be defined as "<PROPERTY_NAME>: true" to be effective.
  40. - To define the logit_bias property, the expected format is "<TOKEN_ID>: <BIAS>" in the "logit_bias" namespace.
  41. - To define multiple "reverse_prompt" properties simultaneously the expected format is a list of strings.
  42. - To define a tensor split, pass a list of floats.
  43. """
  44. usage = "run-with-preset.py [-h] [yaml_files ...] [--<ARG_NAME> <ARG_VALUE> ...]"
  45. epilog = (" --<ARG_NAME> specify additional CLI ars to be passed to the binary (override all preset files). "
  46. "Unknown args will be ignored.")
  47. parser = argparse.ArgumentParser(
  48. description=description, usage=usage, epilog=epilog, formatter_class=argparse.RawTextHelpFormatter)
  49. parser.add_argument("-bin", "--binary", help="The binary to run.")
  50. parser.add_argument("yaml_files", nargs="*",
  51. help="Arbitrary number of YAML files from which to read preset values. "
  52. "If two files specify the same values the later one will be used.")
  53. parser.add_argument("--verbose", action="store_true", help="increase output verbosity")
  54. known_args, unknown_args = parser.parse_known_args()
  55. if not known_args.yaml_files and not unknown_args:
  56. parser.print_help()
  57. sys.exit(0)
  58. logging.basicConfig(level=logging.DEBUG if known_args.verbose else logging.INFO)
  59. props = dict()
  60. for yaml_file in known_args.yaml_files:
  61. with open(yaml_file, "r") as f:
  62. props.update(yaml.load(f, yaml.SafeLoader))
  63. props = {prop.replace("_", "-"): val for prop, val in props.items()}
  64. binary = props.pop("binary", "llama-cli")
  65. if known_args.binary:
  66. binary = known_args.binary
  67. if os.path.exists(f"./{binary}"):
  68. binary = f"./{binary}"
  69. if binary.lower().endswith("llama-cli") or binary.lower().endswith("llama-perplexity"):
  70. cli_args = CLI_ARGS_LLAMA_CLI_PERPLEXITY
  71. elif binary.lower().endswith("llama-bench"):
  72. cli_args = CLI_ARGS_LLAMA_BENCH
  73. elif binary.lower().endswith("llama-server"):
  74. cli_args = CLI_ARGS_LLAMA_SERVER
  75. else:
  76. logger.error(f"Unknown binary: {binary}")
  77. sys.exit(1)
  78. command_list = [binary]
  79. for cli_arg in cli_args:
  80. value = props.pop(cli_arg, None)
  81. if not value or value == -1:
  82. continue
  83. if cli_arg == "logit-bias":
  84. for token, bias in value.items():
  85. command_list.append("--logit-bias")
  86. command_list.append(f"{token}{bias:+}")
  87. continue
  88. if cli_arg == "reverse-prompt" and not isinstance(value, str):
  89. for rp in value:
  90. command_list.append("--reverse-prompt")
  91. command_list.append(str(rp))
  92. continue
  93. command_list.append(f"--{cli_arg}")
  94. if cli_arg == "tensor-split":
  95. command_list.append(",".join([str(v) for v in value]))
  96. continue
  97. value = str(value)
  98. if value != "True":
  99. command_list.append(str(value))
  100. num_unused = len(props)
  101. if num_unused > 10:
  102. logger.info(f"The preset file contained a total of {num_unused} unused properties.")
  103. elif num_unused > 0:
  104. logger.info("The preset file contained the following unused properties:")
  105. for prop, value in props.items():
  106. logger.info(f" {prop}: {value}")
  107. command_list += unknown_args
  108. sp = subprocess.Popen(command_list)
  109. while sp.returncode is None:
  110. try:
  111. sp.wait()
  112. except KeyboardInterrupt:
  113. pass
  114. sys.exit(sp.returncode)