# Train ClothingCNN on Fashion-MNIST

- **Lesson ID:** 02
- **Goal:** Train and save a `ClothingCNN` Fashion-MNIST classifier on a Mac. Use MPS when you have it, or CPU when you do not.
- **Human lesson:** [02-pytorch-from-scratch.html](02-pytorch-from-scratch.html)

## Prerequisites

- A Mac Python environment with `torch`, `torchvision`, and a writable project directory.
- The fixed label order and tensor rules from the [pipeline brief](01-the-pipeline.llms.md).

## Inputs, outputs, and artifacts

- **Inputs:** Fashion-MNIST download; `transforms.ToTensor()`.
- **Outputs:** Training/test accuracy, a checked sample prediction, logits with shape `[1,10]`.
- **Artifacts:** `clothing.pt`, plus the training script and saved `ClothingCNN` definition you can run again.

## Agent build steps

1. Check `torch.backends.mps.is_available()`; select `torch.device("mps")` if true, otherwise `torch.device("cpu")`. Do not mention CUDA.
2. Load train/test Fashion-MNIST with `transforms.ToTensor()`, batch size 128, shuffled training loader.
3. Define `ClothingCNN`: Conv2d 1→32, ReLU, max-pool; Conv2d 32→64, ReLU, max-pool; flatten; Linear 64×7×7→128; ReLU; Linear 128→10.
4. Train with `CrossEntropyLoss` and Adam at `1e-3` for at least the lesson's three epochs; evaluate after each epoch.
5. Move the trained model to CPU, set eval mode, and save `model.state_dict()` to `clothing.pt`.
6. Reload the state dict with `map_location="cpu"`, run one test image, and assert the example shape `[1,1,28,28]` and output shape `[1,10]`.

## Constraints

MPS/CPU only, no CUDA. `ToTensor()` must yield float32 0–1 pixels. Input is NCHW `[1,1,28,28]`; output is logits, with no softmax in the model. Keep this exact order: `T-shirt/top`, `Trouser`, `Pullover`, `Dress`, `Coat`, `Sandal`, `Shirt`, `Sneaker`, `Bag`, `Ankle boot`.

## Key concepts

- `ClothingCNN` has two conv layers and two linear layers. It returns `[1, 10]` logits with no softmax in the model.
- Training transform is `ToTensor()`: grayscale float32 pixels in 0-1.
- Class order is `T-shirt/top`, `Trouser`, `Pullover`, `Dress`, `Coat`, `Sandal`, `Shirt`, `Sneaker`, `Bag`, `Ankle boot`.
- Pick MPS when `torch.backends.mps.is_available()`, else CPU. Move the model to CPU before saving `clothing.pt`.

## Takeaways

- `clothing.pt` stores weights only. Keep the `ClothingCNN` class for reload and conversion.
- Assert example shape `(1, 1, 28, 28)` and logits shape `(1, 10)` before you export.
- Apply softmax only when you want a confidence number for the UI.

## Acceptance checks

- `clothing.pt` exists and loads into the same `ClothingCNN` on CPU.
- A test batch runs with logits shape `[1,10]` and finite values.
- The model accepts a zero tensor of dtype float32 and shape `[1,1,28,28]`.
- Record the device used and one evaluation accuracy before [conversion](03-convert-with-coreai-torch.llms.md).

## Environment setup

Use macOS with Python 3.11+ and `uv`:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
mkdir -p clothing-coreai && cd clothing-coreai
uv init --python 3.11
uv venv
uv add torch torchvision coreai-torch
uv run python -c "import torch, torchvision; print(torch.__version__, torchvision.__version__); print('MPS:', torch.backends.mps.is_available())"
uv run python train.py
```

Run lesson scripts with `uv run`. Prefer MPS on Apple silicon. Use CPU if MPS is missing. Do not add CUDA.
