-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Edge only inference with cloud training #101
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
6e8b175
initial edge + cloud changes
f-wright 2aad26c
initial try for edge only inference
f-wright 111d565
Merge branch 'main' into edge-with-training
f-wright 8809c51
add edge inference exclusion
f-wright 5a1a838
working background tasks
f-wright 38b7d5a
Automatically reformatting code with black and isort
826c144
update readme
f-wright 23e78b7
Merge branch 'edge-with-training' of /~https://github.com/groundlight/e…
f-wright c7cfd54
updated validators
f-wright 1c8b7e6
update detector config only
f-wright c2d3317
adding testing
f-wright 4bf735b
Automatically reformatting code with black and isort
893f1ef
remove edge only inference from test setup
f-wright b1a9dc8
Merge branch 'edge-with-training' of /~https://github.com/groundlight/e…
f-wright 929456d
clean up
f-wright f2531ed
Merge branch 'main' into edge-with-training
f-wright 4ca87da
remove det id
f-wright 730b999
fix import
f-wright 49dbebc
fix missing paren
f-wright 660f910
update validator to run regardless of which field is set first
f-wright b7ee52d
Automatically reformatting code with black and isort
6927e3a
update validator for pydantic v2
f-wright 5475b05
gMerge branch 'edge-with-training' of /~https://github.com/groundlight/…
f-wright 497bd77
Automatically reformatting code with black and isort
6768872
switch to validation error
f-wright 735dab2
Merge branch 'edge-with-training' of /~https://github.com/groundlight/e…
f-wright f562ca9
debugging test
f-wright 6bc667f
skip testing setup for now
f-wright c580d35
update to model validator and add back test
f-wright 5d9688a
update from Tylers changes
f-wright 957429b
another try for the validator
f-wright 0c611e4
fix config finally
f-wright ac8ec71
Merge branch 'main' into edge-with-training
f-wright 60cf114
Automatically reformatting code with black and isort
53732f4
PR review changes
f-wright 551cf9a
Merge branch 'edge-with-training' of /~https://github.com/groundlight/e…
f-wright File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
from typing import Optional | ||
|
||
import numpy as np | ||
from fastapi import APIRouter, Depends, HTTPException, Query, Request, status | ||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request, status | ||
from groundlight import Groundlight | ||
from model import ( | ||
Detector, | ||
|
@@ -75,6 +75,7 @@ async def post_image_query( # noqa: PLR0913, PLR0915, PLR0912 | |
want_async: Optional[str] = Query(None), | ||
gl: Groundlight = Depends(get_groundlight_sdk_instance), | ||
app_state: AppState = Depends(get_app_state), | ||
background_tasks: BackgroundTasks = BackgroundTasks(), | ||
): | ||
""" | ||
Submit an image query for a given detector. | ||
|
@@ -120,11 +121,14 @@ async def post_image_query( # noqa: PLR0913, PLR0915, PLR0912 | |
|
||
detector_config = app_state.edge_config.detectors.get(detector_id, None) | ||
edge_only = detector_config.edge_only if detector_config is not None else False | ||
edge_only_inference = detector_config.edge_only_inference if detector_config is not None else False | ||
|
||
# TODO: instead of just forwarding want_async calls to the cloud, facilitate partial | ||
# processing of the async request on the edge before escalating to the cloud. | ||
_want_async = want_async is not None and want_async.lower() == "true" | ||
if _want_async and not edge_only: # If edge-only mode is enabled, we don't want to make cloud API calls | ||
if _want_async and not ( | ||
edge_only or edge_only_inference | ||
): # If edge-only mode is enabled, we don't want to make cloud API calls | ||
logger.debug(f"Submitting ask_async image query to cloud API server for {detector_id=}") | ||
return safe_call_sdk( | ||
gl.submit_image_query, | ||
|
@@ -183,11 +187,25 @@ async def post_image_query( # noqa: PLR0913, PLR0915, PLR0912 | |
results = edge_inference_manager.run_inference(detector_id=detector_id, image=image) | ||
confidence = results["confidence"] | ||
|
||
if edge_only or _is_confident_enough(confidence=confidence, confidence_threshold=confidence_threshold): | ||
if ( | ||
edge_only | ||
or edge_only_inference | ||
or _is_confident_enough( | ||
confidence=confidence, | ||
confidence_threshold=confidence_threshold, | ||
) | ||
): | ||
if edge_only: | ||
logger.debug( | ||
f"Edge-only mode enabled - will not escalate to cloud, regardless of confidence. {detector_id=}" | ||
) | ||
elif edge_only_inference: | ||
logger.debug( | ||
"Edge-only inference mode is enabled on this detector. The edge model's answer will be " | ||
"returned regardless of confidence, but will still be escalated to the cloud if the confidence " | ||
"is not high enough. " | ||
f"{detector_id=}" | ||
) | ||
else: | ||
logger.debug(f"Edge detector confidence is high enough to return. {detector_id=}") | ||
|
||
|
@@ -207,6 +225,13 @@ async def post_image_query( # noqa: PLR0913, PLR0915, PLR0912 | |
text=results["text"], | ||
) | ||
app_state.db_manager.create_iqe_record(iq=image_query) | ||
|
||
if edge_only_inference and not _is_confident_enough( | ||
confidence=confidence, | ||
confidence_threshold=confidence_threshold, | ||
): | ||
logger.info("Escalating to the cloud API server for future training due to low confidence.") | ||
background_tasks.add_task(safe_call_sdk, gl.ask_async, detector=detector_id, image=image) | ||
Comment on lines
+229
to
+234
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is great! Love how simple this is. |
||
else: | ||
logger.info( | ||
f"Edge-inference is not confident, escalating to cloud. ({confidence} < thresh={confidence_threshold})" | ||
|
@@ -224,6 +249,10 @@ async def post_image_query( # noqa: PLR0913, PLR0915, PLR0912 | |
# Fail if edge inference is not available and edge-only mode is enabled | ||
if edge_only: | ||
raise RuntimeError("Edge-only mode is enabled on this detector, but edge inference is not available.") | ||
elif edge_only_inference: | ||
raise RuntimeError( | ||
"Edge-only inference mode is enabled on this detector, but edge inference is not available." | ||
) | ||
|
||
# Finally, fall back to submitting the image to the cloud | ||
if not image_query: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import pytest | ||
|
||
from app.core.configs import DetectorConfig | ||
|
||
|
||
def test_detector_config_both_edge_modes(): | ||
with pytest.raises(ValueError): | ||
DetectorConfig( | ||
detector_id="det_xyz", | ||
local_inference_template="default", | ||
motion_detection_template="default", | ||
edge_only=True, | ||
edge_only_inference=True, | ||
) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if there's a different naming we could have for these different modes - I worry that the difference between "edge-only mode" and "edge-only inference" would be unclear to anyone external. Depending on how experimental/temporary these are, this might not matter, but if we expect external customers to use these at some point I think having more clear names might be helpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it's confusing. Maybe I could change them to
edge_only_no_training
andedge_only_cloud_training
? That gets a little wordy, but might be more clear. Definitely open to naming suggestions, wasn't sure what to call it.