Training the rbtnoir Style LoRA

How our film project's old generations became a custom-trained video model — 2026-08-15/16

TL;DR — We taught the MiniMax H3 video model our film's visual style by training a LoRA — a small add-on model — on 59 hand-picked clips from our own AI-film project. The goal: make the cheaper H3 model reproduce the film-noir-cyberpunk look we had built on the more expensive Seedance 2. We trained three versions (with less, normal, and more training) and compared them blind; the 5,000-step LoRA won and is now the default video model in our production app. Total cost: ≈ $115 for training + ≈ $30 for test generations.

One caveat up front: the trainer can continue training from an earlier run (resume_from_lora_url). Using that would have given us all three versions for about 33% less money — see What we'd do differently.

1Gathering the data

We did not have to collect any training data — we already had it. Our app saves a record of every generation it runs: the exact prompt, the reference images that were sent with it, all the settings, and the output file. Each project keeps these records in its own small database. So the training data was already sitting there, waiting to be used.

A small script read all 13 project databases and pulled out 458 candidate samples: 227 images and 231 videos. Each sample is a complete record — the prompt, the reference files, the settings, and the output. (The script only reads copies of the databases, so it can never disturb a live project.)

The videos were almost ready for training on their own: all exactly 24.000 fps (the trainer requires this), all with sound (the trainer learns picture and sound together), and all 5–15 seconds long.

Style target frame from a Seedance 2 generation
The look we wanted: a frame from the project's Seedance 2 footage — almost black-and-white, high contrast, with small touches of color. This is what the LoRA had to teach H3.

2Cleaning & curating

Next came a human review. We built a small local website that shows every candidate in a grid — with its full prompt, its reference images, and a playable video — and went through them by hand:

3Training

We trained on fal's minimax/h3/ref2va/trainer — the variant that accepts reference images, matching how we run the model in production. (A fal LoRA only works in the mode it was trained for, so the trainer and the production endpoint must match.)

ParameterValueWhy
rank16fal's guide recommends 16 for style; the default (32) learns a small dataset too literally
learning_rate2e-4trainer default
reference_conditioning_p0.9keeps the model good at prompt-only generation while it learns to use references
number_of_frames73 (~3 s)trainer default; the number must fit the rule frames % 17 == 5
trigger_phraserbtnoir stylethe words that switch the style on when generating
split_input_into_scenesfalsethe default (true) silently throws away the reference images of any clip it splits
debug_datasettrue on cheapest runreturns a report on how the trainer processed the dataset — one cheap check that covers all three runs

We trained three versions: fewer steps than the docs recommend, exactly as recommended, and more:

RunStepsCost ($0.015/step)
h3-500500$7.50
h3-2000 (docs default)2,000$30.00
h3-5000 (fal's best published run)5,000$75.00

How the jobs ran: we submitted each job and then checked its status in a loop. (fal's streaming subscribe channel hung twice on our machine; simple status checks never failed.) Every step of progress was saved to disk, so a crash or a restart never re-billed anything.

4Evaluation

Act II storyboard still used as Image 1
One of the unseen test cases: the storyboard still sent as Image 1 (the opening frame). The LoRA never saw this shot during training.
H3 base output frame
H3 base — same prompt, references, and seed.
LoRA 500 output frame
+ LoRA @500 steps.
LoRA 5000 output frame
+ LoRA @5000 steps (shipped).

The votes: LoRA@500 ×4 · LoRA@5000 ×4 · H3 base ×3 · LoRA@2000 ×1. Both the smallest and the largest LoRA beat the base model. We broke the tie in favor of @5000, expecting it to hold up better across many kinds of shots. It is now the default video model in the app. At prompt time, the app automatically replaces the project's written style description with the trigger phrase — using both at once would apply the look twice.

5What we'd do differently: chained runs

One important limit first: the trainer cannot save checkpoints during a run. Unlike some local training tools, there is no option to snapshot the weights every N steps — one run produces exactly one LoRA, at the end.

What it can do is start a new run from a finished LoRA's weights (resume_from_lora_url). Training 500 steps, then +1,500 more, then +3,000 more would have cost 5,000 steps ($75) instead of 7,500 ($112.50) — and still given us all three versions, each as the final result of its own run.

Why we ran three separate runs anyway: a resumed run restarts the trainer's internal schedule, so a chained "2,000-step" version is not exactly the same as a true 2,000-step run. That is fine in production, but it would have muddied our clean comparison of step counts.

The takeaway: now that we know how many steps we need, the next LoRA should be one chain of resumed runs — about 33% cheaper for the same information.

6The numbers

Candidates harvested458 (227 images / 231 videos) across 13 project DBs
Video clips kept59 (15 trimmed), 166 reference sidecars
H3 training3 runs, 7,500 steps, $112.50
Evaluation generationsheld-out comparison videos, ≈ $30
Total≈ $145
Winnerh3-ref2va @5000, rank 16, trigger rbtnoir style — default video model in the app

The full machine-readable record of every run (request ids, LoRA URLs) is in lora-lab/runs.json in the project repo. A markdown version of this page sits next to it: training-report.md.