minimind/trainer_web/static/js/train/form.js

129 lines
7.4 KiB
JavaScript

import { startTrain } from '../services/apiClient.js';
import { showNotification } from '../ui/notify.js';
export function initTrainForm() {
const typeSel = document.getElementById('train_type');
if (typeSel) {
typeSel.addEventListener('change', onTrainTypeChange);
typeSel.dispatchEvent(new Event('change'));
}
initGpuSelectors();
const form = document.getElementById('train-form');
if (form) form.addEventListener('submit', onSubmit);
}
function onTrainTypeChange() {
const v = this.value;
const pretrainSft = document.querySelectorAll('.pretrain-sft');
const fromWeightFields = document.querySelectorAll('.from-weight');
const loraFields = document.querySelectorAll('.lora');
const dpoFields = document.querySelectorAll('.dpo');
const dpoCard = document.querySelector('.parameter-card.dpo');
const ppoFields = document.querySelectorAll('.ppo');
const ppoCard = document.querySelector('.parameter-card.ppo');
const grpoFields = document.querySelectorAll('.grpo');
const grpoCard = document.querySelector('.parameter-card.grpo');
const spoFields = document.querySelectorAll('.spo');
const spoCard = document.querySelector('.parameter-card.spo');
pretrainSft.forEach((f) => (f.style.display = v === 'pretrain' || v === 'sft' || v === 'dpo' || v === 'ppo' || v === 'grpo' || v === 'spo' ? 'block' : 'none'));
fromWeightFields.forEach((f) => (f.style.display = v !== 'ppo' && v !== 'grpo' && v !== 'spo' ? 'block' : 'none'));
loraFields.forEach((f) => (f.style.display = v === 'lora' ? 'block' : 'none'));
dpoFields.forEach((f) => (f.style.display = v === 'dpo' ? 'block' : 'none'));
ppoFields.forEach((f) => (f.style.display = v === 'ppo' ? 'block' : 'none'));
if (dpoCard) dpoCard.style.display = v === 'dpo' ? 'block' : 'none';
if (ppoCard) ppoCard.style.display = v === 'ppo' ? 'block' : 'none';
grpoFields.forEach((f) => (f.style.display = v === 'grpo' ? 'block' : 'none'));
spoFields.forEach((f) => (f.style.display = v === 'spo' ? 'block' : 'none'));
if (grpoCard) grpoCard.style.display = v === 'grpo' ? 'block' : 'none';
if (spoCard) spoCard.style.display = v === 'spo' ? 'block' : 'none';
if (v === 'pretrain') setDefaults({ save_dir: '../out', save_weight: 'pretrain', epochs: '1', batch_size: '32', learning_rate: '5e-4', data_path: '../dataset/pretrain_hq.jsonl', from_weight: 'none', log_interval: '100', save_interval: '100', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '512', use_moe: '0' });
else if (v === 'sft') setDefaults({ save_dir: '../out', save_weight: 'full_sft', epochs: '2', batch_size: '16', learning_rate: '5e-7', data_path: '../dataset/sft_mini_512.jsonl', from_weight: 'pretrain', log_interval: '100', save_interval: '100', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '512', use_moe: '0' });
else if (v === 'lora') setDefaults({ save_dir: '../out/lora', lora_name: 'lora_identity', epochs: '50', batch_size: '32', learning_rate: '1e-4', data_path: '../dataset/lora_identity.jsonl', from_weight: 'full_sft', log_interval: '10', save_interval: '1', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '512', use_moe: '0' });
else if (v === 'dpo') setDefaults({ save_dir: '../out', save_weight: 'dpo', epochs: '1', batch_size: '4', learning_rate: '4e-8', data_path: '../dataset/dpo.jsonl', from_weight: 'full_sft', log_interval: '100', save_interval: '100', beta: '0.1', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '1024', use_moe: '0' });
else if (v === 'ppo') setDefaults({ save_dir: '../out', save_weight: 'ppo_actor', epochs: '1', batch_size: '2', learning_rate: '8e-8', data_path: '../dataset/rlaif-mini.jsonl', log_interval: '1', save_interval: '10', clip_epsilon: '0.1', vf_coef: '0.5', kl_coef: '0.02', reasoning: '1', update_old_actor_freq: '4', reward_model_path: '../../internlm2-1_8b-reward', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '66', use_moe: '0' });
else if (v === 'grpo') setDefaults({ save_dir: '../out', save_weight: 'grpo', epochs: '1', batch_size: '2', learning_rate: '8e-8', data_path: '../dataset/rlaif-mini.jsonl', log_interval: '1', save_interval: '10', beta: '0.02', num_generations: '8', reasoning: '1', reward_model_path: '../../internlm2-1_8b-reward', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '66', use_moe: '0' });
else if (v === 'spo') setDefaults({ save_dir: '../out', save_weight: 'spo', epochs: '1', batch_size: '2', learning_rate: '1e-7', data_path: '../dataset/rlaif-mini.jsonl', log_interval: '1', save_interval: '10', beta: '0.02', reasoning: '1', reward_model_path: '../../internlm2-1_8b-reward', hidden_size: '512', num_hidden_layers: '8', max_seq_len: '66', use_moe: '0' });
}
function setDefaults(map) {
Object.entries(map).forEach(([name, val]) => {
const nodes = document.querySelectorAll(`[name="${name}"]`);
nodes.forEach((node) => {
const card = node.closest('.parameter-card');
const visible = !card || card.style.display !== 'none';
if (visible) node.value = val;
});
});
}
function initGpuSelectors() {
const hasGpu = window.hasGpu === true;
const gpuCount = Number(window.gpuCount || 0);
const modeSel = document.getElementById('training_mode');
const single = document.getElementById('single-gpu-selection');
const multi = document.getElementById('multi-gpu-selection');
if (!modeSel) return;
function updateVisibility() {
const mode = modeSel.value;
if (single) single.style.display = mode === 'single_gpu' ? 'block' : 'none';
if (multi) multi.style.display = mode === 'multi_gpu' ? 'block' : 'none';
}
if (!hasGpu) {
modeSel.value = 'cpu';
if (single) single.style.display = 'none';
if (multi) multi.style.display = 'none';
} else {
const gpuNumInput = document.getElementById('gpu_num');
if (gpuNumInput && gpuCount > 0) gpuNumInput.value = gpuCount;
}
updateVisibility();
modeSel.addEventListener('change', updateVisibility);
}
function onSubmit(e) {
e.preventDefault();
const form = e.currentTarget;
const data = {};
const trainingModeSel = form.querySelector('#training_mode');
const trainingMode = trainingModeSel ? trainingModeSel.value : 'cpu';
const inputs = form.querySelectorAll('input, select, textarea');
inputs.forEach((el) => {
const name = el.name;
if (!name || name === 'training_mode') return;
const card = el.closest('.parameter-card');
const visible = !card || card.style.display !== 'none';
if (!visible) return;
let value = el.value;
if (el.type === 'checkbox') {
if (!el.checked) return;
}
if (name === 'gpu_num') {
const multi = document.getElementById('multi-gpu-selection');
if (!(multi && multi.style.display !== 'none')) return;
}
if (name === 'device') {
if (trainingMode === 'single_gpu') value = `cuda:${value}`;
else if (trainingMode === 'cpu') value = 'cpu';
else return;
}
data[name] = value;
});
showNotification('正在启动训练...', 'info');
setTimeout(() => {
startTrain(data)
.then((result) => {
if (result.success) {
showNotification('训练已开始!', 'success');
setTimeout(() => {
const processTab = document.querySelector('.tab[onclick*="processes"]');
if (processTab) processTab.click();
}, 1000);
} else showNotification('训练启动失败:' + result.error, 'error');
})
.catch(() => {
showNotification('启动训练中,请耐心等待...', 'info');
});
}, 1000);
}