mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 22:48:11 +02:00
MoE : avis de placement, copie en placement auto et garde du mode de chargement
Un MoE aux experts sur CPU se règle aujourd'hui à la main (-ot, --n-cpu-moe 40, UBATCH 512) sans que Loki dise ce que --fit ferait mieux, ni qu'un --load-mode none/mlock trop gros pour la RAM mène au swap ou à l'OOM (llama.cpp #26110). Rien n'est réécrit en douce : des avis, une copie sur demande, un refus seulement quand l'échec est certain. - moeNotes (pure, comme nglArgs) : experts placés à la main → --fit ne les place pas, et ne pas monter UBATCH seul (tampon plus gros sur chaque carte) ; placement auto, MoE plus gros que la VRAM, UBATCH ≤ 512 → « UBATCH 2048+ » ; moteur sans --fit → « garde --n-cpu-moe » ; --fit coupé par un autre -ot. Le détecteur cpuExperts ne compte un -ot que s'il vise les experts (exps) vers le CPU : celui de per_layer_token_embd n'en est pas. - « Dupliquer en placement auto… » (éditeur, /api/preset/autoplace) : COPIE du preset affiché, sans -ot des experts, --n-cpu-moe, --cpu-moe, -ngl, --tensor-split, --fit off, -b/-ub ni drapeaux de chargement ; NGL retiré, UBATCH 2048, BATCH 4096, --load-mode mmap ; CTX, cache KV, échantillonnage intacts. Refusée si --fit resterait inactif ou si CTX vaut 0. L'original n'est pas touché, la copie n'est pas activée. - loadModeRisk : none, mlock, dio, mmap+mlock (et --no-mmap, --mlock, LLAMA_ARG_*) face à la RAM effective (limite cgroup comprise), en comptant modèle moins VRAM (tout le modèle sur macOS) : avertissement au-delà de 80 %, refus au lancement au-delà de 90 % de la borne basse seulement ; LOAD_GUARD=off le lève. VRAM inconnue : jamais de refus. - Éditeur : avis sous « Experts MoE sur CPU » et sous « Chargement ». Ligne de commande et environnement du moteur inchangés (test de non-régression) ; presets externes ignorés. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
986a636c20
commit
f87c7b615b
11 files changed
+1001
-8
No files matched your search
@@ -508,6 +508,62 @@ func handlePresetCacheRAM(w http.ResponseWriter, r *http.Request) {
|
||||
sendJSON(w, 200, out)
|
||||
}
|
||||
|
||||
// handlePresetMoE : avis MoE et mode de chargement pour le preset en cours
|
||||
// d'édition (voir backend_serve_moe.go), et ce que ferait « Dupliquer en
|
||||
// placement auto » — sans rien écrire.
|
||||
func handlePresetMoE(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<20)).Decode(&req); err != nil {
|
||||
sendJSON(w, 400, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
notes, load := moePreview(req.Content)
|
||||
out := map[string]any{"ok": true, "notes": notes, "load": load}
|
||||
// L'assistant n'est proposé qu'à un preset qui place des experts à la
|
||||
// main ; « rien à migrer » ne s'affiche pas.
|
||||
if cfg := parseEnv(req.Content); !isExternalConfig(cfg) && cpuExperts(splitArgs(cfg["EXTRA_ARGS"]), nil) != "" {
|
||||
if _, changes, err := autoPlacementPreset(req.Content); err != nil {
|
||||
out["autoplace"] = map[string]any{"ok": false, "why": err.Error()}
|
||||
} else {
|
||||
out["autoplace"] = map[string]any{"ok": true, "changes": changes}
|
||||
}
|
||||
}
|
||||
sendJSON(w, 200, out)
|
||||
}
|
||||
|
||||
// handlePresetAutoPlace crée la copie en placement auto du preset édité (son
|
||||
// contenu tel qu'affiché), sous un nouveau nom. Le preset d'origine n'est pas
|
||||
// touché, et la copie n'est pas activée : c'est à l'utilisateur de basculer,
|
||||
// puis de comparer (bench complet).
|
||||
func handlePresetAutoPlace(w http.ResponseWriter, r *http.Request) {
|
||||
if !postOnly(w, r) {
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 1<<20)).Decode(&req); err != nil {
|
||||
sendJSON(w, 400, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
out, changes, err := autoPlacementPreset(req.Content)
|
||||
if err != nil {
|
||||
sendJSON(w, 200, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
name := firstNonEmpty(strings.TrimSpace(req.Name), presetDisplayName(req.Content, req.ID), "preset") + " (placement auto)"
|
||||
newID, err := SavePreset("", name, out)
|
||||
if err != nil {
|
||||
sendJSON(w, 200, map[string]any{"ok": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
sendJSON(w, 200, map[string]any{"ok": true, "id": newID, "name": name, "changes": changes})
|
||||
}
|
||||
|
||||
func handlePresetSave(w http.ResponseWriter, r *http.Request) {
|
||||
var req presetSaveReq
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
||||
Reference in new issue
Block a user