Skip to content
10 changes: 10 additions & 0 deletions trapdata/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@
MothClassifierPanama2024,
MothClassifierQuebecVermont,
MothClassifierTuringAnguilla,
MothClassifierTuringAnguillaV02,
MothClassifierTuringCostaRica,
MothClassifierTuringJapan,
MothClassifierTuringKenyaUganda,
MothClassifierTuringMadagascar,
MothClassifierTuringSingapore,
MothClassifierTuringThailand,
MothClassifierUKDenmark,
)
from .models.localization import APIMothDetector
Expand Down Expand Up @@ -59,7 +64,12 @@ async def lifespan(app: fastapi.FastAPI):
"uk_denmark_moths_2023": MothClassifierUKDenmark,
"costa_rica_moths_turing_2024": MothClassifierTuringCostaRica,
"anguilla_moths_turing_2024": MothClassifierTuringAnguilla,
"anguilla_moths_turing_v02_2024": MothClassifierTuringAnguillaV02,
"singapore_moths_turing_2024": MothClassifierTuringSingapore,
"thailand_moths_turing_2024": MothClassifierTuringThailand,
"madagascar_moths_turing_2024": MothClassifierTuringMadagascar,
"kenya-uganda_moths_turing_2024": MothClassifierTuringKenyaUganda,
"japan_moths_turing_2024": MothClassifierTuringJapan,
"global_moths_2024": MothClassifierGlobal,
"moth_binary": MothClassifierBinary,
"insect_orders_2025": InsectOrderClassifier,
Expand Down
31 changes: 31 additions & 0 deletions trapdata/api/models/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
PanamaMothSpeciesClassifierMixedResolution2023,
QuebecVermontMothSpeciesClassifier2024,
TuringAnguillaSpeciesClassifier,
TuringAnguillaV02SpeciesClassifier,
TuringCostaRicaSpeciesClassifier,
TuringJapanSpeciesClassifier,
TuringKenyaUgandaSpeciesClassifier,
TuringMadagascarSpeciesClassifier,
TuringSingaporeSpeciesClassifier,
TuringThailandSpeciesClassifier,
UKDenmarkMothSpeciesClassifier2024,
)

Expand Down Expand Up @@ -219,12 +224,38 @@ class MothClassifierTuringAnguilla(APIMothClassifier, TuringAnguillaSpeciesClass
pass


class MothClassifierTuringAnguillaV02(
APIMothClassifier, TuringAnguillaV02SpeciesClassifier
):
pass


class MothClassifierTuringJapan(APIMothClassifier, TuringJapanSpeciesClassifier):
pass


class MothClassifierTuringKenyaUganda(
APIMothClassifier, TuringKenyaUgandaSpeciesClassifier
):
pass


class MothClassifierTuringMadagascar(
APIMothClassifier, TuringMadagascarSpeciesClassifier
):
pass


class MothClassifierTuringThailand(APIMothClassifier, TuringThailandSpeciesClassifier):
pass
Comment on lines +249 to +250
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

MothClassifierTuringThailand is missing a disable comment — inconsistent with MothClassifierTuringSingapore.

Line 253 has # Disabled: category map not available at this time before MothClassifierTuringSingapore. MothClassifierTuringThailand has no equivalent notice, even though it's also disabled and — more critically — will raise a RuntimeError on model.load_state_dict() due to the 3822 vs. 3800 class-count mismatch if anyone instantiates it directly.

♻️ Suggested comment
+# Disabled: model weights have 3800 output neurons but category map lists 3822 classes;
+# state_dict load will fail with a size-mismatch RuntimeError until corrected data is available.
 class MothClassifierTuringThailand(APIMothClassifier, TuringThailandSpeciesClassifier):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class MothClassifierTuringThailand(APIMothClassifier, TuringThailandSpeciesClassifier):
pass
# Disabled: model weights have 3800 output neurons but category map lists 3822 classes;
# state_dict load will fail with a size-mismatch RuntimeError until corrected data is available.
class MothClassifierTuringThailand(APIMothClassifier, TuringThailandSpeciesClassifier):
pass
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trapdata/api/models/classification.py` around lines 249 - 250, Add a disable
comment above the MothClassifierTuringThailand class like the one used for
MothClassifierTuringSingapore to make its disabled state explicit and prevent
surprise errors; specifically note that this classifier is disabled because the
category map is not available and that attempting to instantiate it will raise a
RuntimeError in model.load_state_dict() due to a class-count mismatch (3822 vs.
3800). Place the comment immediately before the MothClassifierTuringThailand
class definition to mirror the existing pattern used for
MothClassifierTuringSingapore.



class MothClassifierTuringSingapore(
APIMothClassifier, TuringSingaporeSpeciesClassifier
):
pass


class MothClassifierGlobal(APIMothClassifier, GlobalMothSpeciesClassifier):
pass

Expand Down
41 changes: 41 additions & 0 deletions trapdata/ml/models/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,19 @@ class TuringAnguillaSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turi
)


class TuringAnguillaV02SpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Anguilla Species Classifier v02 (160 classes)"
description = "Trained on 19th November 2024 by Turing team using Resnet50 model. 160 classes."
weights_path = (
"https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/"
"turing-anguilla_v02_resnet50_2024-11-19-19-17_state.pt"
)
labels_path = (
"https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/"
"02_anguilla_data_category_map_160cls.json"
)


class TuringKenyaUgandaSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Kenya and Uganda Species Classifier"
description = "Trained on 19th November 2024 by Turing team using Resnet50 model."
Expand All @@ -435,6 +448,34 @@ class TuringKenyaUgandaSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_T
)


class TuringThailandSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Thailand Species Classifier"
description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-thailand_v01_resnet50_2024-11-21-16-28_state.pt"
Comment on lines +453 to +454
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inaccurate training dates in descriptions — Madagascar is significantly wrong.

Cross-referencing the description strings against the dates encoded in the weights_path filenames reveals mismatches:

Class Description date Filename date
TuringThailandSpeciesClassifier "11th November 2024" 2024-11-21 (21st Nov)
TuringMadagascarSpeciesClassifier "11th November 2024" 2024-07-01 (1st July 2024)
TuringJapanSpeciesClassifier "19th November 2024" 2024-11-22 (22nd Nov)

The Madagascar discrepancy is the most critical — the description is ~4 months off and contradicts the filename. Please verify with the Turing team and correct before merging.

📝 Proposed corrections
 class TuringThailandSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
     name = "Turing Thailand Species Classifier"
-    description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
+    description = "Trained on 21st November 2024 by Turing team using Resnet50 model."

 class TuringMadagascarSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
     name = "Turing Madagascar Species Classifier"
-    description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
+    description = "Trained on 1st July 2024 by Turing team using Resnet50 model."

 class TuringJapanSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
     name = "Turing Japan Species Classifier"
-    description = "Trained on 19th November 2024 by Turing team using Resnet50 model."
+    description = "Trained on 22nd November 2024 by Turing team using Resnet50 model."

Also applies to: 447-448, 454-455

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trapdata/ml/models/classification.py` around lines 440 - 441, The description
strings for the classifier classes TuringThailandSpeciesClassifier,
TuringMadagascarSpeciesClassifier, and TuringJapanSpeciesClassifier are
inconsistent with the dates encoded in their weights_path filenames; update each
class's description field to match the date in its weights_path (e.g., use
2024-11-21 for the Thailand model, 2024-07-01 for the Madagascar model, and
2024-11-22 for the Japan model), and confirm with the Turing team before
committing to ensure the corrected human-readable dates are accurate.

labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/01_thailand_data_category_map.json"
Comment on lines +451 to +455
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Thailand class is missing a disable note — unlike Singapore.

TuringSingaporeSpeciesClassifier has a clear 3-line # NOTE: block explaining why it's disabled and what's missing (lines 472–474). TuringThailandSpeciesClassifier has no equivalent, despite also being disabled — and for a more dangerous reason: the category map has 3822 classes but the model outputs 3800 neurons, so model.load_state_dict() will throw a size-mismatch RuntimeError on any attempt to instantiate this class.

🛡️ Suggested comment block
+# NOTE: Thailand model has a class-count mismatch: category map lists 3822 classes
+# but the model was trained with 3800 output neurons. Loading state_dict will fail
+# with a size-mismatch RuntimeError. Disabled until corrected weights or map is provided.
 class TuringThailandSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class TuringThailandSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Thailand Species Classifier"
description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-thailand_v01_resnet50_2024-11-21-16-28_state.pt"
labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/01_thailand_data_category_map.json"
# NOTE: Thailand model has a class-count mismatch: category map lists 3822 classes
# but the model was trained with 3800 output neurons. Loading state_dict will fail
# with a size-mismatch RuntimeError. Disabled until corrected weights or map is provided.
class TuringThailandSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Thailand Species Classifier"
description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-thailand_v01_resnet50_2024-11-21-16-28_state.pt"
labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/01_thailand_data_category_map.json"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@trapdata/ml/models/classification.py` around lines 451 - 455, Add a 3-line "#
NOTE:" comment block above the TuringThailandSpeciesClassifier declaration (like
the one above TuringSingaporeSpeciesClassifier) explaining that this classifier
is intentionally disabled because the labels file contains 3822 classes while
the Resnet50 model checkpoint has 3800 output neurons which causes
model.load_state_dict() to raise a size-mismatch RuntimeError; instruct
maintainers to not instantiate this class until the weights or labels are
corrected (or the checkpoint is replaced) and reference the class name
TuringThailandSpeciesClassifier and the failing call model.load_state_dict for
clarity.



class TuringMadagascarSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Madagascar Species Classifier"
description = "Trained on 11th November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-madagascar_v01_resnet50_2024-07-01-13-01_state.pt"
labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/01_madagascar_data_category_map.json"


class TuringJapanSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Japan Species Classifier"
description = "Trained on 19th November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-japan_v01_resnet50_2024-11-22-17-22_state.pt"
labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/01_japan_data_category_map.json"


class TuringSingaporeSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing Singapore Species Classifier"
description = "Trained on 21st November 2024 by Turing team using Resnet50 model."
weights_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/turing-singapore_v02_resnet50_2024-11-21-19-58_state.pt"
labels_path = "https://object-arbutus.cloud.computecanada.ca/ami-models/moths/classification/02_singapore_data_category_map.json"


class TuringUKSpeciesClassifier(SpeciesClassifier, Resnet50Classifier_Turing):
name = "Turing UK Species Classifier"
description = "Trained on 13th May 2024 by Turing team using Resnet50 model."
Expand Down