diff --git a/frontend/src/constants/index.ts b/frontend/src/constants/index.ts index 48eb5b8..e96a8ee 100644 --- a/frontend/src/constants/index.ts +++ b/frontend/src/constants/index.ts @@ -76,6 +76,29 @@ export const LR_SCHEDULER_OPTIONS = [ { label: 'constant', value: 'constant' }, ] +/** 训练时量化位数(QLoRA) */ +export const QUANTIZATION_BIT_OPTIONS = [ + { label: '不量化', value: 0 }, + { label: '8 bit', value: 8 }, + { label: '4 bit (QLoRA)', value: 4 }, +] + +/** 训练后导出量化方法 */ +export const QUANT_METHOD_OPTIONS = [ + { label: 'bitsandbytes', value: 'bnb' }, + { label: 'GPTQ', value: 'gptq' }, + { label: 'AWQ', value: 'awq' }, + { label: 'GGUF (llama.cpp)', value: 'gguf' }, +] + +/** GGUF 量化格式 */ +export const GGUF_FORMAT_OPTIONS = [ + { label: 'Q4_K_M(推荐)', value: 'Q4_K_M' }, + { label: 'Q5_K_M', value: 'Q5_K_M' }, + { label: 'Q8_0', value: 'Q8_0' }, + { label: 'F16(不量化)', value: 'F16' }, +] + /** 训练模板分组(按模型系列) */ export const TEMPLATE_GROUPS: { label: string; options: { label: string; value: string }[] }[] = [ { diff --git a/frontend/src/views/fine-tune/FineTuneCreateView.vue b/frontend/src/views/fine-tune/FineTuneCreateView.vue index b8cae4f..1462606 100644 --- a/frontend/src/views/fine-tune/FineTuneCreateView.vue +++ b/frontend/src/views/fine-tune/FineTuneCreateView.vue @@ -13,7 +13,7 @@ import { import { getModelList } from '@/api/modules/model' import { getDatasetList } from '@/api/modules/dataset' import { getSystemInfo } from '@/api/modules/system' -import { TEMPLATE_GROUPS, LR_SCHEDULER_OPTIONS } from '@/constants' +import { TEMPLATE_GROUPS, LR_SCHEDULER_OPTIONS, QUANTIZATION_BIT_OPTIONS, QUANT_METHOD_OPTIONS, GGUF_FORMAT_OPTIONS } from '@/constants' import type { ModelItem, DatasetItem, GpuInfo } from '@/types' const router = useRouter() @@ -48,6 +48,13 @@ const form = reactive({ lora_alpha: 16, // 修复原项目 lora_alpha 默认值不一致 bug lora_dropout: 0.1, lora_rank: 8, + // 量化参数 + quantization_bit: 0, // 训练时量化(QLoRA):0=不量化 + export_quantized: false, // 训练后是否导出量化模型 + quant_method: 'bnb', // 导出量化方法 + quant_bits: 4, // 导出量化位数 + quant_group_size: 128, // 分组大小(GPTQ/AWQ) + export_format: 'Q4_K_M', // GGUF 导出格式 }) const rules: FormRules = { @@ -95,6 +102,19 @@ const commandPreview = computed(() => { cmd += ` \\\n --lora_dropout ${form.lora_dropout}` cmd += ` \\\n --lora_rank ${form.lora_rank}` } + if (showLoraParams.value && form.quantization_bit) { + cmd += ` \\\n --quantization_bit ${form.quantization_bit}` + } + if (form.export_quantized) { + const method = form.quant_method + const bits = form.quant_bits + cmd += ` \\\n # 训练后导出量化模型:${method} ${bits}bit` + if (method === 'gguf') { + cmd += ` \\\n # export_format=${form.export_format}` + } else if (method === 'gptq' || method === 'awq') { + cmd += ` \\\n # group_size=${form.quant_group_size}` + } + } return cmd }) @@ -132,6 +152,12 @@ function resetParams() { lora_alpha: 16, lora_dropout: 0.1, lora_rank: 8, + quantization_bit: 0, + export_quantized: false, + quant_method: 'bnb', + quant_bits: 4, + quant_group_size: 128, + export_format: 'Q4_K_M', }) } @@ -230,6 +256,12 @@ async function handleSubmit() { lora_alpha: form.lora_alpha, lora_dropout: form.lora_dropout, lora_rank: form.lora_rank, + quantization_bit: form.train_method === 'lora' ? form.quantization_bit : 0, + export_quantized: form.export_quantized, + quant_method: form.export_quantized ? form.quant_method : '', + quant_bits: form.export_quantized ? form.quant_bits : 0, + quant_group_size: form.export_quantized ? form.quant_group_size : 0, + export_format: form.export_quantized && form.quant_method === 'gguf' ? form.export_format : '', status: 'pending', progress: 0, } @@ -260,6 +292,12 @@ async function handleSubmit() { lora_alpha: form.lora_alpha, lora_dropout: form.lora_dropout, lora_rank: form.lora_rank, + quantization_bit: form.train_method === 'lora' ? form.quantization_bit : 0, + export_quantized: form.export_quantized, + quant_method: form.export_quantized ? form.quant_method : '', + quant_bits: form.export_quantized ? form.quant_bits : 0, + quant_group_size: form.export_quantized ? form.quant_group_size : 0, + export_format: form.export_quantized && form.quant_method === 'gguf' ? form.export_format : '', }) ElMessage.success('训练任务已创建并启动') } catch (e) { @@ -437,6 +475,74 @@ onMounted(() => { + + 模型量化 + + + + + + + + + + + + + + + + + 训练命令预览
@@ -606,6 +712,13 @@ onMounted(() => { margin-bottom: 22px; } +.field-tip { + color: #909399; + font-size: 12px; + line-height: 20px; + margin-top: 4px; +} + .form-actions-wrapper { position: fixed; bottom: 0;