vimdhayak commited on
Commit
b25d9f6
·
verified ·
1 Parent(s): 1c5fd6a

Upload 5 files

Browse files
Files changed (3) hide show
  1. README.md +2 -41
  2. app.js +25 -5
  3. index.html +1 -1
README.md CHANGED
@@ -5,48 +5,9 @@ colorFrom: green
5
  colorTo: blue
6
  sdk: static
7
  app_file: index.html
8
- fullWidth: true
9
- header: mini
10
- short_description: Browser waste classification with MS-SE-EfficientNet-B0
11
- tags:
12
- - computer-vision
13
- - image-classification
14
- - waste-classification
15
- - efficientnet
16
- - onnx
17
- - browser-inference
18
  ---
19
 
20
  # MS-SE Waste Classifier
21
 
22
- A fully static Hugging Face Space for ten-class waste image classification. Inference runs locally in the visitor's browser through ONNX Runtime Web.
23
-
24
- ## Upload these files to the Space root
25
-
26
- ```text
27
- README.md
28
- index.html
29
- styles.css
30
- app.js
31
- ms_se_efficientnet_b0.onnx
32
- ```
33
-
34
- Do not place any file inside a subfolder.
35
-
36
- ## Model configuration
37
-
38
- - Architecture: MS-SE-EfficientNet-B0
39
- - Input: RGB image resized to 224 × 224
40
- - Normalization: ImageNet mean `[0.485, 0.456, 0.406]` and standard deviation `[0.229, 0.224, 0.225]`
41
- - Classes: battery, biological, cardboard, clothes, glass, metal, paper, plastic, shoes, trash
42
- - Runtime: ONNX Runtime Web with WebAssembly
43
-
44
- ## Local test
45
-
46
- Run a local web server from this folder:
47
-
48
- ```bash
49
- python -m http.server 8000
50
- ```
51
-
52
- Then open `http://localhost:8000`.
 
5
  colorTo: blue
6
  sdk: static
7
  app_file: index.html
8
+ pinned: false
 
 
 
 
 
 
 
 
 
9
  ---
10
 
11
  # MS-SE Waste Classifier
12
 
13
+ Browser-based waste image classification using MS-SE-EfficientNet-B0 and ONNX Runtime Web.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.js CHANGED
@@ -158,7 +158,7 @@ function renderModelFacts() {
158
  if (!state.metadata) return;
159
  const facts = [
160
  ['Input', `${state.metadata.input.width} × ${state.metadata.input.height} RGB`],
161
- ['Classes', String(state.metadata.classes.length)],
162
  ['Parameters', `${(state.metadata.complexity.parameters / 1e6).toFixed(3)}M`],
163
  ['Runtime', 'WebAssembly'],
164
  ];
@@ -199,11 +199,27 @@ async function initializeModel() {
199
  state.session = await ort.InferenceSession.create(modelBytes, {
200
  executionProviders: ['wasm'],
201
  graphOptimizationLevel: 'all',
202
- freeDimensionOverrides: { batch: 1 },
203
  });
204
 
205
- if (!state.session.inputNames.includes('input') || !state.session.outputNames.includes('logits')) {
206
- throw new Error(`Unexpected ONNX interface: inputs ${state.session.inputNames.join(', ')}, outputs ${state.session.outputNames.join(', ')}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
  state.modelReady = true;
@@ -404,7 +420,11 @@ async function predict() {
404
  const outputs = await state.session.run({ input: inputTensor });
405
  const inferenceEnd = performance.now();
406
 
407
- const logits = Array.from(outputs.logits.data);
 
 
 
 
408
  if (logits.length !== state.labels.length) {
409
  throw new Error(`Expected ${state.labels.length} logits but received ${logits.length}.`);
410
  }
 
158
  if (!state.metadata) return;
159
  const facts = [
160
  ['Input', `${state.metadata.input.width} × ${state.metadata.input.height} RGB`],
161
+ ['Classes', String(state.labels.length)],
162
  ['Parameters', `${(state.metadata.complexity.parameters / 1e6).toFixed(3)}M`],
163
  ['Runtime', 'WebAssembly'],
164
  ];
 
199
  state.session = await ort.InferenceSession.create(modelBytes, {
200
  executionProviders: ['wasm'],
201
  graphOptimizationLevel: 'all',
 
202
  });
203
 
204
+ const inputNames = Array.isArray(state.session.inputNames) ? state.session.inputNames : [];
205
+ const outputNames = Array.isArray(state.session.outputNames) ? state.session.outputNames : [];
206
+ if (!inputNames.includes('input') || !outputNames.includes('logits')) {
207
+ throw new Error(`Unexpected ONNX interface: inputs ${inputNames.join(', ') || 'none'}, outputs ${outputNames.join(', ') || 'none'}`);
208
+ }
209
+
210
+ // Run one deterministic smoke test before enabling the interface. This catches
211
+ // invalid model files, unsupported operators, and output-shape mismatches.
212
+ setProgress(92, 'Verifying model execution and output shape…');
213
+ const testData = new Float32Array(3 * APP.imageSize * APP.imageSize);
214
+ const testTensor = new ort.Tensor('float32', testData, [1, 3, APP.imageSize, APP.imageSize]);
215
+ const testOutputs = await state.session.run({ input: testTensor });
216
+ const testLogits = testOutputs.logits && testOutputs.logits.data;
217
+ if (!testLogits || testLogits.length !== state.labels.length) {
218
+ const actualLength = testLogits ? testLogits.length : 0;
219
+ throw new Error(`ONNX smoke test failed: expected ${state.labels.length} logits, received ${actualLength}.`);
220
+ }
221
+ if (!Array.from(testLogits).every(Number.isFinite)) {
222
+ throw new Error('ONNX smoke test failed: output contains non-finite values.');
223
  }
224
 
225
  state.modelReady = true;
 
420
  const outputs = await state.session.run({ input: inputTensor });
421
  const inferenceEnd = performance.now();
422
 
423
+ const outputTensor = outputs.logits;
424
+ if (!outputTensor || !outputTensor.data) {
425
+ throw new Error('The ONNX runtime did not return the expected logits output.');
426
+ }
427
+ const logits = Array.from(outputTensor.data);
428
  if (logits.length !== state.labels.length) {
429
  throw new Error(`Expected ${state.labels.length} logits but received ${logits.length}.`);
430
  }
index.html CHANGED
@@ -165,6 +165,6 @@
165
  <canvas id="preprocessCanvas" width="224" height="224" class="visually-hidden" aria-hidden="true"></canvas>
166
 
167
  <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0/dist/ort.min.js" crossorigin="anonymous"></script>
168
- <script src="app.js"></script>
169
  </body>
170
  </html>
 
165
  <canvas id="preprocessCanvas" width="224" height="224" class="visually-hidden" aria-hidden="true"></canvas>
166
 
167
  <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.27.0/dist/ort.min.js" crossorigin="anonymous"></script>
168
+ <script src="app.js?v=20260802-2"></script>
169
  </body>
170
  </html>