convert-model.yml 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. name: Convert Model to GGUF
  2. on:
  3. workflow_dispatch:
  4. inputs:
  5. hf_repo:
  6. description: 'HuggingFace 仓库名称 (例如: GaboxR67/MelBandRoformers)'
  7. required: true
  8. type: string
  9. checkpoint_path:
  10. description: '权重文件路径 (相对于仓库, 例如: melbandroformers/vocals/voc_fv6.ckpt)'
  11. required: true
  12. type: string
  13. config_path:
  14. description: '配置文件路径 (相对于仓库, 例如: melbandroformers/vocals/voc_gabox.yaml)'
  15. required: true
  16. type: string
  17. model_name:
  18. description: '输出模型名称 (用于文件命名, 例如: voc_fv6)'
  19. required: false
  20. type: string
  21. default: 'MelBandRoformer-'
  22. quantization_types:
  23. description: '要转换的量化类型 (用逗号分隔, 留空则转换全部)'
  24. required: false
  25. type: string
  26. default: 'fp32,fp16,q8_0,q4_0,q4_1,q5_0,q5_1'
  27. gguf_name:
  28. description: 'GGUF 元数据中的模型名称 (可选, 默认: Mel-Band-Roformer Separator)'
  29. required: false
  30. type: string
  31. gguf_description:
  32. description: 'GGUF 元数据中的模型描述 (可选, 默认: Music source separation model)'
  33. required: false
  34. type: string
  35. env:
  36. SUPPORTED_QUANT_TYPES: 'fp32,fp16,q8_0,q4_0,q4_1,q5_0,q5_1'
  37. jobs:
  38. convert-to-all-quant-types:
  39. runs-on: ubuntu-latest
  40. steps:
  41. - name: Checkout
  42. uses: actions/checkout@v4
  43. - name: Setup Python
  44. uses: actions/setup-python@v5
  45. with:
  46. python-version: '3.11'
  47. - name: Install Dependencies
  48. run: |
  49. pip install torch --index-url https://download.pytorch.org/whl/cpu
  50. pip install huggingface_hub gguf librosa einops pyyaml numpy
  51. - name: Download Model from HuggingFace
  52. env:
  53. HF_TOKEN: ${{ secrets.HF_TOKEN }}
  54. run: |
  55. python -c "
  56. from huggingface_hub import hf_hub_download
  57. import os
  58. token = os.environ.get('HF_TOKEN') or None
  59. repo = '${{ inputs.hf_repo }}'
  60. print(f'Downloading from {repo}...')
  61. # Download checkpoint
  62. ckpt_path = hf_hub_download(
  63. repo,
  64. '${{ inputs.checkpoint_path }}',
  65. local_dir='./model',
  66. token=token
  67. )
  68. print(f' Checkpoint: {ckpt_path}')
  69. # Download config
  70. config_path = hf_hub_download(
  71. repo,
  72. '${{ inputs.config_path }}',
  73. local_dir='./model',
  74. token=token
  75. )
  76. print(f' Config: {config_path}')
  77. "
  78. - name: Show Model Info
  79. run: |
  80. echo "=== Model Configuration ==="
  81. cat model/${{ inputs.config_path }}
  82. echo ""
  83. echo "=== Checkpoint File Size ==="
  84. ls -lh model/${{ inputs.checkpoint_path }}
  85. - name: Create Output Directory
  86. run: mkdir -p output
  87. - name: Convert to All Quantization Types
  88. run: |
  89. #!/bin/bash
  90. set -e
  91. CHECKPOINT="model/${{ inputs.checkpoint_path }}"
  92. CONFIG="model/${{ inputs.config_path }}"
  93. MODEL_NAME="${{ inputs.model_name }}"
  94. GGUF_NAME="${{ inputs.gguf_name }}"
  95. GGUF_DESC="${{ inputs.gguf_description }}"
  96. QUANT_TYPES="${{ inputs.quantization_types }}"
  97. # If no types specified, use all supported types
  98. if [ -z "$QUANT_TYPES" ]; then
  99. QUANT_TYPES="${{ env.SUPPORTED_QUANT_TYPES }}"
  100. fi
  101. echo "=== Converting Model: $MODEL_NAME ==="
  102. echo "Checkpoint: $CHECKPOINT"
  103. echo "Config: $CONFIG"
  104. echo "Quantization Types: $QUANT_TYPES"
  105. echo ""
  106. # Convert comma-separated to array
  107. IFS=',' read -ra TYPES <<< "$QUANT_TYPES"
  108. for qtype in "${TYPES[@]}"; do
  109. # Trim whitespace
  110. qtype=$(echo "$qtype" | xargs)
  111. # Generate output filename following GGUF naming convention
  112. # Format: {model_name}-{quantization}.gguf
  113. OUTPUT_FILE="output/${MODEL_NAME}-${qtype^^}.gguf"
  114. echo ">>> Converting to $qtype -> $OUTPUT_FILE"
  115. # Build convert command with optional metadata args
  116. CMD="python scripts/convert_to_gguf.py --ckpt \"$CHECKPOINT\" --config \"$CONFIG\" --out \"$OUTPUT_FILE\" --dtype \"$qtype\""
  117. [ -n "$GGUF_NAME" ] && CMD="$CMD --name \"$GGUF_NAME\""
  118. [ -n "$GGUF_DESC" ] && CMD="$CMD --description \"$GGUF_DESC\""
  119. eval $CMD
  120. # Show file size
  121. SIZE=$(ls -lh "$OUTPUT_FILE" | awk '{print $5}')
  122. echo " Output size: $SIZE"
  123. echo ""
  124. done
  125. echo "=== Conversion Complete ==="
  126. ls -lh output/
  127. - name: Generate Summary Report
  128. run: |
  129. python -c "
  130. import os
  131. import json
  132. output_dir = 'output'
  133. model_name = '${{ inputs.model_name }}'
  134. report = {
  135. 'model_name': model_name,
  136. 'hf_repo': '${{ inputs.hf_repo }}',
  137. 'checkpoint': '${{ inputs.checkpoint_path }}',
  138. 'config': '${{ inputs.config_path }}',
  139. 'files': []
  140. }
  141. total_size = 0
  142. for f in sorted(os.listdir(output_dir)):
  143. if f.endswith('.gguf'):
  144. path = os.path.join(output_dir, f)
  145. size_bytes = os.path.getsize(path)
  146. total_size += size_bytes
  147. # Extract quant type from filename
  148. quant_type = f.replace(f'{model_name}-', '').replace('.gguf', '')
  149. report['files'].append({
  150. 'filename': f,
  151. 'quant_type': quant_type,
  152. 'size_bytes': size_bytes,
  153. 'size_mb': round(size_bytes / 1024 / 1024, 2)
  154. })
  155. report['total_size_bytes'] = total_size
  156. report['total_size_mb'] = round(total_size / 1024 / 1024, 2)
  157. # Write JSON report
  158. with open('output/conversion_report.json', 'w') as f:
  159. json.dump(report, f, indent=2)
  160. # Print markdown table for GitHub Actions summary
  161. print('## Conversion Report')
  162. print('')
  163. print(f'**Model**: {model_name}')
  164. print(f'**Source**: [{report[\"hf_repo\"]}](https://huggingface.co/{report[\"hf_repo\"]})')
  165. print('')
  166. print('| Quantization | Filename | Size |')
  167. print('|--------------|----------|------|')
  168. for f in report['files']:
  169. print(f'| {f[\"quant_type\"]} | {f[\"filename\"]} | {f[\"size_mb\"]} MB |')
  170. print('')
  171. print(f'**Total Size**: {report[\"total_size_mb\"]} MB')
  172. " | tee -a $GITHUB_STEP_SUMMARY
  173. - name: Upload Converted Models
  174. uses: actions/upload-artifact@v4
  175. with:
  176. name: gguf-models-${{ inputs.model_name }}
  177. path: |
  178. output/*.gguf
  179. output/conversion_report.json
  180. retention-days: 30
  181. compression-level: 0 # GGUF is already compressed for quantized types