ibsocr1 commited on
Commit
12c9bf8
·
verified ·
1 Parent(s): 7c20709

Upload 5 files

Browse files
Files changed (2) hide show
  1. README.md +8 -203
  2. training/train.py +28 -74
README.md CHANGED
@@ -1,210 +1,15 @@
1
- ---
2
- title: Ice Cream Dataset + Counter
3
- emoji: 🍦
4
- colorFrom: yellow
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 6.5.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
 
12
- # 🍦 Ice Cream Dataset + Counter — Gradio Space
13
 
14
- This is the **Gradio + ZeroGPU-compatible** version of the uploaded Ice Cream Counter project. It does **not** use Docker, FastAPI, Uvicorn, or a custom HTML frontend.
15
 
16
- ## What it does
17
 
18
- 1. Upload training freezer photos.
19
- 2. Define your product classes.
20
- 3. Annotate each ice cream with bounding boxes.
21
- 4. Train an RT-DETR object detector.
22
- 5. Upload one new freezer image.
23
- 6. Get the total count, per-product counts, confidence scores, and an annotated result image.
24
 
25
- The model is still:
26
 
27
- `PekingU/rtdetr_r50vd`
28
 
29
- No YOLO is used.
30
-
31
- ## Create the Hugging Face Space
32
-
33
- Create a new Space and choose:
34
-
35
- - **SDK:** Gradio
36
- - **Hardware:** ZeroGPU or a dedicated GPU is recommended for training
37
-
38
- The app uses `@spaces.GPU` for training and counting, so it also boots correctly when the Space hardware is **ZeroGPU**.
39
-
40
- Then upload these files/folders:
41
-
42
- ```text
43
- app.py
44
- requirements.txt
45
- README.md
46
- training/
47
- ```
48
-
49
- You do **not** need:
50
-
51
- ```text
52
- Dockerfile
53
- FastAPI
54
- Uvicorn
55
- static/index.html
56
- app/main.py
57
- ```
58
-
59
- ## Persistent dataset and model
60
-
61
- The app stores:
62
-
63
- ```text
64
- images/
65
- dataset.json
66
- model/
67
- generated_dataset/
68
- ```
69
-
70
- When `/data` is available and writable, the app automatically uses:
71
-
72
- ```text
73
- /data/icecream_counter/
74
- ```
75
-
76
- You can also explicitly set:
77
-
78
- ```text
79
- DATA_DIR=/data/icecream_counter
80
- ```
81
-
82
- in the Space variables.
83
-
84
- ### Important Hugging Face storage point
85
-
86
- A normal Space filesystem is not permanent storage across every rebuild/restart. If you need the dataset and trained model to survive Space restarts/rebuilds, attach **persistent storage** to the Space or move the data/model to an external persistent service.
87
-
88
- The Gradio conversion itself does not change this storage rule.
89
-
90
- ## Annotation workflow
91
-
92
- In the **Annotate** tab the actual uploaded training image is displayed directly using Gradio's Image component. This avoids browser canvas/JavaScript issues that can make the preview appear black.
93
-
94
- 1. Select a training image.
95
- 2. The real image appears in the preview.
96
- 3. Read the image dimensions shown below it.
97
- 4. Select the product class.
98
- 5. Enter the bounding box in original-image pixel coordinates:
99
- - X (left)
100
- - Y (top)
101
- - Width
102
- - Height
103
- 6. Click **Save Box**.
104
- 7. Saved boxes are drawn in red on the real image.
105
- 8. Repeat for every ice cream.
106
- 9. Use **Delete Box** or **Clear All Boxes** when needed.
107
-
108
- This version prioritizes a reliable visible image over the previous JavaScript canvas approach.
109
-
110
- ## Training
111
-
112
- The app creates an 80/20 COCO train/validation split from the annotated images and starts the existing RT-DETR training script.
113
-
114
- Default settings:
115
-
116
- ```text
117
- Epochs: 30
118
- Batch size: 2
119
- Learning rate: 1e-5
120
- ```
121
-
122
- For an initial test on a small dataset, use fewer epochs such as 2–5. Once everything works, increase the epochs.
123
-
124
- A GPU Space is strongly recommended.
125
-
126
-
127
- ## Training fix
128
-
129
- This release includes a CUDA-device fix for RT-DETR's contrastive-denoising training path. On some
130
- Transformers/PyTorch combinations, the denoising class-index tensor can remain on CPU while the
131
- RT-DETR class embedding is on CUDA, producing:
132
-
133
- `RuntimeError: Expected all tensors to be on the same device ... cpu ... cuda:0`
134
-
135
- The training script now moves nested target tensors explicitly and patches the RT-DETR denoising
136
- helper so its target tensors follow the class-embedding device. The `num_labels=10` vs. checkpoint
137
- `80` message is expected when fine-tuning the COCO-pretrained checkpoint for 10 custom classes;
138
- `ignore_mismatched_sizes=True` intentionally reinitializes the classification heads.
139
-
140
- ## Counting
141
-
142
- After training, open the **Count** tab and upload one image.
143
-
144
- The result contains:
145
-
146
- ```json
147
- {
148
- "total": 31,
149
- "counts": {
150
- "cone": 6,
151
- "correto": 7,
152
- "cornetto": 12,
153
- "magnum": 6
154
- }
155
- }
156
- ```
157
-
158
- The result image also shows the detected bounding boxes and confidence values.
159
-
160
- ## Default classes
161
-
162
- ```text
163
- cornetto
164
- magnum
165
- correto
166
- cone
167
- cup
168
- sandwich
169
- stick
170
- other
171
- ```
172
-
173
- You can change them from the Dataset tab.
174
-
175
- ## Local test
176
-
177
- ```bash
178
- pip install -r requirements.txt
179
- python app.py
180
- ```
181
-
182
- Then open:
183
-
184
- ```text
185
- http://localhost:7860
186
- ```
187
-
188
- ## Recommended Space setup
189
-
190
- For the first deployment:
191
-
192
- 1. Create the Space as **Gradio**.
193
- 2. Upload `app.py`, `requirements.txt`, `README.md`, and `training/`.
194
- 3. Wait for dependencies to install.
195
- 4. Open the Dataset tab.
196
- 5. Upload 2+ training images.
197
- 6. Annotate them.
198
- 7. Start with 2–5 epochs to verify training.
199
- 8. After the model finishes, test the Count tab.
200
- 9. For serious training, attach a GPU and persistent storage.
201
-
202
-
203
-
204
- ### RT-DETR training compatibility
205
- The trainer disables RT-DETR contrastive denoising by default because some Transformers releases can create CPU class-index tensors while the embedding is on CUDA. The detector's normal supervised detection loss remains enabled. A device-safe denoising patch is also included for future re-enablement.
206
-
207
-
208
- ## Fixed22 training patch
209
-
210
- This version fixes the RT-DETR CPU/CUDA denoising crash by wrapping the denoising class embedding as a real `torch.nn.Module` and moving its index tensor to the embedding weight device before `nn.Embedding` is called. A plain Python function wrapper is intentionally not used because Transformers expects the embedding to remain a module.
 
1
+ # Ice Cream Counter Annotator — Fixed23
 
 
 
 
 
 
 
 
 
2
 
3
+ This version fixes the RT-DETR training crash:
4
 
5
+ `RuntimeError: Expected all tensors to be on the same device, but got index is on cpu, different from other tensors on cuda:0`
6
 
7
+ The issue occurs in Hugging Face RT-DETR's optional contrastive denoising path. Fixed23 disables that auxiliary path **before model construction** and also replaces the helper with the official `(None, None, None, None)` no-denoising return as a final safeguard.
8
 
9
+ The normal RT-DETR detector loss and 10-class fine-tuning remain enabled.
 
 
 
 
 
10
 
11
+ The `80 -> 10` checkpoint shape messages are expected when adapting the COCO checkpoint to 10 custom classes.
12
 
13
+ ## Install
14
 
15
+ Replace the files in the Hugging Face Space with this ZIP and restart/rebuild the Space.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/train.py CHANGED
@@ -6,7 +6,7 @@ import torch
6
  from PIL import Image
7
  from torch.utils.data import Dataset, DataLoader
8
  from tqdm import tqdm
9
- from transformers import RTDetrImageProcessor, RTDetrForObjectDetection
10
 
11
  BASE_MODEL = "PekingU/rtdetr_r50vd"
12
 
@@ -88,70 +88,21 @@ def evaluate(model, loader, device):
88
 
89
 
90
  def patch_rtdetr_denoising_device():
91
- """Patch RT-DETR denoising so embedding indices are always on the embedding device.
92
 
93
- Important: the wrapper must be an nn.Module, not a plain Python function.
94
- Transformers may inspect/use class_embed as a module, and a plain function
95
- loses the original module parameters/device information.
96
  """
97
- try:
98
- import transformers.models.rt_detr.modeling_rt_detr as rtdetr_mod
99
- import torch.nn as nn
100
-
101
- original = rtdetr_mod.get_contrastive_denoising_training_group
102
- if getattr(original, "_icecream_device_patch", False):
103
- return
104
-
105
- class DeviceSafeEmbedding(nn.Module):
106
- def __init__(self, embedding):
107
- super().__init__()
108
- self.embedding = embedding
109
-
110
- def forward(self, indices):
111
- if torch.is_tensor(indices):
112
- indices = indices.to(self.embedding.weight.device)
113
- return self.embedding(indices)
114
-
115
- def wrapped(targets, num_classes, num_queries, class_embed,
116
- num_denoising_queries=100, label_noise_ratio=0.5,
117
- box_noise_scale=1.0, **kwargs):
118
- # Move every target tensor to the embedding/model device.
119
- try:
120
- embed_device = class_embed.weight.device
121
- except Exception:
122
- try:
123
- embed_device = next(class_embed.parameters()).device
124
- except Exception:
125
- embed_device = None
126
-
127
- if embed_device is not None:
128
- fixed_targets = []
129
- for target in targets:
130
- if isinstance(target, dict):
131
- target = dict(target)
132
- for key, value in list(target.items()):
133
- if torch.is_tensor(value):
134
- target[key] = value.to(embed_device)
135
- fixed_targets.append(target)
136
- targets = fixed_targets
137
- class_embed = DeviceSafeEmbedding(class_embed)
138
-
139
- return original(
140
- targets=targets,
141
- num_classes=num_classes,
142
- num_queries=num_queries,
143
- class_embed=class_embed,
144
- num_denoising_queries=num_denoising_queries,
145
- label_noise_ratio=label_noise_ratio,
146
- box_noise_scale=box_noise_scale,
147
- **kwargs,
148
- )
149
-
150
- wrapped._icecream_device_patch = True
151
- rtdetr_mod.get_contrastive_denoising_training_group = wrapped
152
- print("RT-DETR denoising device patch installed")
153
- except Exception as exc:
154
- raise RuntimeError(f"Could not install RT-DETR denoising device patch: {exc}") from exc
155
 
156
  def main():
157
  p=argparse.ArgumentParser()
@@ -175,22 +126,25 @@ def main():
175
  if len(train.category_id_to_label)!=len(classes) or len(val.category_id_to_label)!=len(classes):
176
  raise ValueError("COCO categories do not match classes.txt. Rebuild the dataset after saving the classes.")
177
 
 
 
 
 
 
 
 
 
 
 
178
  model=RTDetrForObjectDetection.from_pretrained(
179
- BASE_MODEL,num_labels=len(classes),id2label=id2label,label2id=label2id,
180
  ignore_mismatched_sizes=True
181
  )
182
- # Some Transformers RT-DETR releases enter the denoising path whenever
183
- # training, regardless of num_denoising. Keep the config disabled where
184
- # supported, but also install the device-safe embedding patch below.
185
- for cfg_owner in (model, getattr(model, "model", None)):
186
- cfg = getattr(cfg_owner, "config", None)
187
- if cfg is not None:
188
- for name in ("num_denoising", "num_denoising_queries"):
189
- if hasattr(cfg, name):
190
- setattr(cfg, name, 0)
191
  device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
192
  model.to(device)
193
- patch_rtdetr_denoising_device()
194
 
195
  tr=DataLoader(train,batch_size=a.batch_size,shuffle=True,num_workers=0,collate_fn=collate_fn)
196
  va=DataLoader(val,batch_size=a.batch_size,shuffle=False,num_workers=0,collate_fn=collate_fn)
 
6
  from PIL import Image
7
  from torch.utils.data import Dataset, DataLoader
8
  from tqdm import tqdm
9
+ from transformers import RTDetrImageProcessor, RTDetrForObjectDetection, RTDetrConfig
10
 
11
  BASE_MODEL = "PekingU/rtdetr_r50vd"
12
 
 
88
 
89
 
90
  def patch_rtdetr_denoising_device():
91
+ """Disable RT-DETR contrastive denoising completely.
92
 
93
+ The installed Transformers build is entering the denoising helper even
94
+ though the training targets are on CUDA. Denoising is auxiliary to the
95
+ detector loss, so return the official no-denoising tuple directly.
96
  """
97
+ import transformers.models.rt_detr.modeling_rt_detr as rtdetr_mod
98
+
99
+ def disabled_denoising(*args, **kwargs):
100
+ return None, None, None, None
101
+
102
+ disabled_denoising._icecream_denoising_disabled = True
103
+ rtdetr_mod.get_contrastive_denoising_training_group = disabled_denoising
104
+ print("RT-DETR contrastive denoising DISABLED")
105
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  def main():
108
  p=argparse.ArgumentParser()
 
126
  if len(train.category_id_to_label)!=len(classes) or len(val.category_id_to_label)!=len(classes):
127
  raise ValueError("COCO categories do not match classes.txt. Rebuild the dataset after saving the classes.")
128
 
129
+ # Build from a config with denoising disabled BEFORE model construction.
130
+ cfg = RTDetrConfig.from_pretrained(BASE_MODEL)
131
+ if hasattr(cfg, "num_denoising"):
132
+ cfg.num_denoising = 0
133
+ if hasattr(cfg, "num_denoising_queries"):
134
+ cfg.num_denoising_queries = 0
135
+ cfg.num_labels = len(classes)
136
+ cfg.id2label = id2label
137
+ cfg.label2id = label2id
138
+
139
  model=RTDetrForObjectDetection.from_pretrained(
140
+ BASE_MODEL, config=cfg,
141
  ignore_mismatched_sizes=True
142
  )
143
+ # Belt-and-suspenders: if this Transformers build still calls the helper,
144
+ # return the official no-denoising tuple instead of entering F.embedding.
145
+ patch_rtdetr_denoising_device()
 
 
 
 
 
 
146
  device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
147
  model.to(device)
 
148
 
149
  tr=DataLoader(train,batch_size=a.batch_size,shuffle=True,num_workers=0,collate_fn=collate_fn)
150
  va=DataLoader(val,batch_size=a.batch_size,shuffle=False,num_workers=0,collate_fn=collate_fn)