mshz88 commited on
Commit
01416c0
·
verified ·
1 Parent(s): ee395af

Add fp16→fp32 fallback for vision encoder WebGPU compatibility

Browse files
Files changed (2) hide show
  1. js/constants.js +154 -84
  2. js/model.js +31 -3
js/constants.js CHANGED
@@ -4,7 +4,10 @@
4
  * Ported from hf_space/constants.py.
5
  */
6
 
 
7
  // Prompts
 
 
8
  export const INTERPRET_PROMPT =
9
  "Provide a comprehensive clinical interpretation of this fetal ultrasound " +
10
  "image. Identify all visible anatomical structures, describe the fetal " +
@@ -21,7 +24,10 @@ export const CLASSIFY_PROMPT =
21
  "What anatomical view or structure does it show? " +
22
  'Return a JSON object with "label" as the classification.';
23
 
 
24
  // Classification -> Detection / Segmentation class mapping
 
 
25
  export const CLASSIFY_TO_DETECT = {
26
  huvf: "abdomen, arm, head, legs",
27
  huvb: "abdomen, arm, head, legs",
@@ -58,20 +64,39 @@ export const SPECIFIC_CLS_LABELS = new Set([
58
  "V sign", "X sign", "liver",
59
  ]);
60
 
61
- // Keyword-based mapping
 
 
 
62
  export const KEYWORD_FALLBACK = [
63
- [["cerebel","cervellet","ventric","thalm","bpd","banana","holopros","cisterna","fossa","csp","cavum","septum pellucidum","lateral ventricle"],"Brain, CSP, LV","Brain"],
64
- [["brain"],"Brain, CSP, LV","Brain"],
65
- [["cardiac","thorax","thorac","thoric","thorcic","aort","heart","stenos","chamber","valve"],"cardiac, thorax","cardiac, thorax"],
66
- [["fetal head","fetal_head","cervix","cervic","cervex","pubic","symphys","pelvimetr","angle of progression"],"fetal_head, pubic_symphysis","fetal_head, pubic_symphysis"],
67
- [["femur","femoral","fetal.femur","fetal-femur"],"legs",null],
68
- [["nasal","nuchal","translucen"],"NT, nasal_bone, nasal_skin, nasal_tip","NT"],
69
- [["crl","crown","rump"],"B, CRL, H, NB",null],
70
- [["liver","stomach","vein","artery"],"artery, liver, stomach, vein","artery, liver, stomach, vein"],
71
- [["abdomen","abdom"],"abdomen",null],
72
- [["arm"],"abdomen, arm",null],
73
- [["head"],"head",null],
74
- [["leg"],"abdomen, legs",null],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  ];
76
 
77
  export const DEFAULT_DETECT_CLASSES = "abdomen, arm, head, legs";
@@ -86,103 +111,145 @@ export function keywordLookup(text) {
86
  return null;
87
  }
88
 
89
- // Per-class keyword scoring
 
 
 
90
  export const FIELD_WEIGHTS = {
91
- biometric_measurements: 3.0, imaging_plane: 2.5,
92
- anatomical_structures: 1.0, fetal_orientation: 0.5,
93
- normality_assessment: 0.5, gestational_age: 0.3,
94
- image_quality: 0.0, clinical_recommendations: 0.3,
 
 
 
 
95
  };
96
 
97
  export const CLASS_KEYWORDS = {
98
- Brain:["brain","cerebr","cerebellum","cortex","vermis","falx","interhemispheric","cranial","intracranial","parieto-occipital","frontal lobe","occipital"],
99
- CSP:["septum pellucidum","cavum","csp","midline echo"],
100
- LV:["lateral ventricle","ventricl","choroid plexus","ventriculomegaly"],
101
- cardiac:["heart","cardiac","chamber","four chamber","4-chamber","valve","myocard","atri","foramen ovale","interventricular","aort","aortic"],
102
- thorax:["thorax","thorac","thoric","thorcic","chest","lung","pleural","rib cage","diaphragm","mediastin"],
103
- NT:["nuchal translucen","nuchal fold","nuchal"," nt "," nt,","nt_","nt "],
104
- nasal_bone:["nasal bone","nasal bridge"],
105
- nasal_skin:["nasal skin"],
106
- nasal_tip:["nasal tip"],
107
- CRL:["crown-rump","crown rump","crl"],
108
- B:[], H:[], NB:[],
109
- artery:["artery","arter","umbilical arter"],
110
- liver:["liver","hepat"],
111
- stomach:["stomach","gastric","stomach bubble"],
112
- vein:["vein","venous","vena cava","umbilical vein"],
113
- fetal_head:["cervix","cervic","cervical length"],
114
- pubic_symphysis:["pubic","symphys","pelvimetr"],
115
- abdomen:["abdomen","abdomin","abdom","ac_plane"],
116
- arm:["arm","upper limb","humerus"],
117
- head:["skull","calvar","biparietal","fetal head","head","neck"],
118
- legs:["femur","femoral","thigh","lower limb","lower extremit","tibia","legs","leg "],
 
 
 
 
 
 
 
 
 
 
119
  };
120
 
121
  export const CO_OCCURRENCE_GROUPS = [
122
- ["brain",["Brain","CSP","LV"],["Brain"],["nt_nasal"]],
123
- ["cardiac",["cardiac","thorax"],["cardiac","thorax"],[]],
124
- ["nt_nasal",["NT","nasal_bone","nasal_skin","nasal_tip"],["NT"],["brain","crl"]],
125
- ["crl",["B","CRL","H","NB"],null,["nt_nasal"]],
126
- ["doppler",["artery","liver","stomach","vein"],["artery","liver","stomach","vein"],[]],
127
- ["pelvimetry",["fetal_head","pubic_symphysis"],["fetal_head","pubic_symphysis"],[]],
128
- ["body_full",["abdomen","arm","head","legs"],null,[]],
129
- ["femur",["legs"],null,[]],
130
  ];
131
 
132
  export const GROUP_ALIASES = {
133
- brain:["bpd","biparietal"," hc ","head circumference","v sign","x sign","trans-thalamic","trans-cerebellar","transventricular","transcerebellar"],
134
- crl:["first trimester","dating scan","embryo","sagittal profile"],
135
- femur:[" fl ","femur length","fl_plane","fl plane","fl "],
136
- body_full:["abdominal circumference"," ac ","ac_plane","ac plane","fetal pose","body habitus","no_plane","no plane"],
137
- doppler:["doppler","flow","waveform","pulsatility","resistance index","stomach bubble","hepatic","ductus venosus","umbilical arter","umbilical vein"],
138
- nt_nasal:["first trimester screen","aneuploidy","trisomy","down syndrome"],
139
- pelvimetry:["pelvimetry","pelvic","birth canal","vaginal delivery"],
140
- cardiac:["echocardiogra","outflow tract","aortic arch","aorta"],
 
 
 
 
 
 
 
 
 
 
141
  };
142
 
143
  export const PLANE_TO_GROUP = {
144
- "trans-thalamic":"brain",transthalamic:"brain","trans-cerebellar":"brain",transcerebellar:"brain",
145
- transventricular:"brain",biparietal:"brain","four chamber":"cardiac","4-chamber":"cardiac",
146
- "4 chamber":"cardiac","outflow tract":"cardiac","three vessel":"cardiac",aortic:"cardiac",
147
- nuchal:"nt_nasal","longitudinal view of femur":"femur","femur length":"femur",
148
- "abdominal circumference":"body_full","ac plane":"body_full","crown-rump":"crl","crown rump":"crl",
149
- doppler:"doppler",waveform:"doppler","abdominal organ":"doppler","stomach bubble":"doppler",
150
- "cervical length":"pelvimetry",
 
 
 
 
 
 
151
  };
152
 
153
  export const NEGATIVE_MEASUREMENT_PATTERNS = [
154
- "not measurable","not visible","cannot be measured","unable to measure",
155
- "not assessed","not obtained","not clearly","inadequate",
 
156
  ];
157
 
 
158
  // Routing group map
 
 
159
  export const ROUTING_GROUP_MAP = {
160
- brain:["Brain, CSP, LV","Brain"],
161
- cardiac:["cardiac, thorax","cardiac, thorax"],
162
- nt_nasal:["NT, nasal_bone, nasal_skin, nasal_tip","NT"],
163
- crl:["B, CRL, H, NB",null],
164
- doppler:["artery, liver, stomach, vein","artery, liver, stomach, vein"],
165
- pelvimetry:["fetal_head, pubic_symphysis","fetal_head, pubic_symphysis"],
166
- body_pose:["abdomen, arm, head, legs",null],
167
- femur:["legs",null],
168
- crl_kp:["CRL_KP, ScaleBarKpoints",null],
169
- nt_kp:["NTKpoints, ScaleBarKpoints",null],
170
  };
171
 
172
- // Color palette
 
 
 
173
  const _RAW_PALETTE = [
174
- "#E6194B","#3CB44B","#FFE119","#4363D8","#F58231",
175
- "#911EB4","#42D4F4","#F032E6","#BFEF45","#FABED4",
176
- "#469990","#DCBEFF","#9A6324","#FFFAC8","#800000",
177
- "#AAFFC3","#808000","#FFD8B1","#000075","#A9A9A9",
178
  ];
179
 
180
  const ALL_CLASSES_SORTED = [
181
- "AB","B","Brain","C","CRL","CRL_KP","CSP","DP","G","H","LV",
182
- "MDS","MLS","MX","NB","NT","NTAPS","NTKpoints","RBP",
183
- "ScaleBar","ScaleBarKpoints",
184
- "abdomen","arm","artery","cardiac","fetal_head","head","legs","liver",
185
- "nasal_bone","nasal_skin","nasal_tip","pubic_symphysis","stomach","thorax","vein",
 
 
186
  ].sort();
187
 
188
  export const CLASS_COLORS = {};
@@ -192,7 +259,10 @@ ALL_CLASSES_SORTED.forEach((cls, i) => {
192
 
193
  export { _RAW_PALETTE };
194
 
 
195
  // Inference settings
 
 
196
  export const TEMPERATURE = 0.1;
197
  export const MAX_NEW_TOKENS = 1024;
198
  export const COORD_SCALE = 1000;
 
4
  * Ported from hf_space/constants.py.
5
  */
6
 
7
+ // ---------------------------------------------------------------------------
8
  // Prompts
9
+ // ---------------------------------------------------------------------------
10
+
11
  export const INTERPRET_PROMPT =
12
  "Provide a comprehensive clinical interpretation of this fetal ultrasound " +
13
  "image. Identify all visible anatomical structures, describe the fetal " +
 
24
  "What anatomical view or structure does it show? " +
25
  'Return a JSON object with "label" as the classification.';
26
 
27
+ // ---------------------------------------------------------------------------
28
  // Classification -> Detection / Segmentation class mapping
29
+ // ---------------------------------------------------------------------------
30
+
31
  export const CLASSIFY_TO_DETECT = {
32
  huvf: "abdomen, arm, head, legs",
33
  huvb: "abdomen, arm, head, legs",
 
64
  "V sign", "X sign", "liver",
65
  ]);
66
 
67
+ // ---------------------------------------------------------------------------
68
+ // Keyword-based mapping (ordered specific-first)
69
+ // ---------------------------------------------------------------------------
70
+
71
  export const KEYWORD_FALLBACK = [
72
+ [["cerebel", "cervellet", "ventric", "thalm", "bpd",
73
+ "banana", "holopros", "cisterna", "fossa", "csp", "cavum",
74
+ "septum pellucidum", "lateral ventricle"],
75
+ "Brain, CSP, LV", "Brain"],
76
+ [["brain"],
77
+ "Brain, CSP, LV", "Brain"],
78
+ [["cardiac", "thorax", "thorac", "thoric", "thorcic",
79
+ "aort", "heart", "stenos", "chamber", "valve"],
80
+ "cardiac, thorax", "cardiac, thorax"],
81
+ [["fetal head", "fetal_head", "cervix", "cervic", "cervex", "pubic", "symphys",
82
+ "pelvimetr", "angle of progression"],
83
+ "fetal_head, pubic_symphysis", "fetal_head, pubic_symphysis"],
84
+ [["femur", "femoral", "fetal.femur", "fetal-femur"],
85
+ "legs", null],
86
+ [["nasal", "nuchal", "translucen"],
87
+ "NT, nasal_bone, nasal_skin, nasal_tip", "NT"],
88
+ [["crl", "crown", "rump"],
89
+ "B, CRL, H, NB", null],
90
+ [["liver", "stomach", "vein", "artery"],
91
+ "artery, liver, stomach, vein", "artery, liver, stomach, vein"],
92
+ [["abdomen", "abdom"],
93
+ "abdomen", null],
94
+ [["arm"],
95
+ "abdomen, arm", null],
96
+ [["head"],
97
+ "head", null],
98
+ [["leg"],
99
+ "abdomen, legs", null],
100
  ];
101
 
102
  export const DEFAULT_DETECT_CLASSES = "abdomen, arm, head, legs";
 
111
  return null;
112
  }
113
 
114
+ // ---------------------------------------------------------------------------
115
+ // Per-class keyword scoring for interpretation-first mapping
116
+ // ---------------------------------------------------------------------------
117
+
118
  export const FIELD_WEIGHTS = {
119
+ biometric_measurements: 3.0,
120
+ imaging_plane: 2.5,
121
+ anatomical_structures: 1.0,
122
+ fetal_orientation: 0.5,
123
+ normality_assessment: 0.5,
124
+ gestational_age: 0.3,
125
+ image_quality: 0.0,
126
+ clinical_recommendations: 0.3,
127
  };
128
 
129
  export const CLASS_KEYWORDS = {
130
+ Brain: ["brain", "cerebr", "cerebellum", "cortex", "vermis",
131
+ "falx", "interhemispheric", "cranial", "intracranial",
132
+ "parieto-occipital", "frontal lobe", "occipital"],
133
+ CSP: ["septum pellucidum", "cavum", "csp", "midline echo"],
134
+ LV: ["lateral ventricle", "ventricl", "choroid plexus",
135
+ "ventriculomegaly"],
136
+ cardiac: ["heart", "cardiac", "chamber", "four chamber",
137
+ "4-chamber", "valve", "myocard", "atri",
138
+ "foramen ovale", "interventricular", "aort", "aortic"],
139
+ thorax: ["thorax", "thorac", "thoric", "thorcic", "chest",
140
+ "lung", "pleural", "rib cage", "diaphragm", "mediastin"],
141
+ NT: ["nuchal translucen", "nuchal fold", "nuchal",
142
+ " nt ", " nt,", "nt_", "nt "],
143
+ nasal_bone: ["nasal bone", "nasal bridge"],
144
+ nasal_skin: ["nasal skin"],
145
+ nasal_tip: ["nasal tip"],
146
+ CRL: ["crown-rump", "crown rump", "crl"],
147
+ B: [],
148
+ H: [],
149
+ NB: [],
150
+ artery: ["artery", "arter", "umbilical arter"],
151
+ liver: ["liver", "hepat"],
152
+ stomach: ["stomach", "gastric", "stomach bubble"],
153
+ vein: ["vein", "venous", "vena cava", "umbilical vein"],
154
+ fetal_head: ["cervix", "cervic", "cervical length"],
155
+ pubic_symphysis: ["pubic", "symphys", "pelvimetr"],
156
+ abdomen: ["abdomen", "abdomin", "abdom", "ac_plane"],
157
+ arm: ["arm", "upper limb", "humerus"],
158
+ head: ["skull", "calvar", "biparietal", "fetal head", "head", "neck"],
159
+ legs: ["femur", "femoral", "thigh", "lower limb",
160
+ "lower extremit", "tibia", "legs", "leg "],
161
  };
162
 
163
  export const CO_OCCURRENCE_GROUPS = [
164
+ ["brain", ["Brain", "CSP", "LV"], ["Brain"], ["nt_nasal"]],
165
+ ["cardiac", ["cardiac", "thorax"], ["cardiac", "thorax"], []],
166
+ ["nt_nasal", ["NT", "nasal_bone", "nasal_skin", "nasal_tip"], ["NT"], ["brain", "crl"]],
167
+ ["crl", ["B", "CRL", "H", "NB"], null, ["nt_nasal"]],
168
+ ["doppler", ["artery", "liver", "stomach", "vein"], ["artery", "liver", "stomach", "vein"], []],
169
+ ["pelvimetry", ["fetal_head", "pubic_symphysis"], ["fetal_head", "pubic_symphysis"], []],
170
+ ["body_full", ["abdomen", "arm", "head", "legs"], null, []],
171
+ ["femur", ["legs"], null, []],
172
  ];
173
 
174
  export const GROUP_ALIASES = {
175
+ brain: ["bpd", "biparietal", " hc ", "head circumference",
176
+ "v sign", "x sign", "trans-thalamic", "trans-cerebellar",
177
+ "transventricular", "transcerebellar"],
178
+ crl: ["first trimester", "dating scan", "embryo",
179
+ "sagittal profile"],
180
+ femur: [" fl ", "femur length", "fl_plane", "fl plane", "fl "],
181
+ body_full: ["abdominal circumference", " ac ", "ac_plane",
182
+ "ac plane", "fetal pose", "body habitus",
183
+ "no_plane", "no plane"],
184
+ doppler: ["doppler", "flow", "waveform", "pulsatility",
185
+ "resistance index", "stomach bubble",
186
+ "hepatic", "ductus venosus", "umbilical arter",
187
+ "umbilical vein"],
188
+ nt_nasal: ["first trimester screen", "aneuploidy", "trisomy",
189
+ "down syndrome"],
190
+ pelvimetry: ["pelvimetry", "pelvic", "birth canal",
191
+ "vaginal delivery"],
192
+ cardiac: ["echocardiogra", "outflow tract", "aortic arch", "aorta"],
193
  };
194
 
195
  export const PLANE_TO_GROUP = {
196
+ "trans-thalamic": "brain", transthalamic: "brain",
197
+ "trans-cerebellar": "brain", transcerebellar: "brain",
198
+ transventricular: "brain", biparietal: "brain",
199
+ "four chamber": "cardiac", "4-chamber": "cardiac",
200
+ "4 chamber": "cardiac", "outflow tract": "cardiac",
201
+ "three vessel": "cardiac", aortic: "cardiac",
202
+ nuchal: "nt_nasal",
203
+ "longitudinal view of femur": "femur", "femur length": "femur",
204
+ "abdominal circumference": "body_full", "ac plane": "body_full",
205
+ "crown-rump": "crl", "crown rump": "crl",
206
+ doppler: "doppler", waveform: "doppler",
207
+ "abdominal organ": "doppler", "stomach bubble": "doppler",
208
+ "cervical length": "pelvimetry",
209
  };
210
 
211
  export const NEGATIVE_MEASUREMENT_PATTERNS = [
212
+ "not measurable", "not visible", "cannot be measured",
213
+ "unable to measure", "not assessed", "not obtained",
214
+ "not clearly", "inadequate",
215
  ];
216
 
217
+ // ---------------------------------------------------------------------------
218
  // Routing group map
219
+ // ---------------------------------------------------------------------------
220
+
221
  export const ROUTING_GROUP_MAP = {
222
+ brain: ["Brain, CSP, LV", "Brain"],
223
+ cardiac: ["cardiac, thorax", "cardiac, thorax"],
224
+ nt_nasal: ["NT, nasal_bone, nasal_skin, nasal_tip", "NT"],
225
+ crl: ["B, CRL, H, NB", null],
226
+ doppler: ["artery, liver, stomach, vein", "artery, liver, stomach, vein"],
227
+ pelvimetry: ["fetal_head, pubic_symphysis", "fetal_head, pubic_symphysis"],
228
+ body_pose: ["abdomen, arm, head, legs", null],
229
+ femur: ["legs", null],
230
+ crl_kp: ["CRL_KP, ScaleBarKpoints", null],
231
+ nt_kp: ["NTKpoints, ScaleBarKpoints", null],
232
  };
233
 
234
+ // ---------------------------------------------------------------------------
235
+ // Color palette for annotation rendering
236
+ // ---------------------------------------------------------------------------
237
+
238
  const _RAW_PALETTE = [
239
+ "#E6194B", "#3CB44B", "#FFE119", "#4363D8", "#F58231",
240
+ "#911EB4", "#42D4F4", "#F032E6", "#BFEF45", "#FABED4",
241
+ "#469990", "#DCBEFF", "#9A6324", "#FFFAC8", "#800000",
242
+ "#AAFFC3", "#808000", "#FFD8B1", "#000075", "#A9A9A9",
243
  ];
244
 
245
  const ALL_CLASSES_SORTED = [
246
+ "AB", "B", "Brain", "C", "CRL", "CRL_KP", "CSP", "DP", "G", "H", "LV",
247
+ "MDS", "MLS", "MX", "NB", "NT", "NTAPS", "NTKpoints", "RBP",
248
+ "ScaleBar", "ScaleBarKpoints",
249
+ "abdomen", "arm", "artery", "cardiac",
250
+ "fetal_head", "head", "legs", "liver",
251
+ "nasal_bone", "nasal_skin", "nasal_tip",
252
+ "pubic_symphysis", "stomach", "thorax", "vein",
253
  ].sort();
254
 
255
  export const CLASS_COLORS = {};
 
259
 
260
  export { _RAW_PALETTE };
261
 
262
+ // ---------------------------------------------------------------------------
263
  // Inference settings
264
+ // ---------------------------------------------------------------------------
265
+
266
  export const TEMPERATURE = 0.1;
267
  export const MAX_NEW_TOKENS = 1024;
268
  export const COORD_SCALE = 1000;
js/model.js CHANGED
@@ -46,11 +46,17 @@ export async function loadModel(onProgress, device = "webgpu") {
46
  console.log(`[FADA] Loading model on device=${device}...`);
47
  activeDevice = device;
48
 
49
- model = await Qwen3_5ForConditionalGeneration.from_pretrained(MODEL_ID, {
 
 
 
 
 
 
50
  revision: MODEL_REVISION,
51
  dtype: {
52
  embed_tokens: "q4",
53
- vision_encoder: "fp16",
54
  decoder_model_merged: "q4",
55
  },
56
  device: device,
@@ -66,8 +72,30 @@ export async function loadModel(onProgress, device = "webgpu") {
66
  }
67
  },
68
  });
69
- console.log("[FADA] Model loaded successfully on", device);
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  onProgress?.({ status: "ready" });
72
  })();
73
 
 
46
  console.log(`[FADA] Loading model on device=${device}...`);
47
  activeDevice = device;
48
 
49
+ // Use fp32 for vision_encoder on WASM (no fp16 benefit) or try fp16 on WebGPU with fallback
50
+ const visionDtype = device === "wasm" ? "fp32" : "fp16";
51
+ if (device === "wasm") {
52
+ console.log("[FADA] WASM backend selected, using fp32 for vision encoder");
53
+ }
54
+
55
+ const buildModelConfig = (vDtype) => ({
56
  revision: MODEL_REVISION,
57
  dtype: {
58
  embed_tokens: "q4",
59
+ vision_encoder: vDtype,
60
  decoder_model_merged: "q4",
61
  },
62
  device: device,
 
72
  }
73
  },
74
  });
 
75
 
76
+ try {
77
+ model = await Qwen3_5ForConditionalGeneration.from_pretrained(
78
+ MODEL_ID,
79
+ buildModelConfig(visionDtype)
80
+ );
81
+ } catch (err) {
82
+ const isFp16Error =
83
+ visionDtype === "fp16" &&
84
+ err?.message?.toLowerCase().includes("does not support fp16");
85
+
86
+ if (isFp16Error) {
87
+ console.warn("[FADA] FP16 not supported on this device, retrying with FP32 vision encoder...");
88
+ onProgress?.({ status: "loading", file: "model", note: "FP16 not supported, loading vision encoder in FP32 mode..." });
89
+ model = await Qwen3_5ForConditionalGeneration.from_pretrained(
90
+ MODEL_ID,
91
+ buildModelConfig("fp32")
92
+ );
93
+ } else {
94
+ throw err;
95
+ }
96
+ }
97
+
98
+ console.log("[FADA] Model loaded successfully on", device);
99
  onProgress?.({ status: "ready" });
100
  })();
101