Training my first model
From a free Kaggle GPU to a public page anyone can use, and everything that broke on the way.
What I wanted
I wanted to do the whole training cycle once, start to finish, instead of reading about it. One model, trained on public data, on a free graphics chip, with an honest score. Then put it somewhere another person could actually use it.
The job I picked was simple: read a movie review and say whether it is positive or negative.
The data
I used the IMDB movie review set from Stanford: 50,000 reviews, each already labelled positive or negative. I split it once, with a fixed seed so the split can be rebuilt exactly:
One real problem turned up here. 123 reviews appeared in both the training data and the exam. A model tested on reviews it has already seen gets a better score than it deserves. I removed them, and the training script now refuses to start if any overlap exists.
Training on Kaggle
I didn’t train from nothing. I started from DistilBERT, a small model (66 million numbers) that already understands English. It only had to learn one new thing: which way a review leans. That’s called fine-tuning, and it’s why this fits on a free chip.
Kaggle lends out an NVIDIA T4 graphics chip for free, up to about 30 hours a week. Three passes over the 22,500 reviews took 16 minutes. The whole run, including scoring, took about 30.
| Measure | Score on the exam |
|---|---|
| Before training | 50.5% (a coin flip) |
| After training | 91.3% |
| Positive reviews | 92.4% called correctly |
| Negative reviews | 90.2% called correctly |
The “before” number matters as much as the “after”. Without it, 91.3% is just a number. And because both kinds of review score about the same, I know it learned both answers instead of just guessing the common one. Published results for a model this size on this data sit in the low 90s, so it landed where it should.
Watching the two kinds of loss told me something the score didn’t. On the reviews it trained on, the model kept getting better. On reviews it hadn’t seen, it started getting slightly worse after the first pass. That means it was starting to memorise instead of learn. Two passes would probably have done just as well.
What broke
Almost none of the trouble was about the model itself. It was switches, saving, and sessions:
Output vanished. A Kaggle notebook in Draft mode doesn’t keep what it printed. One page reload wiped 23 minutes of work. Only “Save Version” keeps it.
“Temporary failure in name resolution.” That means no internet. The notebook needs it to download the starting model, and the switch was off. Later, the screen said it was on while Kaggle’s saved settings said it was off.
Two sessions running at once. A Kaggle session uses your weekly allowance whether it’s doing anything or not. I had an idle one burning hours next to the real run.
A crash about mismatched lengths. Reviews are different lengths, and the trainer was never told how to pad the short ones. The fix was one line.
A cell that never started. It showed as running, forever, while still charging GPU time. It’s a known Kaggle bug. The only fix was a fresh notebook.
Putting it online
A trained model sitting in a Kaggle folder is useless to anyone else. The goal became: someone opens a link, pastes a review, and sees positive or negative, with no account and nothing to install.
First I published the model files to Hugging Face as a public model repository. That part was easy.
One detail: the copy I published isn’t quite the one scored above. Kaggle saves a copy after each pass, and the final one got stuck inside Kaggle. So I used a pass-2 copy from an earlier run, which scores 91.0% on the 2,500 check reviews.
The page was not. The usual way to host a demo there is a Gradio app on a free server. But in October 2026 Hugging Face started charging for those (about $9 a month). The only free option left was a Static Space, which serves plain files and has no server to run a model on.
The way around it: run the model in the visitor’s browser instead of on a server. I converted the model to ONNX, a format browsers can run, and shrank it to 8-bit numbers. That took it from 268 MB to 67 MB. A small library called Transformers.js loads it on the page. The first click is slow while the model downloads, and every click after is instant.
The shrunk version scored 90.5% on a 200-review sample, against 91.0% for the full one. Losing half a point to get a page that costs nothing felt like a fair trade.
It’s live at huggingface.co/spaces/mthynk/imdb-movie-review-sorter.
Check the work
The split, the training script, the exact console output, and the trainer's own record are all in the bundle. Two steps below rebuild the data and prove it matches.
- Full bundle (.zip)scripts, console output, trainer record, hashes
- README.mdwhich file backs each claim
- RUN_RESULT.txtthe successful run, pasted exactly as Kaggle printed it
- trainer_state.jsonper-pass check scores and losses
- splits.sha256hashes of the four review files
Download the public ACL IMDb archive, extract it, and rebuild the split:
tar -xzf aclImdb_v1.tar.gz python3 make_splits.pyExpect: learn 22500, check 2500, exam 24877, dropped from exam 123
Copy the checksum list into the new folder and compare:
cp splits.sha256 splits/ cd splits shasum -a 256 -c splits.sha256Expect: all four files OK. I rebuilt it while writing this page and the hashes matched.
What this cannot prove. The 91.3% result is the final pass; that checkpoint was stuck inside Kaggle, so the published model is a pass-2 copy from an earlier run at 91.0%. The 90.5% browser figure came from a throwaway test script that was not kept. The 64 MB of reviews and the 268 MB model are not in the bundle.
What I learned
Measure before, not just after. The 50.5% starting score is what makes 91.3% mean something.
Keep the exam separate, and check for duplicates. 123 overlaps in clean, public data. Real data would have more.
Notice when the goal drifts. I spent five failed Kaggle runs chasing a model that scored half a point higher, while a perfectly good one was already on my machine. Before fixing a blocker, ask whether the blocked step is even needed.
Keep one place that says where things stand. The work was spread across notes, folders, and two websites. More than once I asked “where did I leave off?” and nobody knew, so things got redone.
Most of the friction isn’t the interesting part. Training took 16 minutes. Getting it trained and online took most of a week. I’m told that ratio is normal.