File size: 5,112 Bytes
3426645
ad83752
 
3426645
ad83752
3426645
ad83752
3426645
 
 
ad83752
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
---
title: Crop vs No Crop Segmentation
emoji: 🌾
colorFrom: green
colorTo: yellow
sdk: docker
app_port: 8501
pinned: false
---

# 🌾 Crop vs No-Crop Segmentation

A production-ready **Streamlit** app that performs **binary semantic
segmentation** with a fine-tuned **NVIDIA SegFormer-B2** model, deployed on
**Hugging Face Spaces** using the **Docker SDK**.

| Class | Meaning | Mask color |
|:-----:|---------|------------|
| 0 | Background / No Crop | Dark gray |
| 1 | Crop | Bright yellow |

Inference is CPU-optimized, so it runs on free Hugging Face Spaces.

---

## ✨ Features

- Upload `jpg` / `jpeg` / `png` images.
- One-click **Run Segmentation** with a progress spinner.
- **Three-panel output:** Original Β· Predicted Mask Β· Crop Overlay
  (semi-transparent magenta over crop regions), all at identical size.
- **Download Result** β€” exports all three panels combined horizontally as
  `prediction_result.png`.
- Model is loaded **once** via `@st.cache_resource`.
- Weights load from a **local `best.pt`** or directly from the
  **Hugging Face Hub**.
- Automatic **GPU/CPU** device selection; inference under `torch.no_grad()`.
- Friendly error handling for invalid/corrupted uploads, missing weights, and
  inference failures.

---

## 🧠 How the model is built

The architecture is rebuilt from the `nvidia/mit-b2` backbone config with
`num_labels=2`, and the fine-tuned weights are loaded on top:

```python
MODEL_NAME = "nvidia/mit-b2"
config = SegformerConfig.from_pretrained(MODEL_NAME, num_labels=2)
model = SegformerForSemanticSegmentation(config)
model.load_state_dict(torch.load("best.pt", map_location="cpu"), strict=False)
```

The checkpoint is expected to be a plain state dict:

```python
torch.save(model.state_dict(), "best.pt")
```

---

## πŸ“‚ Folder structure

```
crop-segmentation/
β”œβ”€β”€ app.py             # Streamlit UI + workflow
β”œβ”€β”€ predictor.py       # Model build (mit-b2) + best.pt loading + inference
β”œβ”€β”€ utils.py           # Image loading, mask/overlay/combine, PNG export
β”œβ”€β”€ requirements.txt   # Python dependencies
β”œβ”€β”€ Dockerfile         # HF Spaces Docker build (Python 3.10, CPU torch)
β”œβ”€β”€ README.md          # This file (with HF Spaces front matter)
β”œβ”€β”€ .gitignore
β”œβ”€β”€ .dockerignore
β”œβ”€β”€ best.pt            # Fine-tuned weights (provide your own)
└── assets/            # Screenshots / static assets
```

---

## πŸ’» Local installation

```bash
git clone <your-repo-url>
cd crop-segmentation

python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate

# CPU torch (optional but recommended for parity with deployment)
pip install torch==2.11.0 torchvision==0.26.0 \
    --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt

# Make sure best.pt is present, or set HF_REPO_ID (see below)
streamlit run app.py
```

Open http://localhost:8501.

### Loading weights

Two options, controlled by environment variables:

| Variable | Purpose |
|----------|---------|
| *(none)* | Use a local `best.pt` next to the app. |
| `HF_REPO_ID` | Download `best.pt` from this HF **model** repo, e.g. `your-username/crop-segformer-b2`. |
| `HF_TOKEN` | Token for a private weights repo (optional). |
| `INPUT_SIZE` | Square inference size (default `512`). |

```bash
export HF_REPO_ID="your-username/crop-segformer-b2"
streamlit run app.py
```

---

## πŸš€ Hugging Face Spaces deployment (Docker SDK)

1. Create a new Space β†’ **SDK: Docker**.
2. Push these files to the Space repository.
3. Provide the weights using **one** of:
   - **Commit `best.pt` to the Space** (use Git LFS for large files):
     ```bash
     git lfs install
     git lfs track "*.pt"
     git add .gitattributes best.pt
     git commit -m "Add weights"
     git push
     ```
   - **Load from a model repo** β€” in the Space **Settings β†’ Variables**, set
     `HF_REPO_ID` (and `HF_TOKEN` if private). No `best.pt` in the Space needed.
4. The `README.md` front matter pins `sdk: docker` and `app_port: 8501`, so the
   Space serves the Streamlit app on port 8501 automatically.

The Space will build the Docker image, install dependencies (CPU torch), and
launch:

```bash
streamlit run app.py --server.port=8501 --server.address=0.0.0.0
```

---

## πŸ–ΌοΈ Example screenshots

> Replace these placeholders with real screenshots in `assets/`.

| Upload | Results (3 panels) |
|--------|--------------------|
| `assets/screenshot_upload.png` | `assets/screenshot_results.png` |

---

## βš™οΈ Notes & assumptions

- Preprocessing: convert to RGB β†’ resize to `INPUT_SIZE` β†’ `ToTensor` β†’
  ImageNet normalization (`mean=[0.485,0.456,0.406]`, `std=[0.229,0.224,0.225]`).
  If your fine-tuning used different stats or size, set `INPUT_SIZE` and adjust
  `IMAGENET_MEAN`/`IMAGENET_STD` in `predictor.py` to match.
- Postprocessing: argmax over upsampled logits, resized back to the original
  image resolution.
- Weights are loaded with `strict=False` so minor key mismatches log a warning
  rather than crash; verify the warnings are empty for a correct checkpoint.