Skip to content

Commit 408d284

Browse files
authored
[CVAT] Update honeypot use logic (#2909)
* Update honeypot reroll algorithm * Add bag-based honeypot caching * Update gt reroll approach * Allow to limit max gt size in recording oracle * Update poetry.lock * Update tests, refactor code, add handling for gt size limits * Bump human sdk to 3.0.8b0 * Add annotation speed checks * Fix rng use * fix warmup progress check * Fix warmup checks * Allow 1 warmup iterations * Update .env template * Don't fail honeypot reroll in unsupported cases with multiple labels, skip honeypot reroll instead * Disable gt limiting for unsupported cases instead of disabling honeypot changes * Refactor grouped()
1 parent 6271fb8 commit 408d284

File tree

13 files changed

+758
-403
lines changed

13 files changed

+758
-403
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
"""Update GT stats with total_uses field
2+
3+
Revision ID: 76f0bc042477
4+
Revises: 9d4367899f90
5+
Create Date: 2024-12-12 18:14:43.885249
6+
7+
"""
8+
9+
import sqlalchemy as sa
10+
from sqlalchemy import Column, ForeignKey, Integer, String, update
11+
from sqlalchemy.orm import declarative_base
12+
13+
from alembic import op
14+
15+
# revision identifiers, used by Alembic.
16+
revision = "76f0bc042477"
17+
down_revision = "9d4367899f90"
18+
branch_labels = None
19+
depends_on = None
20+
21+
Base = declarative_base()
22+
23+
24+
class GtStats(Base):
25+
__tablename__ = "gt_stats"
26+
27+
# A composite primary key is used
28+
task_id = Column(
29+
String, ForeignKey("tasks.id", ondelete="CASCADE"), primary_key=True, nullable=False
30+
)
31+
gt_frame_name = Column(String, primary_key=True, nullable=False)
32+
33+
failed_attempts = Column(Integer, default=0, nullable=False)
34+
accepted_attempts = Column(Integer, default=0, nullable=False)
35+
total_uses = Column(Integer, default=0, nullable=False)
36+
37+
38+
def upgrade() -> None:
39+
# ### commands auto generated by Alembic - please adjust! ###
40+
op.add_column(
41+
"gt_stats", sa.Column("total_uses", sa.Integer(), nullable=False, server_default="0")
42+
)
43+
op.add_column(
44+
"gt_stats", sa.Column("enabled", sa.Boolean(), nullable=False, server_default="True")
45+
)
46+
# ### end Alembic commands ###
47+
48+
op.execute(
49+
update(GtStats).values(total_uses=GtStats.accepted_attempts + GtStats.failed_attempts)
50+
)
51+
52+
op.alter_column("gt_stats", "total_uses", server_default=None)
53+
op.alter_column("gt_stats", "enabled", server_default=None)
54+
55+
56+
def downgrade() -> None:
57+
# ### commands auto generated by Alembic - please adjust! ###
58+
op.drop_column("gt_stats", "total_uses")
59+
op.drop_column("gt_stats", "enabled")
60+
# ### end Alembic commands ###

packages/examples/cvat/recording-oracle/src/.env.template

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ ENABLE_CUSTOM_CLOUD_HOST=
7676

7777
# Validation
7878

79-
DEFAULT_POINT_VALIDITY_RELATIVE_RADIUS=
80-
DEFAULT_OKS_SIGMA=
81-
GT_FAILURE_THRESHOLD=
79+
MIN_AVAILABLE_GT_THRESHOLD=
80+
MAX_USABLE_GT_SHARE=
8281
GT_BAN_THRESHOLD=
8382
UNVERIFIABLE_ASSIGNMENTS_THRESHOLD=
8483
MAX_ESCROW_ITERATIONS=
84+
WARMUP_ITERATIONS=
85+
MIN_WARMUP_PROGRESS=
8586

8687
# Encryption
8788
PGP_PRIVATE_KEY=

packages/examples/cvat/recording-oracle/src/core/config.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -165,43 +165,51 @@ class FeaturesConfig:
165165

166166

167167
class ValidationConfig:
168-
default_point_validity_relative_radius = float(
169-
os.environ.get("DEFAULT_POINT_VALIDITY_RELATIVE_RADIUS", 0.9)
170-
)
171-
172-
default_oks_sigma = float(
173-
os.environ.get("DEFAULT_OKS_SIGMA", 0.1) # average value for COCO points
174-
)
175-
"Default OKS sigma for GT skeleton points validation. Valid range is (0; 1]"
168+
min_available_gt_threshold = float(os.environ.get("MIN_AVAILABLE_GT_THRESHOLD", "0.3"))
169+
"""
170+
The minimum required share of available GT frames required to continue annotation attempts.
171+
When there is no enough GT left, annotation stops.
172+
"""
176173

177-
gt_failure_threshold = float(os.environ.get("GT_FAILURE_THRESHOLD", 0.9))
174+
max_gt_share = float(os.environ.get("MAX_USABLE_GT_SHARE", "0.05"))
178175
"""
179-
The maximum allowed fraction of failed assignments per GT sample,
180-
before it's considered failed for the current validation iteration.
181-
v = 0 -> any GT failure leads to image failure
182-
v = 1 -> any GT failures do not lead to image failure
176+
The maximum share of the dataset to be used for validation. If the available GT share is
177+
greater than this number, the extra frames will not be used. It's recommended to keep this
178+
value small enough for faster convergence rate of the annotation process.
183179
"""
184180

185-
gt_ban_threshold = int(os.environ.get("GT_BAN_THRESHOLD", 3))
181+
gt_ban_threshold = float(os.environ.get("GT_BAN_THRESHOLD", "0.03"))
186182
"""
187-
The maximum allowed number of failures per GT sample before it's excluded from validation
183+
The minimum allowed rating (annotation probability) per GT sample,
184+
before it's considered bad and banned for further use.
188185
"""
189186

190187
unverifiable_assignments_threshold = float(
191-
os.environ.get("UNVERIFIABLE_ASSIGNMENTS_THRESHOLD", 0.1)
188+
os.environ.get("UNVERIFIABLE_ASSIGNMENTS_THRESHOLD", "0.1")
192189
)
193190
"""
194191
The maximum allowed fraction of jobs with insufficient GT available for validation.
195192
Each such job will be accepted "blindly", as we can't validate the annotations.
196193
"""
197194

198-
max_escrow_iterations = int(os.getenv("MAX_ESCROW_ITERATIONS", "0"))
195+
max_escrow_iterations = int(os.getenv("MAX_ESCROW_ITERATIONS", "50"))
199196
"""
200197
Maximum escrow annotation-validation iterations.
201198
After this, the escrow is finished automatically.
202199
Supposed only for testing. Use 0 to disable.
203200
"""
204201

202+
warmup_iterations = int(os.getenv("WARMUP_ITERATIONS", "1"))
203+
"""
204+
The first escrow iterations where the annotation speed is checked to be big enough.
205+
"""
206+
207+
min_warmup_progress = float(os.getenv("MIN_WARMUP_PROGRESS", "10"))
208+
"""
209+
Minimum percent of the accepted jobs in an escrow after the first WARMUP iterations.
210+
If the value is lower, the escrow annotation is paused for manual investigation.
211+
"""
212+
205213

206214
class EncryptionConfig(_BaseConfig):
207215
pgp_passphrase = os.environ.get("PGP_PASSPHRASE", "")

packages/examples/cvat/recording-oracle/src/core/gt_stats.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ class ValidationFrameStats:
66
accumulated_quality: float = 0.0
77
failed_attempts: int = 0
88
accepted_attempts: int = 0
9+
total_uses: int = 0
10+
enabled: bool = True
911

1012
@property
11-
def average_quality(self) -> float:
12-
return self.accumulated_quality / ((self.failed_attempts + self.accepted_attempts) or 1)
13+
def rating(self) -> float:
14+
return (self.accepted_attempts + 1) / (self.total_uses + 1)
1315

1416

15-
_TaskIdValFrameIdPair = tuple[int, int]
16-
17-
GtStats = dict[_TaskIdValFrameIdPair, ValidationFrameStats]
17+
GtKey = str
18+
GtStats = dict[GtKey, ValidationFrameStats]

packages/examples/cvat/recording-oracle/src/core/validation_errors.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,16 @@ def __str__(self) -> str:
1313

1414
class LowAccuracyError(DatasetValidationError):
1515
pass
16+
17+
18+
class TooSlowAnnotationError(DatasetValidationError):
19+
def __init__(self, current_progress: float, current_iteration: int):
20+
super().__init__()
21+
self.current_progress = current_progress
22+
self.current_iteration = current_iteration
23+
24+
def __str__(self):
25+
return (
26+
f"Escrow annotation progress is too small: {self.current_progress:.2f}% "
27+
f"at the {self.current_iteration} iterations"
28+
)

0 commit comments

Comments
 (0)