LoRA training: preview strength setting, negative allowed
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MpnF7GwNGMbngU11wjym7P
This commit is contained in:
@@ -114,6 +114,7 @@ export default {
|
||||
await session.flush();
|
||||
const settings = settingsOf(doc);
|
||||
delete settings.preset; // a starting point the person picked, not a setting of the trainer
|
||||
delete settings.preview_strength; // used by the previews only
|
||||
settings.trigger = doc.trigger || "";
|
||||
settings.postfix = doc.postfix || "";
|
||||
if (resumeId) settings.resume = resumeId;
|
||||
@@ -197,6 +198,7 @@ export default {
|
||||
refreshLive();
|
||||
}
|
||||
/** A picture or clip made by the pipeline with the LoRA so far; when `auto`, training carries on afterwards. */
|
||||
const previewStrength = () => { const v = Number(settingsOf(session.doc).preview_strength); return Number.isFinite(v) ? v : 1; };
|
||||
async function previewNow(auto) {
|
||||
const paused = ui.run.paused;
|
||||
if (!paused || !paused.preview) return;
|
||||
@@ -204,7 +206,7 @@ export default {
|
||||
setRun({ state: "previewing", message: `Making a preview with the LoRA at step ${paused.step}` });
|
||||
draw();
|
||||
let out;
|
||||
try { out = app.runner && app.runner.preview ? await app.runner.preview({ lora: paused.preview }) : { error: "Previews need the app's Generate." }; } catch (err) { out = { error: err.message }; }
|
||||
try { out = app.runner && app.runner.preview ? await app.runner.preview({ lora: paused.preview, strength: previewStrength() }) : { error: "Previews need the app's Generate." }; } catch (err) { out = { error: err.message }; }
|
||||
if (out.image) {
|
||||
const im = out.image;
|
||||
ui.previews.push({ id: `p${ui.previews.length + 1}`, step: paused.step, src: { kind: "output", type: im.type || "output", subfolder: im.subfolder || "", filename: im.filename }, media_kind: VIDEO.test(im.filename) ? "video" : "image" });
|
||||
|
||||
@@ -4,7 +4,7 @@ import { stillOf } from "./state.js";
|
||||
|
||||
/** The node's own defaults. A set remembers what was changed from them. */
|
||||
export const DEFAULTS = {
|
||||
name: "funpack_lora", use: "all", preview_every: 0, save_every: 0, steps: 500, learning_rate: 0.0001, rank: 16, algorithm: "LoRA", optimizer: "AdamW", loss: "MSE",
|
||||
name: "funpack_lora", use: "all", preview_every: 0, preview_strength: 1, save_every: 0, steps: 500, learning_rate: 0.0001, rank: 16, algorithm: "LoRA", optimizer: "AdamW", loss: "MSE",
|
||||
batch_size: 1, grad_accumulation: 1, resolution: 512, aspect_buckets: false, frames: 33, fps: 0, start: "start", seed: 0,
|
||||
training_dtype: "bf16", lora_dtype: "bf16", gradient_checkpointing: true, offloading: false, bypass: false, swap_blocks: 0,
|
||||
};
|
||||
@@ -94,6 +94,7 @@ export function trainStep({ app, session, go, ui }) {
|
||||
num("learning_rate", "Learning rate", "How big each step is. Lower is safer and slower.", { min: 0.0000001, max: 1, step: 0.0001, precision: 7 }),
|
||||
num("rank", "Rank", "How much it can learn. Higher holds more detail and makes a bigger file.", { min: 1, max: 128, step: 1 }),
|
||||
num("save_every", "Save a copy every (steps)", "0 saves only the finished LoRA. Otherwise a copy of the LoRA so far goes to your loras folder every this many steps, named like yourname_step200, so you can pick the best moment.", { min: 0, max: 100000, step: 10 }),
|
||||
num("preview_strength", "Preview strength", "How strongly the LoRA is applied in previews. 1 is the usual; use a negative value (for example -1) to see a LoRA trained to be subtracted. Only for previews: it is not part of the training.", { min: -10, max: 10, step: 0.1, precision: 2 }),
|
||||
num("preview_every", "Preview every (steps)", "0 never. Otherwise training waits every this many steps while your pipeline makes a picture or clip with the LoRA so far (the picked scene, the project's own settings), then carries on. Needs a LoRA loader in the pipeline; each wait loads the models again.", { min: 0, max: 100000, step: 10 })] }),
|
||||
c.group.default({ label: "Pictures and clips", rows: [
|
||||
num("resolution", "Size", "Pixels per side. Everything is fitted to about this area.", { min: 64, max: 2048, step: 32 }),
|
||||
|
||||
@@ -296,6 +296,7 @@ test("Tags step: a clip's frame count and rate show beside its label", async ()
|
||||
|
||||
test("a preview step pauses the run, the pipeline makes a preview with the LoRA so far, and training carries on", async () => {
|
||||
const f = fake();
|
||||
f.doc.settings = { preview_strength: -0.8 };
|
||||
const previews = [];
|
||||
f.app.runner = { preview: async (o) => { previews.push(o); return { image: { filename: "pv.mp4", subfolder: "", type: "output" } }; } };
|
||||
let queued = 0, polls = 0;
|
||||
@@ -318,6 +319,8 @@ test("a preview step pauses the run, the pipeline makes a preview with the LoRA
|
||||
await wait(3600);
|
||||
assert.equal(previews.length, 1);
|
||||
assert.equal(previews[0].lora, "cats_preview.safetensors");
|
||||
assert.equal(previews[0].strength, -0.8, "the preview uses the strength set for it, here a negative one");
|
||||
assert.ok(!("preview_strength" in f.calls.find((c) => c[0] === "plan")[2]), "and it is not sent to the trainer");
|
||||
assert.equal(queued, 2, "training was queued again to carry on");
|
||||
const plans = f.calls.filter((c) => c[0] === "plan");
|
||||
assert.equal(plans[1][2].resume, "r1");
|
||||
|
||||
Reference in New Issue
Block a user