Skip to content

Commit 40539dd

Browse files
authored
Merge pull request #39 from allenai/josh/claude/fishing-buoy-name-allow
Allow Fishing ship type with buoyish name as a buoy
2 parents 4ee3b59 + aa16427 commit 40539dd

2 files changed

Lines changed: 93 additions & 2 deletions

File tree

ais/src/atlantes/inference/atlas_entity/postprocessor.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ def _init_metrics(self) -> None:
7474
"Not enough messages",
7575
)
7676

77+
self.fishing_buoy_name_allowed_rule_applied = Counter(
78+
"entity_post_processed_fishing_buoy_name_allowed",
79+
"Buoyish name with a Fishing ship type allowed through as a buoy",
80+
)
81+
7782
def is_binned_ship_type_known(self, binned_ship_type: int) -> bool:
7883
"""Check if the ship type is known"""
7984
if binned_ship_type not in self.ais_categories["category"].values:
@@ -86,6 +91,20 @@ def is_binned_ship_type_known(self, binned_ship_type: int) -> bool:
8691
)
8792
return binned_ship_type != unknown_category
8893

94+
def is_binned_ship_type_fishing(self, binned_ship_type: int) -> bool:
95+
"""Check if the binned ship type is Fishing.
96+
97+
A lot of fishing gear (buoys, nets, FADs) reports a Fishing ship type, so a
98+
buoyish name paired with a Fishing ship type is expected rather than a conflict."""
99+
if binned_ship_type not in self.ais_categories["category"].values:
100+
raise ValueError(f"Unknown ship type {binned_ship_type=}")
101+
fishing_category = int(
102+
self.ais_categories[self.ais_categories["category_desc"] == "Fishing"][
103+
"category"
104+
].iloc[0]
105+
)
106+
return binned_ship_type == fishing_category
107+
89108
def check_confidence_threshold(
90109
self, confidence: float, predicted_class: AtlasEntityLabelsTrainingWithUnknown
91110
) -> tuple[bool, AtlasEntityLabelsTrainingWithUnknown]:
@@ -126,19 +145,26 @@ def postprocess(
126145
)
127146
binned_ship_type = int(metadata.binned_ship_type)
128147
is_buoy_name = is_buoy_based_on_name(metadata.mmsi, metadata.entity_name)
129-
# TODO: Ask SME if Fishing reporting vessels can be buoys
130148
is_known_binned_ship_type = self.is_binned_ship_type_known(binned_ship_type)
149+
# A lot of fishing gear reports a Fishing ship type, so a buoyish name with a
150+
# Fishing ship type is allowed through and classified as a buoy rather than raising.
151+
is_fishing_binned_ship_type = self.is_binned_ship_type_fishing(binned_ship_type)
131152
has_not_enough_messages = (
132153
metadata.track_length < self.data_config["MIN_AIS_MESSAGES"]
133154
)
134155

135156
# Postprocessing Rules
136-
if is_buoy_name and is_known_binned_ship_type:
157+
if is_buoy_name and is_known_binned_ship_type and not is_fishing_binned_ship_type:
137158
logger.error(
138159
f"known ship type and buoyish name {binned_ship_type=}, {metadata.entity_name=}"
139160
)
140161
raise KnownShipTypeAndBuoyName()
141162
elif was_post_processed := is_buoy_name:
163+
if is_fishing_binned_ship_type and is_known_binned_ship_type:
164+
logger.info(
165+
f"Fishing ship type with buoyish name allowed through as buoy {metadata.entity_name=}"
166+
)
167+
self.fishing_buoy_name_allowed_rule_applied.inc()
142168
logger.info(f"Buoyish name {metadata.entity_name=}")
143169
self.buoy_post_processed_rule_applied.inc()
144170
postprocessed_entity_class = AtlasEntityLabelsTrainingWithUnknown.BUOY

ais/tests/unit/inference/atlas_entity/test_unit_entity_postprocessor.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,3 +812,68 @@ def test_postprocess_raises_error_for_known_binned_ship_type_and_buoy_name(
812812
entity_postprocessor_class.postprocess(
813813
entity_outputs_with_details_metadata_tuples_1
814814
)
815+
816+
def test_is_binned_ship_type_fishing(
817+
self, entity_postprocessor_class: AtlasEntityPostProcessor
818+
) -> None:
819+
"""The Fishing category (2) is fishing; other known categories are not."""
820+
assert entity_postprocessor_class.is_binned_ship_type_fishing(2)
821+
assert not entity_postprocessor_class.is_binned_ship_type_fishing(8)
822+
823+
def test_postprocess_fishing_ship_type_and_buoy_name_allowed_as_buoy(
824+
self, entity_postprocessor_class: AtlasEntityPostProcessor
825+
) -> None:
826+
"""A Fishing ship type with a buoyish name is allowed through as a buoy.
827+
828+
A lot of fishing gear reports a Fishing ship type, so this pairing must not
829+
raise KnownShipTypeAndBuoyName the way other known ship types do."""
830+
fishing_binned_ship_type = 2
831+
entity_outputs_with_details_metadata_tuples_1 = EntityPostprocessorInput(
832+
predicted_class=AtlasEntityLabelsTrainingWithUnknown.VESSEL,
833+
entity_classification_details=EntityPostprocessorInputDetails(
834+
model="test", confidence=0.9, outputs=[0.9, 0.1]
835+
),
836+
metadata=EntityMetadata(
837+
binned_ship_type=fishing_binned_ship_type,
838+
mmsi="123456789",
839+
entity_name="Net-18%",
840+
track_length=800,
841+
file_location=None,
842+
trackId="B:123456789",
843+
flag_code="USA",
844+
ais_type=30,
845+
),
846+
)
847+
output = entity_postprocessor_class.postprocess(
848+
entity_outputs_with_details_metadata_tuples_1
849+
)
850+
assert output.entity_class == "buoy"
851+
assert output.entity_classification_details.postprocess_rule_applied is True
852+
853+
def test_postprocess_fishing_ais_type_and_buoy_name_allowed_as_buoy(
854+
self, entity_postprocessor_class: AtlasEntityPostProcessor
855+
) -> None:
856+
"""The Fishing exception also applies when the type is binned from ais_type=30.
857+
858+
Mirrors the production case (WIN 6+, ais_type 30) that previously raised."""
859+
entity_outputs_with_details_metadata_tuples_1 = EntityPostprocessorInput(
860+
predicted_class=AtlasEntityLabelsTrainingWithUnknown.VESSEL,
861+
entity_classification_details=EntityPostprocessorInputDetails(
862+
model="test", confidence=0.9, outputs=[0.9, 0.1]
863+
),
864+
metadata=EntityMetadata(
865+
binned_ship_type=None,
866+
mmsi="674118012",
867+
entity_name="Net-18%",
868+
track_length=800,
869+
file_location=None,
870+
trackId="B:674118012",
871+
flag_code="USA",
872+
ais_type=30,
873+
),
874+
)
875+
output = entity_postprocessor_class.postprocess(
876+
entity_outputs_with_details_metadata_tuples_1
877+
)
878+
assert output.entity_class == "buoy"
879+
assert output.entity_classification_details.postprocess_rule_applied is True

0 commit comments

Comments
 (0)