Metadata-Version: 2.4
Name: coldet-trainer
Version: 0.1.2
Summary: Constraint-based CNN generator and trainer. Describe what you need — not how to build it.
License: MIT
Keywords: deep-learning,computer-vision,cnn,pytorch,constraint-based
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: torch>=2.0
Requires-Dist: numpy>=1.24
Requires-Dist: opencv-python>=4.8
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: torchvision>=0.15; extra == "dev"

# coldet

> **Describe constraints, not networks.**

coldet is a minimal Python package for building and training vision models without touching a single line of architecture code. You express *what you need* — size, speed, accuracy tradeoff — and the system generates a valid CNN for you.

coldet is classification-only. All detection, segmentation, and open-vocabulary tasks have been intentionally removed to keep the surface area small and the output format predictable.

---

## Why constraint-based modelling?

Traditional ML frameworks ask you to design networks: choose a backbone, wire up layers, pick kernel sizes, set strides. This works when you have expertise and time. Most of the time, you just need a model that is *fast enough* and *accurate enough* for your problem.

coldet flips the question. Instead of:

> "I want ResNet-50 with a 4-layer head…"

You say:

> "I want something medium-sized that leans toward speed."

The architecture is derived automatically from those constraints. You never see layer names, channel counts, or backbone identifiers — because they are not your concern.

**Benefits:**
- No architecture expertise required.
- Constraints are reproducible: same inputs → same model.
- Easier to reason about tradeoffs (`speed_bias=0.9` is faster than `speed_bias=0.3` — always).

---

## Installation

```bash
pip install coldet
```

Or from source:

```bash
git clone https://github.com/yourorg/coldet
cd coldet
pip install -e .
```

---

## Dataset formats

coldet supports two dataset layouts. The right one is auto-detected.

### 1. Flat — subfolder-per-class

Each subfolder is a class. Simple and fast to set up.

```
dataset/
    red/
        img001.jpg
        img002.png
        ...
    blue/
        img001.jpg
        ...
    green/
        ...
```

Supported image formats: `.jpg`, `.jpeg`, `.png`, `.ppm`, `.bmp`, `.tiff`, `.webp`.

### 2. Hierarchical — parent/sub-class layout

Use this when your classes have natural sub-categories (e.g. "red" → "crimson", "scarlet"). Each parent folder contains one or more sub-class folders.

```
dataset/
    red/
        crimson/
            img001.jpg
            ...
        scarlet/
            img001.jpg
            ...
    blue/
        img001.jpg    ← images directly in a parent are labelled with the parent name
        ...
    green/
        olive/
            img001.jpg
        ...
```

**How labels are assigned:**
- Each unique sub-class folder name becomes a label (e.g. `crimson`, `scarlet`, `olive`).
- Images placed directly inside a parent folder (not in any sub-class folder) are assigned a synthetic sub-class label identical to the parent name (e.g. `blue`).
- The hierarchy `{parent: [sub, ...]}` is saved in every `.coldet` checkpoint and used at inference time to aggregate parent-level probabilities.

**Inference output for a hierarchical model** (see `coldet.infer`):**
```
predicted_class:     crimson
confidence:          61.2%
probabilities:       {crimson: 61.2%, scarlet: 13.3%, red: 10.1%, ...}
predicted_parent:    red
parent_probabilities: {red: 74.5%, blue: 18.2%, green: 7.3%}
```

The `parent_probabilities` are computed by summing all sub-class probabilities that belong to each parent. They always sum to 1.0.

---

## Quickstart

### Classification — flat layout

```python
import coldet

trainer = coldet.Trainer(
    size="medium",       # "nano" | "small" | "medium" | "large"
    speed_bias=0.7,      # 0 = prefer accuracy, 1 = prefer speed
    dataset="dataset/",
    batch_size=32,
    image_size=224,
)
# [coldet] dataset 'dataset/' — 3 classes discovered: ['blue', 'green', 'red']

trainer.train(epochs=10)
trainer.summary()
trainer.save("checkpoints/run1.coldet")
```

### Classification — hierarchical layout

```python
import coldet

trainer = coldet.Trainer(
    size="medium",
    speed_bias=0.5,
    dataset="hier_dataset/",  # contains sub-class subfolders → hierarchical mode
    batch_size=16,
    image_size=256,
)
# [coldet] hierarchical dataset 'hier_dataset/' — 5 sub-classes across 3 parent classes: ['blue', 'green', 'red']

trainer.train(epochs=20)
trainer.summary()
trainer.save("checkpoints/hier_run.coldet")
```

### Manual DataLoader

```python
import coldet
from torch.utils.data import DataLoader

trainer = coldet.Trainer(size="medium", speed_bias=0.7, num_classes=3)
trainer.train(my_dataloader, epochs=10)
trainer.summary()
```

### Loading a checkpoint

```python
# Load into an existing Trainer (constraints must match)
trainer.load("checkpoints/run1.coldet")

# Reconstruct from scratch — no constructor arguments needed.
# Use this in inference scripts.
trainer = coldet.Trainer.from_checkpoint("checkpoints/run1.coldet")

import torch
images = torch.rand(4, 3, 224, 224)
logits = trainer.predict(images)   # shape (4, num_classes)
```

---

## Inference — `coldet.infer`

The recommended way to run a trained model on a single image. No Trainer setup needed.

```python
import coldet

result = coldet.infer(
    image_path="photo.jpg",
    model_path="checkpoints/run1.coldet",
    temperature=1.0,   # optional, default 1.0
)

print(result["predicted_class"])   # e.g. "crimson"
print(f"{result['confidence']:.1%}")  # e.g. "61.2%"

# Full probability breakdown
for cls, prob in result["probabilities"].items():
    print(f"  {cls}: {prob:.1%}")

# Hierarchical models also include parent-level aggregation
if result["parent_probabilities"]:
    print(f"\nParent: {result['predicted_parent']}")
    for par, prob in result["parent_probabilities"].items():
        print(f"  {par}: {prob:.1%}")
```

### Temperature

The `temperature` parameter scales the logits before the final softmax:

| Value | Effect |
|-------|--------|
| `< 1.0` | Sharper distribution — the top prediction dominates more. Use when you want decisive, high-confidence outputs. |
| `1.0` (default) | Standard softmax probabilities. |
| `> 1.0` | Flatter distribution — probabilities are more spread out. Use to see how uncertain the model is across all classes. |

Useful range: `0.1` – `5.0`.

### Return value

| Key | Type | Description |
|-----|------|-------------|
| `predicted_class` | str | Sub-class with the highest probability |
| `confidence` | float | Probability of the predicted class (0–1) |
| `probabilities` | dict[str, float] | All sub-class probabilities, sorted descending |
| `parent_probabilities` | dict[str, float] or None | Parent-class probabilities (hierarchical models only) |
| `predicted_parent` | str or None | Parent of the predicted sub-class (hierarchical only) |
| `temperature` | float | Temperature used |
| `image_path` | str | Echoed input path |

---

## API Reference

### `coldet.load_dataset`

```python
loader, class_names, hierarchy = coldet.load_dataset(
    dataset_path,        # root folder
    image_size=224,
    batch_size=32,
    shuffle=True,
    num_workers=0,
)
```

Returns a `(DataLoader, list[str], dict or None)` tuple.

- `class_names` — sorted list of all leaf (sub-class) labels; index = integer label.
- `hierarchy` — `{parent: [sub, ...]}` for hierarchical datasets, `None` for flat.

Called internally by `Trainer` when `dataset=` is supplied.

---

### `coldet.Trainer`

```python
Trainer(
    size="small",           # capacity tier
    speed_bias=0.5,         # float [0, 1]
    accuracy_bias=None,     # float [0, 1] — defaults to 1 - speed_bias
    dataset=None,           # path to dataset (either layout)
    image_size=224,
    batch_size=32,
    num_classes=1000,       # ignored when dataset= is supplied
    lr=1e-3,
    device=None,            # auto-detected (CUDA if available)
)
```

| Method | Description |
|--------|-------------|
| `train(dataloader=None, epochs=1, verbose=True)` | Train for N epochs. Returns list of epoch losses. Cosine annealing is applied automatically. |
| `summary(output_dir=".")` | Writes `sum.md` and `graph.png`. Returns info dict. |
| `predict(images)` | Forward pass, eval mode. `images` is `(B, 3, H, W)`. Returns `(B, num_classes)` logits. |
| `save(path)` | Save checkpoint as a `.coldet` file. |
| `load(path)` | Restore weights and training state into an already-constructed Trainer. |
| `Trainer.from_checkpoint(path, device=None)` | Class method. Reconstruct a complete Trainer from a `.coldet` file — no other arguments needed. |

#### `summary()` return value

```python
{
    'size_label':       'medium',
    'total_params':     214_832,
    'trainable_params': 214_832,
    'model_size_mb':    0.859,
    'speed_tier':       'balanced',
    'trained_epochs':   10,
    'num_classes':      5,
    'class_names':      ['blue', 'crimson', 'green', 'red', 'scarlet'],
    'hierarchy':        {'blue': ['blue'], 'green': ['green'], 'red': ['crimson', 'red', 'scarlet']},
    # hierarchy is None for flat datasets
}
```

#### `summary()` output files

| File | Contents |
|------|----------|
| `sum.md` | Constraints, parameter counts, class list (with parent column for hierarchical models), training history. |
| `graph.png` | Training loss curve. Written only after at least one epoch. |

---

### `coldet.infer`

```python
result = coldet.infer(
    image_path,          # str — path to image file
    model_path,          # str — path to .coldet file
    temperature=1.0,     # float > 0
    device=None,         # str or None
)
```

See the [Inference section](#inference--coldetinfer) above for full documentation.

---

### `coldet.build_model`

Lower-level function for the raw `nn.Module`:

```python
model = coldet.build_model(
    size="large",
    speed_bias=0.3,
    accuracy_bias=0.8,
    num_classes=10,
)
```

Returns a `torch.nn.Module`. Architecture is generated, not predefined.

---

## The `.coldet` file format

`.coldet` files are PyTorch checkpoints (readable with `torch.load`). They contain:

- Model weights and optimiser state.
- All constraint parameters (`size`, `speed_bias`, `accuracy_bias`, `lr`, `image_size`).
- The resolved architecture dict (so the model can be reconstructed exactly, even if the constraint-to-arch mapping ever changes).
- Class names and the hierarchy dict (if applicable).
- Full training loss history.

The extension `.coldet` is conventional. You can use any extension — `torch.save` / `torch.load` don't care.

---

## Constraint guide

| Goal | Recommended settings |
|------|----------------------|
| Edge / mobile deployment | `size="small"`, `speed_bias=0.9` |
| Balanced production model | `size="medium"`, `speed_bias=0.5` |
| Maximum accuracy, offline | `size="large"`, `speed_bias=0.1`, `accuracy_bias=0.9` |
| Rapid prototyping | `size="small"`, `speed_bias=0.7` |
| Hierarchical fine-grained recognition | `size="medium"`, `speed_bias=0.4` |

---

## What is hidden (intentionally)

coldet deliberately does not expose:

- Layer names, channel counts, or kernel sizes.
- Backbone / neck / head terminology.
- Depthwise vs standard convolution choices.
- Dropout values or batch norm parameters.

These are implementation details derived from your constraints. Exposing them would reintroduce the complexity the package is designed to remove.

---

## Philosophy

> **Describe constraints, not networks.**

Good abstractions hide decisions that don't belong to the user. Network architecture is an implementation concern — it should be derived from requirements, not specified by them. coldet treats the model as an *output* of a constraint-solving process, not an *input* from the user.

---

## License

MIT
