Turn a Hosted Image Editor Into a Local LoRA You Own
A mountain bike photographer rented a 20-billion-parameter editing model for an afternoon, used it to label his own photos, and trained a 3.9-billion-parameter adapter that does the same job offline, forever. The method generalizes to any edit you keep paying for.
The entire README of DirtScan/trail-delighter, published this morning, is three bullet points long.
Take photos of a mountain bike trail, which are usually sunny, full of cast shadows, lens flare and glare. Run a selection of them through a hosted lighting-restoration model to produce a "teacher set." Train a new LoRA on that teacher set, but against a smaller base you can run yourself.
That is the whole prose description. The repository underneath it ships considerably more: the exact training config, three intermediate checkpoints, and fifteen matched image triads showing the original photograph, the hosted model's version, and the local adapter's version side by side. Which means somebody published a complete, auditable worked example of a technique most people are still describing in the abstract.
And the technique is an escape route from something a lot of us are doing without noticing: paying a per-image fee, month after month, for one specific transformation we perform on the same kind of picture every single time.
The teacher here is Qwen-Image-Edit-2509 with a lighting-restoration adapter, served through fal at $0.035 per megapixel. The student is FLUX.2 Klein 4B. The teacher carries 20,430,401,088 parameters. The student carries 3,875,544,576. That is a 5.3x reduction, and the student does the job on a card you already own, offline, at no marginal cost, for as long as you keep the file.
Why this is a different move than fine-tuning
Most LoRA advice starts with "collect a dataset." Then it stops, because collecting a dataset is the hard part and nobody wants to say so. You need pairs. You need a before and an after for every image, and producing the after by hand in Photoshop is exactly the labor you were trying to escape.
What this method does is hire the labeling out. The hosted model already solves your problem well. It just solves it expensively and only while you are connected and paying. So you use it once, on a few hundred of your own images, and you keep both sides of every transaction. Input and output. That paired set is the dataset.
You are not distilling the teacher's weights. You do not have them, and for a hosted endpoint you never will. You are distilling its behavior on your specific distribution of images, through a dataset. The hosted model becomes a labeling service you rent for one afternoon rather than a dependency you carry for years.
And this is why the student can be so much smaller than the teacher without embarrassing itself. The 20-billion-parameter model is general. It can composite, restyle, remove objects, change seasons, follow arbitrary text instructions about arbitrary pictures. Your student needs to do exactly one transformation on exactly one kind of photograph. That is a far smaller function to represent. The author's own summary of the tradeoff is one clause: using Klein as the base makes the result "smaller and easier to run."
The narrowness is the point. A general delighter would need general capacity. A delighter for sunlit trail photographs needs to learn one mapping over one visual domain, and 3.9 billion parameters is more than enough room.
The training config shows how literally this is set up. The dataset block takes a folder_path pointing at the teacher's outputs and a control_path pointing at the originals. The originals are the control signal, the teacher's versions are the target, and the model learns to travel between them. This is paired control training, not style training, which is why it can learn "remove this lighting condition, change nothing else" rather than "make pictures that look a certain way." If you have only ever trained style LoRAs on captioned folders, that distinction is the thing to take away.
The licence check nobody runs
Here is the part I got wrong on first read, and it changed how I think about the whole method.
The trail-delighter card ends with a caution: "The adapter is provided under Apache-2.0, subject to the terms of the base FLUX.2 Klein model." That reads like a warning. So I went and checked the base model, expecting a revenue cap or a territory clause or a naming requirement, the kind of thing attached to most of the good open weights this year.
FLUX.2 Klein 4B is Apache 2.0. Ungated. No revenue threshold, no naming clause, no filtering requirement. Qwen-Image-Edit-2509, the teacher model, is also Apache 2.0 and also ungated. Both ends of this chain are about as permissive as open weights get.
So the model licences are not your problem. The service terms are.
When you build a teacher set, you are creating a derivative dataset out of a commercial API's outputs, and then training a model on it. That is a specific permission, it varies by provider, and it is governed by a terms-of-service document rather than by anything on a model card. Some providers grant you full rights to outputs. Some reserve rights over outputs. Some have an explicit clause about using outputs to train competing models, which is arguably what you are doing, depending on how narrowly you read "competing."
The endpoint in this example carries a "Commercial use" badge on its listing page, which is a good sign and not a substitute for reading the actual agreement. Go read it. It takes ten minutes and it is the only genuine legal risk in this entire workflow. Everyone I have watched try this checked the base model licence, which was fine, and never opened the service terms, which is where the answer actually lives.
Put this into practice
Pick something you already pay for repeatedly. Background cleanup on product shots. Colour matching across a shoot. Straightening and delighting scanned artwork. Removing a recurring watermark from your own archive. The narrower and more repetitive it is, the better this works.
1. Read the teacher's terms of service first. Before you spend a cent, confirm you are allowed to train on outputs. If the answer is unclear, ask support and keep the reply. Do not build a dataset you cannot legally use.
2. Resize before you call the teacher, not after. This is the biggest cost saving and almost everyone gets it backwards. You are billed per megapixel. A 12-megapixel photo costs about $0.42 through the endpoint above. The published config trains at 512 pixels, which is 0.26 megapixels, so nearly all of that resolution is thrown away the moment training starts. Downscale to your training resolution first, then send. At 512 the teacher costs under a cent per image, which puts a whole dataset in the price range of a coffee.
3. Use far fewer images than you think. The published run is named trail_delight_klein4b_highres15 and ships fifteen matched triads. Fifteen. Five hundred steps at batch size one. If you were bracing yourself to shoot and label a thousand photographs, do not. The student is learning one mapping over one visual domain, and a small set of images that all exhibit the same problem beats a large set that does not.
4. Run the teacher and keep both sides in separate folders. You need an originals folder and a teacher-outputs folder with matching filenames, because the trainer wants them as two paths, not as interleaved pairs. Run the whole batch in one session so the teacher behaves consistently across the set.
5. Look at every pair before you train. This is where the method lives or dies. The teacher will fail on some images: over-smoothing, invented detail in a blown highlight, a colour cast pushed the wrong way. Every failure you leave in becomes a rule your student learns permanently. With fifteen images there is no excuse for skipping this.
6. Train it. The published config is an ostris/ai-toolkit (12k stars) job, and these are its actual settings, which is the part every other write-up of this technique is missing:
network: { type: lora, linear: 64, linear_alpha: 32, conv: 32, conv_alpha: 16 }
datasets: [{ folder_path: .../target, control_path: .../reference, resolution: [512] }]
train: { steps: 500, batch_size: 1, optimizer: adamw8bit, lr: 0.0001,
noise_scheduler: flowmatch, timestep_type: weighted,
train_unet: true, train_text_encoder: false,
gradient_checkpointing: true, dtype: bf16 }
model: { name_or_path: black-forest-labs/FLUX.2-klein-base-4B, quantize: true }
save: { save_every: 125, max_step_saves_to_keep: 4 }
Note train_text_encoder: false. You are teaching an image transformation, not new vocabulary, so the text side stays frozen and the whole job fits in far less memory. save_every: 125 gives you checkpoints at 125, 250 and 375 steps alongside the final one, and the repo ships all three, which is the author telling you to compare them rather than assuming 500 is right for your data.
7. Write a preserve-list, not just an instruction. The config publishes the sample prompt verbatim, and it is the most transferable thing in the whole repository:
"Remove cast shadows and glare from this trail-surface photograph. Preserve the exact trail geometry, rocks, leaves, markings, and camera viewpoint. Use neutral soft overcast illumination."
One clause says what to remove. One long clause enumerates what must survive. One clause specifies the target condition. Most people write only the first. The middle clause is what stops an edit model from redecorating your photograph while it fixes the lighting, and you should write your own version of it for whatever you are distilling.
8. Test on images the teacher never saw. Hold a few back from the start. Then do what this repo did and lay out three columns: original, teacher, student. If the student tracks the teacher on held-out images you have learned the transformation. If it only works on the training set, you memorized it.
If you want to try the shape of this before spending anything, the Spaces list on the Qwen editing model includes community deployments of the same lighting-restoration behavior, including akhaliq/Qwen-Image-Edit-2509-Light_restoration, so you can make a handful of pairs by hand and find out whether the teacher solves your problem at all before committing to a batch.
Honest limitations
Every error the teacher makes becomes a rule the student learns. There is no correction step in this loop, no human in the middle, no reward signal. The student's ceiling is the teacher's behavior on your images, and it will inherit the teacher's bad habits as faithfully as its good ones. Step five is not optional.
The evaluation is fifteen pictures and your own eyes. The repository publishes matched original, teacher and student versions of fifteen images, which is genuinely more than most releases offer, and it is still fifteen images with no metric attached. There is no distance measurement between student and teacher, no held-out test set, and no statement of how many images the model actually trained on. The run name says highres15 and fifteen triads are published, but the total dataset size is nowhere stated, so treat fifteen as an inference rather than a fact.
The card and the config disagree about the base model. The model card declares black-forest-labs/FLUX.2-klein-4B as the base. The training config trained against black-forest-labs/FLUX.2-klein-base-4B. Both repositories exist, both are Apache 2.0, and both carry 3,875,544,576 parameters, but they are different checkpoints. If you load this adapter onto the model the card names, you are loading it onto something other than what it was trained on. Worth an experiment, not worth an assumption.
The settings are one person's answer for one domain. Rank 64 with alpha 32 at 500 steps worked for trail surfaces. Faces, product shots and scanned artwork will want something else. Start from the published config because a working starting point beats a blank one, then move one dial at a time.
The result is narrow by construction, and that cuts both ways. A delighter trained on sunlit trail photographs is a delighter for sunlit trail photographs. Point it at an indoor portrait and you will get something, but not something you should trust. If your work spans several visual domains, you need several adapters, and the cost math multiplies with them.
You are trading a variable cost for a fixed one, which is only a win at volume. If you delight thirty images a year, keep paying the API. This makes sense when the transformation is a standing part of your process, not an occasional need. Run the arithmetic on your actual last twelve months before you spend a weekend on it.
And the teacher can improve out from under you. The hosted model gets updated. Your frozen student does not. Six months from now the API may simply be better than the thing you distilled, and you will have to decide whether to re-run the whole process against the new version. That is a real recurring cost, just a much smaller one than per-image billing.
What I want to see someone try
The obvious next move is stacking. Nothing about this method requires the teacher to be a single model. You could build a teacher set where the after image is the output of a three-step chain you assembled yourself: delight, then colour match, then straighten. The student learns the composite in one pass, and you have distilled a pipeline rather than a model. I have not seen anyone publish that, and I would like to.
The other thing I keep turning over is that this is a strange kind of technology transfer. A hosted 20-billion-parameter model can be reduced, for a specific job on a specific kind of image, into a file small enough to run on a laptop, by anyone with a few hundred photographs and an afternoon. Nobody had to open-source anything for that to be possible. The capability leaked out through the API, one paid request at a time.
If you build one of these, publish what this one did: the config, the intermediate checkpoints, and the three-column comparison. Then go one better and add the thing it left out, which is a number. Any number. Pixel distance between student and teacher on twenty images the student never saw would be enough to turn a convincing demo into a result somebody else can build on.
Medium metadata
Primary sources:
- Worked example: https://huggingface.co/DirtScan/trail-delighter
- Training config: https://huggingface.co/DirtScan/trail-delighter/blob/main/training/config.yaml
- Teacher endpoint and pricing: https://fal.ai/models/fal-ai/qwen-image-edit-2509-lora-gallery/lighting-restoration
- Teacher model (Apache 2.0, 20.43B): https://huggingface.co/Qwen/Qwen-Image-Edit-2509
- Student base (Apache 2.0, 3.88B): https://huggingface.co/black-forest-labs/FLUX.2-klein-4B
- Trainers: https://github.com/ostris/ai-toolkit and https://github.com/kohya-ss/musubi-tuner