| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- // Command convert converts HuggingFace models (safetensors) to .mak format
- //
- // Pure Go implementation - no Python dependencies!
- //
- // Usage:
- //
- // convert /path/to/model output.mak
- // convert /path/to/model output.mak --quant q4_k
- // convert /path/to/model output.mak --quant q4_k --mix
- package main
- import (
- "flag"
- "fmt"
- "os"
- "strings"
- "makarna/pkg/convert"
- _ "makarna/pkg/model/models"
- "makarna/pkg/quant"
- )
- func main() {
- fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
- quantType := fs.String("quant", "", "Quantization type: q2_k, q3_k, q4_k, q5_k, q6_k, q8_k (empty = F32)")
- mixMode := fs.Bool("mix", false, "Enable smart mix quantization")
- workers := fs.Int("workers", 0, "Number of parallel workers for conversion (0 = GOMAXPROCS)")
- maxInFlightMB := fs.Int("max-inflight-mb", 0, "Max in-flight tensor memory (decoded+output) in MB (0 = auto)")
- // Go's standard flag package stops parsing at the first non-flag argument.
- // Users often pass: convert <model_dir> <out.mak> --quant q4_k --mix
- // Pre-scan to allow flags to appear anywhere.
- flagArgs, posArgs := splitFlagsAndPositionals(os.Args[1:])
- _ = fs.Parse(flagArgs)
- args := posArgs
- if len(args) < 2 {
- fmt.Println("Usage: convert <model_dir> <output.mak> [--quant TYPE] [--mix]")
- os.Exit(1)
- }
- modelPath := args[0]
- outputPath := args[1]
- var baseQuant quant.QuantType
- if *quantType != "" {
- baseQuant = quant.QuantType(*quantType)
- switch baseQuant {
- case quant.TypeQ2K, quant.TypeQ3K, quant.TypeQ4K, quant.TypeQ5K, quant.TypeQ6K, quant.TypeQ8K:
- // OK
- default:
- fmt.Printf("Unknown quant type: %s\n", *quantType)
- os.Exit(1)
- }
- }
- fmt.Printf("convert: model=%s out=%s quant=%s mix=%v workers=%d max_inflight_mb=%d\n", modelPath, outputPath, baseQuant, *mixMode, *workers, *maxInFlightMB)
- opts := convert.Options{
- BaseQuant: baseQuant,
- MixMode: *mixMode,
- Workers: *workers,
- MaxInFlightBytes: uint64(*maxInFlightMB) * 1024 * 1024,
- }
- if err := convert.ConvertDirectory(modelPath, outputPath, opts); err != nil {
- fmt.Printf("convert failed: %v\n", err)
- os.Exit(1)
- }
- }
- func splitFlagsAndPositionals(argv []string) (flagArgs []string, posArgs []string) {
- // Known flags for this command. Values indicate whether the flag expects a separate value.
- expectsValue := map[string]bool{
- "--quant": true,
- "-quant": true,
- "--workers": true,
- "-workers": true,
- "--max-inflight-mb": true,
- "-max-inflight-mb": true,
- "--mix": false,
- "-mix": false,
- }
- for i := 0; i < len(argv); i++ {
- a := argv[i]
- if !strings.HasPrefix(a, "-") {
- posArgs = append(posArgs, a)
- continue
- }
- // Support --flag=value form.
- if strings.Contains(a, "=") {
- flagArgs = append(flagArgs, a)
- continue
- }
- flagArgs = append(flagArgs, a)
- if expectsValue[a] {
- if i+1 < len(argv) && !strings.HasPrefix(argv[i+1], "-") {
- flagArgs = append(flagArgs, argv[i+1])
- i++
- }
- }
- }
- return flagArgs, posArgs
- }
|