Build with AI

How do you train your first model on any laptop, with no GPU?

Written as of · Published · Updated · By Robert Scales, with AI tools · 4 min read

Short answer

Install scikit-learn, load its built-in handwritten digits, and fit a small neural network on the CPU; on one processor thread this took under half a second and reached 96.9% accuracy on images it never saw. The point is the habit, not the score: keep test data apart, compare against a dumb baseline, save the model and check that it reloads.

Training a model does not start with buying hardware. It starts with a question a program can learn to answer from examples. "Which digit is in this tiny picture?" is a good first one: the data ships with a free library, the answer can be checked, and the whole job fits in the memory of an old computer.

To train a model is to adjust a large set of numbers until the program's answers on known examples get better. A GPU, or graphics processor, only does that arithmetic faster. When the data and the model are small, the ordinary processor in any laptop is plenty, and a mistake costs you a few seconds, not a rental bill.

The whole project, in one file

You need Python 3 and two minutes. The commands below create a separate environment, so nothing touches the rest of your system.

python3 -m venv first-model
source first-model/bin/activate      # on Windows: first-model\Scripts\activate
pip install scikit-learn

Save this as first_model.py and run python first_model.py.

import os
os.environ["OMP_NUM_THREADS"] = "1"   # one CPU thread, on purpose
import joblib
from sklearn.datasets import load_digits
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier

digits = load_digits()
X, y = digits.data / 16.0, digits.target   # pixels go from 0 to 16; bring them to 0-1
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=0)

baseline = DummyClassifier(strategy="most_frequent").fit(X_train, y_train)
print("always guessing one digit:", baseline.score(X_test, y_test))

model = MLPClassifier(hidden_layer_sizes=(64,), max_iter=400, random_state=0)
model.fit(X_train, y_train)
print("small neural network:", model.score(X_test, y_test))

joblib.dump(model, "digits.joblib")
again = joblib.load("digits.joblib")
print("reloaded model agrees:", (again.predict(X_test) == model.predict(X_test)).all())

The digits dataset holds 1,797 images of 8 by 8 pixels, in 10 classes. train_test_split keeps 360 of them away from training. stratify=y makes sure every digit appears in both piles in the same proportion. The MLPClassifier is a small neural network: 64 inputs, one hidden layer of 64 units, 10 outputs.

What it measured

These numbers come from running the longer companion script, 01_first_model.py, once, limited to a single CPU thread on an Apple M5 Max computer with 64 GB of memory, Python 3.14 and scikit-learn 1.9.1. An older laptop will take longer; that was not tested here.

ModelTraining timeAccuracy on 360 unseen imagesMistakes
Always guess the most common digit0.000 s10.0%324
Logistic regression (a straight-line classifier)0.016 s96.7%12
Small neural network, 4,810 parameters0.379 s96.9%11

Measured here as well: the saved file is 165 KB, the reloaded model gave the same answer on all 360 test images, and the whole program peaked at 215 MB of memory. The slowest part of the first run was not training at all. Starting Python and loading the libraries from a cold disk took about 50 seconds; later runs start in a second or two.

Look at the table again. The neural network beat the much simpler straight-line model by one image out of 360. That is not a meaningful win, and the series comes back to why in project four. A beginner who skips the simple model would never learn that the "real AI" barely mattered here.

Why four habits matter more than this model

Everything else in this series is a bigger version of what those twenty lines do.

HabitIn this projectWhat it prevents
Hold out test data360 images never used in trainingGrading the model on the answers it has memorized, which the scikit-learn documentation calls a methodological mistake
Beat a baseline10% from guessingCelebrating a score that means nothing
Fix the random seedrandom_state=0Not knowing whether a change or plain luck moved your score
Save and reloadjoblib.dump, then compareFinding out later that the model only worked in memory

joblib files use Python's pickle format, which can run code when loaded. Open only the ones you made yourself. Project 14 moves to a safer format.

When a laptop stops being enough

scikit-learn says plainly that this network is not meant for large-scale work and has no GPU support. You will outgrow it, though usually later than you expect. Later projects in this series were all run on one machine, and they show exactly where the time and memory go. For now, one rule of thumb is enough: if a run finishes in minutes on your processor, you do not need anything else yet.

Try it: Change test_size=0.2 to test_size=0.9, so that only 179 images train the model, then run it again and write down what happens to the accuracy.

What should you change first once the model works?

Change one thing at a time and write down the result. Good first changes are the amount of training data, then the hidden layer size, for example (16,) or (256,). Those two experiments teach you how much a problem depends on data and how much on model size.

Next, find out which mistakes it makes. Print the confusion between true and predicted digits with sklearn.metrics.confusion_matrix, then look at the pictures themselves. In the companion run the most common error was calling an 8 a 1, twice. Looking at errors tells you more than one more decimal of accuracy.

Then swap in your own small table of data, if you have one you are allowed to use. The code hardly changes, while the questions get harder: where the labels come from, whether they are right, and whether your test set looks like real use. Project three is about exactly that. Before that, project two opens the box and shows what "training" actually changes.

Download the companion code for this series (zip), with every script and the recorded results.

Sources

  1. load_digits — scikit-learn
  2. Neural network models (supervised) — scikit-learn
  3. Cross-validation: evaluating estimator performance — scikit-learn

From the Guide to Artificial Intelligence, by Robert Scales, published by Holistic Hybrid Inc. Share and adapt it under CC BY-NC-SA 4.0: credit the guide, link to https://guidetoartificialintelligence.com/en/learn/train-first-model-laptop-no-gpu/, no commercial use without permission, and keep the same licence.

Get the free Guide to Artificial Intelligence

Sign up for the newsletter and receive the free guide: what changed in AI, one lesson, one prompt to try. Unsubscribe in one click.

How we handle your address

Back to top

Display

Your choices are saved in this browser only. No data is sent.

Text size
100%
Colours
Reading
More settings
Accessibility statement

Get the app

Add the guide to your home screen. It opens like an app, and the pages you have read stay available offline.

Read without a connection: download the articles

iPhone and iPad (Safari, Chrome, Edge)

  1. Tap the Share button (the square with an arrow). In Chrome and Edge, it is in the address bar or the menu.
  2. Choose “Add to Home Screen”.
  3. Tap “Add”.

Android (Chrome, Edge, Samsung Internet, Firefox)

  1. Open the browser menu (⋮ or ☰).
  2. Choose “Install app” or “Add to Home screen”.
  3. Confirm with “Install”.

Computer (Chrome, Edge)

  1. Click the install icon at the right end of the address bar, or open the browser menu (⋮ or …).
  2. In Chrome, choose “Cast, save and share”, then “Install page as app”. In Edge, choose “Apps”, then “Install this site as an app”.
  3. Click “Install”.

Mac (Safari)

  1. Open the File menu.
  2. Choose “Add to Dock”.
  3. Click “Add”.

Firefox on a computer can’t install a site as an app. Use Chrome, Edge or Safari instead.