()
| 740 | num_workers = min(8, multiprocessing.cpu_count()) |
| 741 | |
| 742 | with ThreadPoolExecutor(max_workers=num_workers) as executor: |
| 743 | # Submit all conversion tasks |
| 744 | future_to_key = {executor.submit(convert_key, key): key for key in keys_list} |
| 745 | |
| 746 | # Process results as they complete with progress bar |
| 747 | for future in tqdm(as_completed(future_to_key), total=len(keys_list), desc="Converting keys (parallel)"): |
| 748 | original_key = future_to_key[future] |
| 749 | new_key = future.result() |
| 750 | converted_weights[new_key] = merged_weights[original_key] |
| 751 | else: |
| 752 | # For smaller models, use simple loop with less overhead |
| 753 | for key in tqdm(keys_list, desc="Converting keys"): |
| 754 | new_key = convert_key(key) |
| 755 | converted_weights[new_key] = merged_weights[key] |
| 756 | else: |
| 757 | converted_weights = merged_weights |
| 758 | |
| 759 | # Apply LoRA AFTER key conversion to ensure proper key matching |
| 760 | if args.lora_path is not None: |
| 761 | # Handle alpha list - if single alpha, replicate for all LoRAs |
| 762 | if args.lora_alpha is not None: |
| 763 | if len(args.lora_alpha) == 1 and len(args.lora_path) > 1: |
| 764 | args.lora_alpha = args.lora_alpha * len(args.lora_path) |
| 765 | elif len(args.lora_alpha) != len(args.lora_path): |
| 766 | raise ValueError(f"Number of lora_alpha ({len(args.lora_alpha)}) must match number of lora_path ({len(args.lora_path)}) or be 1") |
| 767 | |
| 768 | # Normalize strength list |
| 769 | if args.lora_strength is not None: |
| 770 | if len(args.lora_strength) == 1 and len(args.lora_path) > 1: |
| 771 | args.lora_strength = args.lora_strength * len(args.lora_path) |
| 772 | elif len(args.lora_strength) != len(args.lora_path): |
| 773 | raise ValueError(f"Number of strength ({len(args.lora_strength)}) must match number of lora_path ({len(args.lora_path)}) or be 1") |
| 774 | |
| 775 | # Determine if we should apply key mapping rules to LoRA keys |
| 776 | key_mapping_rules = None |
| 777 | if args.lora_key_convert == "convert" and args.direction is not None: |
| 778 | # Apply same conversion as model |
| 779 | key_mapping_rules = get_key_mapping_rules(args.direction, args.model_type) |
| 780 | logger.info("Applying key conversion to LoRA weights") |
| 781 | elif args.lora_key_convert == "same": |
| 782 | # Don't convert LoRA keys |
| 783 | logger.info("Using original LoRA keys without conversion") |
| 784 | else: # auto |
| 785 | # Auto-detect: if model was converted, try with conversion first |
| 786 | if args.direction is not None: |
| 787 | key_mapping_rules = get_key_mapping_rules(args.direction, args.model_type) |
| 788 | logger.info("Auto mode: will try with key conversion first") |
| 789 | |
| 790 | for idx, path in enumerate(args.lora_path): |
| 791 | # Pass key mapping rules to handle converted keys properly |
| 792 | strength = args.lora_strength[idx] if args.lora_strength is not None else 1.0 |
| 793 | alpha = args.lora_alpha[idx] if args.lora_alpha is not None else None |
| 794 | strict_lora = args.model_type == "h3" |
| 795 | load_loras( |
| 796 | path, |
| 797 | converted_weights, |
| 798 | alpha, |
| 799 | key_mapping_rules, |
no test coverage detected