convert-model.yml 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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: ''
  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. architecture:
  36. description: '模型架构类型 (可选, 例如: bs_roformer, mel_band_roformer)'
  37. required: false
  38. type: string
  39. env:
  40. SUPPORTED_QUANT_TYPES: 'fp32,fp16,q8_0,q4_0,q4_1,q5_0,q5_1'
  41. jobs:
  42. convert-to-all-quant-types:
  43. runs-on: ubuntu-latest
  44. steps:
  45. - name: Checkout
  46. uses: actions/checkout@v4
  47. - name: Setup Python
  48. uses: actions/setup-python@v5
  49. with:
  50. python-version: '3.11'
  51. - name: Install Dependencies
  52. run: |
  53. pip install torch --index-url https://download.pytorch.org/whl/cpu
  54. pip install huggingface_hub gguf librosa einops pyyaml numpy
  55. - name: Download Model from HuggingFace
  56. env:
  57. HF_TOKEN: ${{ secrets.HF_TOKEN }}
  58. run: |
  59. python -c "
  60. from huggingface_hub import hf_hub_download
  61. import os
  62. token = os.environ.get('HF_TOKEN') or None
  63. repo = '${{ inputs.hf_repo }}'
  64. print(f'Downloading from {repo}...')
  65. # Download checkpoint
  66. ckpt_path = hf_hub_download(
  67. repo,
  68. '${{ inputs.checkpoint_path }}',
  69. local_dir='./model',
  70. token=token
  71. )
  72. print(f' Checkpoint: {ckpt_path}')
  73. # Download config
  74. config_path = hf_hub_download(
  75. repo,
  76. '${{ inputs.config_path }}',
  77. local_dir='./model',
  78. token=token
  79. )
  80. print(f' Config: {config_path}')
  81. "
  82. - name: Show Model Info
  83. run: |
  84. echo "=== Model Configuration ==="
  85. cat model/${{ inputs.config_path }}
  86. echo ""
  87. echo "=== Checkpoint File Size ==="
  88. ls -lh model/${{ inputs.checkpoint_path }}
  89. - name: Create Output Directory
  90. run: mkdir -p output
  91. - name: Convert to All Quantization Types
  92. run: |
  93. #!/bin/bash
  94. set -e
  95. CHECKPOINT="model/${{ inputs.checkpoint_path }}"
  96. CONFIG="model/${{ inputs.config_path }}"
  97. MODEL_NAME="${{ inputs.model_name }}"
  98. GGUF_NAME="${{ inputs.gguf_name }}"
  99. GGUF_DESC="${{ inputs.gguf_description }}"
  100. QUANT_TYPES="${{ inputs.quantization_types }}"
  101. ARCH="${{ inputs.architecture }}"
  102. # If no types specified, use all supported types
  103. if [ -z "$QUANT_TYPES" ]; then
  104. QUANT_TYPES="${{ env.SUPPORTED_QUANT_TYPES }}"
  105. fi
  106. echo "=== Converting Model: $MODEL_NAME ==="
  107. echo "Checkpoint: $CHECKPOINT"
  108. echo "Config: $CONFIG"
  109. echo "Quantization Types: $QUANT_TYPES"
  110. echo ""
  111. # Convert comma-separated to array
  112. IFS=',' read -ra TYPES <<< "$QUANT_TYPES"
  113. for qtype in "${TYPES[@]}"; do
  114. # Trim whitespace
  115. qtype=$(echo "$qtype" | xargs)
  116. # Generate output filename following GGUF naming convention
  117. # Format: {model_name}-{quantization}.gguf
  118. OUTPUT_FILE="output/${MODEL_NAME}-${qtype^^}.gguf"
  119. echo ">>> Converting to $qtype -> $OUTPUT_FILE"
  120. # Build convert command with optional metadata args
  121. CMD="python scripts/convert_to_gguf.py --ckpt \"$CHECKPOINT\" --config \"$CONFIG\" --out \"$OUTPUT_FILE\" --dtype \"$qtype\""
  122. [ -n "$GGUF_NAME" ] && CMD="$CMD --name \"$GGUF_NAME\""
  123. [ -n "$GGUF_DESC" ] && CMD="$CMD --description \"$GGUF_DESC\""
  124. [ -n "$ARCH" ] && CMD="$CMD --arch \"$ARCH\""
  125. eval $CMD
  126. # Show file size
  127. SIZE=$(ls -lh "$OUTPUT_FILE" | awk '{print $5}')
  128. echo " Output size: $SIZE"
  129. echo ""
  130. done
  131. echo "=== Conversion Complete ==="
  132. ls -lh output/
  133. - name: Generate Summary Report
  134. run: |
  135. python -c "
  136. import os
  137. import json
  138. output_dir = 'output'
  139. model_name = '${{ inputs.model_name }}'
  140. report = {
  141. 'model_name': model_name,
  142. 'hf_repo': '${{ inputs.hf_repo }}',
  143. 'checkpoint': '${{ inputs.checkpoint_path }}',
  144. 'config': '${{ inputs.config_path }}',
  145. 'files': []
  146. }
  147. total_size = 0
  148. for f in sorted(os.listdir(output_dir)):
  149. if f.endswith('.gguf'):
  150. path = os.path.join(output_dir, f)
  151. size_bytes = os.path.getsize(path)
  152. total_size += size_bytes
  153. # Extract quant type from filename
  154. quant_type = f.replace(f'{model_name}-', '').replace('.gguf', '')
  155. report['files'].append({
  156. 'filename': f,
  157. 'quant_type': quant_type,
  158. 'size_bytes': size_bytes,
  159. 'size_mb': round(size_bytes / 1024 / 1024, 2)
  160. })
  161. report['total_size_bytes'] = total_size
  162. report['total_size_mb'] = round(total_size / 1024 / 1024, 2)
  163. # Write JSON report
  164. with open('output/conversion_report.json', 'w') as f:
  165. json.dump(report, f, indent=2)
  166. # Print markdown table for GitHub Actions summary
  167. print('## Conversion Report')
  168. print('')
  169. print(f'**Model**: {model_name}')
  170. print(f'**Source**: [{report[\"hf_repo\"]}](https://huggingface.co/{report[\"hf_repo\"]})')
  171. print('')
  172. print('| Quantization | Filename | Size |')
  173. print('|--------------|----------|------|')
  174. for f in report['files']:
  175. print(f'| {f[\"quant_type\"]} | {f[\"filename\"]} | {f[\"size_mb\"]} MB |')
  176. print('')
  177. print(f'**Total Size**: {report[\"total_size_mb\"]} MB')
  178. " | tee -a $GITHUB_STEP_SUMMARY
  179. - name: Upload Converted Models
  180. uses: actions/upload-artifact@v4
  181. with:
  182. name: gguf-models-${{ inputs.model_name }}
  183. path: |
  184. output/*.gguf
  185. output/conversion_report.json
  186. retention-days: 30
  187. compression-level: 0 # GGUF is already compressed for quantized types