- 引入 MemoryRouterXL 与 v5/v6 流式多线程训练/编码管线 - 修复 prepare_memory_router_dataset 候选池重建缺陷(mega 家族 3568x 加速,输出逐字节相同) - 修复 v5 被破坏的拒答与多跳标签(train 未知样本 319 -> 16319,multi_hop 平均正例 1.00 -> 2.00) - 同存储预算下 V2-128 v6 逐轴 22/22 通过:Top-1 41.12% -> 94.62%,未知拒答 0.00% -> 100.00% - 记录三条被实测推翻的显然优化(logits_to_keep=1 反而慢 55%、XL 容量未带来收益) - 记忆手术跨架构可移植性 14/14,读写关闭时与原生模型逐位相同
138 lines
5.4 KiB
PowerShell
138 lines
5.4 KiB
PowerShell
# Launch MemoryRouterXL training runs in the fork.
|
|
#
|
|
# Order matters: the 512-dim run goes first because router_dim == the stored
|
|
# address size per memory record, so 512 matches the existing 512-dim baseline
|
|
# exactly (same per-record storage cost) and isolates router-internal capacity.
|
|
#
|
|
# Every run reuses:
|
|
# * the frozen router_training_v3 dataset (same train/eval as the 512 baseline),
|
|
# * the frozen Qwen feature cache (Qwen is never loaded; no re-encoding),
|
|
# * the identical evaluation protocol of train_memory_router_large.
|
|
#
|
|
# Usage:
|
|
# pwsh -File H:\Memory\V2_dpskw\run_router_xl.ps1
|
|
# pwsh -File H:\Memory\V2_dpskw\run_router_xl.ps1 -Configs xl512
|
|
# pwsh -File H:\Memory\V2_dpskw\run_router_xl.ps1 -Configs xl512 -Resume
|
|
param(
|
|
[int]$Steps = 100000,
|
|
[int]$EvalInterval = 500,
|
|
[int]$BatchSize = 64,
|
|
[double]$GpuMemoryGb = 9,
|
|
[string[]]$Configs = @('xl512'),
|
|
[switch]$Resume
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$Python = 'C:\Users\Administrator\miniconda3\envs\LLM\python.exe'
|
|
$ForkRoot = 'H:\Memory\V2_dpskw'
|
|
$Parent = 'H:\Memory'
|
|
$TrainFile = 'data/router_training_v3/train.jsonl'
|
|
$EvalFile = 'data/router_training_v3/eval.jsonl'
|
|
$CacheDir = 'checkpoints/router_shared/feature_cache'
|
|
$ModelPath = 'qwen3_5_4b_natural_memory_v2'
|
|
|
|
# Architecture presets. ``xl512`` keeps router_dim = 512 and num_heads = 8, i.e.
|
|
# the exact address geometry of the V2 512 baseline, and spends the extra
|
|
# capacity inside the encoder, the pair trunk and the policy heads.
|
|
$Presets = @{
|
|
'xl512' = [pscustomobject]@{
|
|
Label = 'router_xl_512'
|
|
OutputDir = 'checkpoints/router_xl_512'
|
|
Args = @(
|
|
'--router-dim 512', '--num-heads 8',
|
|
'--encoder-layers 2', '--encoder-hidden 512',
|
|
'--pair-blocks 1', '--pair-hidden 512', '--pair-expansion 2', '--pair-dropout 0.05',
|
|
'--policy-layers 2', '--policy-hidden 512'
|
|
)
|
|
}
|
|
'xl1024' = [pscustomobject]@{
|
|
Label = 'router_xl_1024'
|
|
OutputDir = 'checkpoints/router_xl_1024'
|
|
Args = @(
|
|
'--router-dim 1024', '--num-heads 16',
|
|
'--encoder-layers 2', '--encoder-hidden 1024',
|
|
'--pair-blocks 1', '--pair-hidden 1024', '--pair-expansion 2', '--pair-dropout 0.05',
|
|
'--policy-layers 2', '--policy-hidden 512'
|
|
)
|
|
}
|
|
'xl2048' = [pscustomobject]@{
|
|
Label = 'router_xl_2048'
|
|
OutputDir = 'checkpoints/router_xl_2048'
|
|
Args = @(
|
|
'--router-dim 2048', '--num-heads 16',
|
|
'--encoder-layers 2', '--encoder-hidden 2048',
|
|
'--pair-blocks 1', '--pair-hidden 2048', '--pair-expansion 2', '--pair-dropout 0.05',
|
|
'--policy-layers 2', '--policy-hidden 512'
|
|
)
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $Python)) { throw "Python not found: $Python" }
|
|
foreach ($required in @($TrainFile, $EvalFile)) {
|
|
if (-not (Test-Path -LiteralPath (Join-Path $ForkRoot $required))) { throw "Missing data file: $required" }
|
|
}
|
|
if (-not (Test-Path -LiteralPath (Join-Path $ForkRoot $CacheDir))) { throw "Missing feature cache: $CacheDir" }
|
|
|
|
$env:PYTHONPATH = $Parent
|
|
Set-Location $ForkRoot
|
|
|
|
# Refuse to start if the frozen feature cache does not match the frozen data:
|
|
# otherwise the trainer would silently load the 4B model and re-encode.
|
|
$cacheCheck = & $Python -m V2_dpskw.check_router_cache 2>&1 | Out-String
|
|
if ($cacheCheck -notmatch 'CACHE HIT') {
|
|
throw "feature cache check failed:`n$cacheCheck"
|
|
}
|
|
Write-Output 'feature cache: HIT'
|
|
|
|
$common = @(
|
|
'-m V2_dpskw.train_memory_router_xl',
|
|
"--train-file $TrainFile",
|
|
"--eval-file $EvalFile",
|
|
"--feature-cache-dir $CacheDir",
|
|
"--model-path $ModelPath",
|
|
"--steps $Steps",
|
|
"--batch-size $BatchSize",
|
|
"--eval-interval $EvalInterval",
|
|
"--gpu-memory-gb $GpuMemoryGb",
|
|
'--log-every 100'
|
|
)
|
|
|
|
$started = @()
|
|
foreach ($name in $Configs) {
|
|
if (-not $Presets.ContainsKey($name)) { throw "unknown config: $name" }
|
|
$run = $Presets[$name]
|
|
$outputDir = Join-Path $ForkRoot $run.OutputDir
|
|
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
|
$runArgs = $run.Args
|
|
|
|
$resumePath = ''
|
|
if ($Resume) {
|
|
$latest = Get-ChildItem -Path $outputDir -Filter 'router_step_*.pt' -ErrorAction SilentlyContinue |
|
|
Sort-Object Name -Descending | Select-Object -First 1
|
|
if ($latest) {
|
|
$resumePath = $latest.FullName
|
|
Write-Output ("resuming {0} from {1}" -f $run.Label, $latest.Name)
|
|
}
|
|
}
|
|
|
|
$argumentLine = ($common + @("--label $($run.Label)", "--output-dir $($run.OutputDir)"))
|
|
if ($resumePath) {
|
|
$argumentLine += @("--resume `"$resumePath`"")
|
|
} else {
|
|
$argumentLine += @('--overwrite-metrics')
|
|
}
|
|
$argumentLine = ($argumentLine + $runArgs) -join ' '
|
|
|
|
$stdout = Join-Path $outputDir 'training_stdout.log'
|
|
$stderr = Join-Path $outputDir 'training_stderr.log'
|
|
Write-Output ("starting {0}: {1}" -f $run.Label, $argumentLine)
|
|
$process = Start-Process -FilePath $Python -WorkingDirectory $ForkRoot `
|
|
-ArgumentList $argumentLine -RedirectStandardOutput $stdout `
|
|
-RedirectStandardError $stderr -WindowStyle Hidden -PassThru -Wait
|
|
Write-Output ("{0} exited with code {1}" -f $run.Label, $process.ExitCode)
|
|
$started += [pscustomobject]@{ label = $run.Label; output_dir = $run.OutputDir; exit_code = $process.ExitCode; stdout = $stdout; stderr = $stderr }
|
|
}
|
|
|
|
$started | ConvertTo-Json -Compress
|