-
Notifications
You must be signed in to change notification settings - Fork 7
Add support for feed-forward multi-track video requests. #1906
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
base: develop
Are you sure you want to change the base?
Conversation
Add FEED_FORWARD_ALL_TRACKS property.
|
This should only be |
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.
Reviewable status: 0 of 21 files reviewed, 1 unresolved discussion (waiting on @brosenberg42 and @jrobble)
trunk/workflow-manager/src/main/resources/workflow-properties.json line 14 at r1 (raw file):
Previously, brosenberg42 wrote…
This should only be
["VIDEO"].
Done.
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.
@brosenberg42 reviewed 5 of 21 files at r1, 16 of 16 files at r2, all commit messages.
Reviewable status: all files reviewed, 7 unresolved discussions (waiting on @jrobble)
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/service/TaskMergingManager.java line 87 at r2 (raw file):
Message message, List<Track> feedForwardTracks) { // TODO: for now, assume all feed-forward tracks have the same history var feedForwardTrack = feedForwardTracks.get(0);
In a comment on DetectionRequest.java, I suggested changing the Optional<List<Track>> field to List<Track>. If we make that change, we might need to handle an empty list here.
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/segmenting/VideoMediaSegmenter.java line 162 at r2 (raw file):
} var AllVideoTracksRequestBuilder = AllVideoTracksRequest.newBuilder();
The A at the beginning of the variable name should be lower case.
trunk/detection/executor/cpp/batch/ProtobufRequestUtil.cpp line 118 at r2 (raw file):
const auto& pb_ff_tracks = video_request.feed_forward_tracks(); std::vector<MPFVideoTrack> ff_tracks; for (const auto& pb_ff_track : pb_ff_tracks) {
Please create a function named ConvertFeedForwardTrack and call it from here and from CreateVideoJob. It would convert the protobuf track to the C++ track similar to ConvertFeedForwardLocation
trunk/detection/executor/cpp/batch/CppComponentHandle.cpp line 63 at r2 (raw file):
std::vector<MPFVideoTrack> CppComponentHandle::GetDetections(const MPFAllVideoTracksJob &job) { return component_->GetDetections(job);
We could throw an exception here instead of calling in to the component. It would allow us to remove the method from the C++ component interface.
trunk/detection/executor/cpp/batch/PythonComponentHandle.h line 60 at r2 (raw file):
std::vector<MPFVideoTrack> GetDetections(const MPFVideoJob &job); std::vector<MPFVideoTrack> GetDetections(const MPFAllVideoTracksJob &job);
Please add a test to test_batch_executor.cpp for this method. There are unit tests for all of the other job types in that file.
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/segmenting/DetectionRequest.java line 38 at r2 (raw file):
public record DetectionRequest( DetectionProtobuf.DetectionRequest protobuf, Optional<List<Track>> feedForwardTracks,
Normally, Optional is not used with collections because, in most cases, you can just use an empty collection. In this class, when there are no headers, we use Map.of(). We should handle feedForwardTracks similarly and use List.of() when there are no tracks.
trunk/detection/executor/cpp/batch/PythonComponentHandle.cpp line 573 at r2 (raw file):
case VIDEO: return component_.get_detections_from_video_method.has_value() || component_.get_detections_from_all_video_tracks_method.has_value();
This is logically wrong. Supports() can return true even when calling the actual method will throw MPF_UNSUPPORTED_DATA_TYPE. One way to address the issue is to change the parameter to PythonComponentHandle::Supports and CppComponentHandle::Supports to be JobContext.
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.
Reviewable status: all files reviewed, 8 unresolved discussions (waiting on @jrobble)
trunk/detection/executor/cpp/batch/ProtobufRequestUtil.cpp line 140 at r2 (raw file):
}; } else {
Shouldn't this job type always have feed forward tracks? Is there a use case where it makes sense to create a MPFAllVideoTracksJob with no tracks?
|
Previously, brosenberg42 wrote…
class JobRunner(contextlib.AbstractContextManager):
def __init__(self,
cmd_line_args: argparse.Namespace,
env_props: Mapping[str, str],
job_stdin: TextIO,
component,
descriptor):
with contextlib.ExitStack() as exit_stack:
self._output_dest = cmd_line_args.output
exit_stack.push(self._output_dest)
self._component_handle = component
self._sdk_module = component.sdk_module
self._mime_type = self._get_mime_type(
cmd_line_args.media_type, cmd_line_args.media_path, cmd_line_args.media_metadata)
self._media_type = self._get_media_type(
cmd_line_args.media_type, self._mime_type)
if not self._component_handle.supports(self._media_type):
raise RuntimeError(
f'The component does not support {self._media_type.name.lower()} jobs.')and here in detection executor while (true) {
logger.Info("Waiting for next job.");
auto job_context = job_receiver.GetJob();
if (!component.Supports(job_context.job_type)) {
job_receiver.ReportUnsupportedDataType(job_context);
continue;
}I can see how to get the job context from the latter code, but not the former. Once I have the job context what do I do with it? |
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.
Reviewable status: 15 of 23 files reviewed, 8 unresolved discussions (waiting on @brosenberg42 and @jrobble)
trunk/detection/executor/cpp/batch/CppComponentHandle.cpp line 63 at r2 (raw file):
Previously, brosenberg42 wrote…
We could throw an exception here instead of calling in to the component. It would allow us to remove the method from the C++ component interface.
Done.
trunk/detection/executor/cpp/batch/ProtobufRequestUtil.cpp line 118 at r2 (raw file):
Previously, brosenberg42 wrote…
Please create a function named
ConvertFeedForwardTrackand call it from here and fromCreateVideoJob. It would convert the protobuf track to the C++ track similar toConvertFeedForwardLocation
Done.
trunk/detection/executor/cpp/batch/ProtobufRequestUtil.cpp line 140 at r2 (raw file):
Previously, brosenberg42 wrote…
Shouldn't this job type always have feed forward tracks? Is there a use case where it makes sense to create a
MPFAllVideoTracksJobwith no tracks?
See this discussion: https://reviewable.io/reviews/openmpf/openmpf-python-component-sdk/91#-Oa0icuW7rcYdA2ZnFnn
trunk/detection/executor/cpp/batch/PythonComponentHandle.h line 60 at r2 (raw file):
Previously, brosenberg42 wrote…
Please add a test to
test_batch_executor.cppfor this method. There are unit tests for all of the other job types in that file.
Done.
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/segmenting/DetectionRequest.java line 38 at r2 (raw file):
Previously, brosenberg42 wrote…
Normally, Optional is not used with collections because, in most cases, you can just use an empty collection. In this class, when there are no headers, we use
Map.of(). We should handlefeedForwardTrackssimilarly and useList.of()when there are no tracks.
Done.
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/segmenting/VideoMediaSegmenter.java line 162 at r2 (raw file):
Previously, brosenberg42 wrote…
The A at the beginning of the variable name should be lower case.
Done.
trunk/workflow-manager/src/main/java/org/mitre/mpf/wfm/service/TaskMergingManager.java line 87 at r2 (raw file):
Previously, brosenberg42 wrote…
In a comment on DetectionRequest.java, I suggested changing the
Optional<List<Track>>field toList<Track>. If we make that change, we might need to handle an empty list here.
Done.
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.
@brosenberg42 reviewed 8 of 8 files at r3, 2 of 2 files at r4, all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @jrobble)
trunk/detection/executor/cpp/batch/PythonComponentHandle.cpp line 573 at r2 (raw file):
Previously, jrobble (Jeff Robble) wrote…
Supports()is used here inmpf_cli_job_runner.py:class JobRunner(contextlib.AbstractContextManager): def __init__(self, cmd_line_args: argparse.Namespace, env_props: Mapping[str, str], job_stdin: TextIO, component, descriptor): with contextlib.ExitStack() as exit_stack: self._output_dest = cmd_line_args.output exit_stack.push(self._output_dest) self._component_handle = component self._sdk_module = component.sdk_module self._mime_type = self._get_mime_type( cmd_line_args.media_type, cmd_line_args.media_path, cmd_line_args.media_metadata) self._media_type = self._get_media_type( cmd_line_args.media_type, self._mime_type) if not self._component_handle.supports(self._media_type): raise RuntimeError( f'The component does not support {self._media_type.name.lower()} jobs.')and here in detection executor
main.cpp:while (true) { logger.Info("Waiting for next job."); auto job_context = job_receiver.GetJob(); if (!component.Supports(job_context.job_type)) { job_receiver.ReportUnsupportedDataType(job_context); continue; }I can see how to get the job context from the latter code, but not the former.
Once I have the job context what do I do with it?
CppComponentHandle is only used by the batch executor. It is not used in MpfCppSdkPythonBindings, so we don't need to worry about the cli runner.
|
I'm confused. Both C++ and Python handles are used by def _init_component(self, cmd_args) -> None:
if self._component:
return
self._descriptor = self._load_descriptor(cmd_args.descriptor_file)
lang = self._descriptor['sourceLanguage'].lower()
if lang == 'c++':
# Need to conditionally import because the C++ SDK won't be installed in Python
# component images.
import mpf_cpp_runner
self._component = mpf_cpp_runner.CppComponentHandle(self._descriptor)
self._exit_stack.enter_context(self._component)
elif lang == 'python':
# Need to conditionally import because the Python SDK won't be installed in C++
# component images.
import mpf_python_runner
self._component = mpf_python_runner.PythonComponentHandle(self._descriptor)
else:
raise NotImplementedError(f'{lang} components are not supported.')However,
The bindings are used by the handle, not the other way around. Overall, I'm lost. What are we trying to achieve?
It sounds like you only care about the C++ and Python handles that are part of the C++ detection executor. As I showed above in if (!component.Supports(job_context.job_type)) {I can get |
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.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @jrobble)
trunk/detection/executor/cpp/batch/PythonComponentHandle.cpp line 573 at r2 (raw file):
Overall, I'm lost. What are we trying to achieve?
If you try to run an all tracks job on a component that only supports regular video jobs, Supports will return true. We didn't add a new data type for multi-track jobs, so we need more than just the data type to determine whether or not the job type is supported. mpf_cpp_runner.CppComponentHandle is a Python class. It is meant to be the CLI runner's version of the batch executor's CppComponentHandle.cpp.
This is how I thought you would implement Supports with the change:
bool Supports(const JobContext& job_context) const {
if (std::holds_alternative<MPFVideoJob>(job_context.job)) {
return component_.get_detections_from_video_method.has_value();
}
else if (std::holds_alternative<MPFAllVideoTracksJob>(job_context.job)) {
return component_.get_detections_from_all_video_tracks_method.has_value();
}
else if (std::holds_alternative<MPFImageJob>(job_context.job)) {
return component_.get_detections_from_image_method.has_value();
}
else if (std::holds_alternative<MPFAudioJob>(job_context.job)) {
return component_.get_detections_from_audio_method.has_value();
}
else {
return component_.get_detections_from_generic_method.has_value();
}
}|
Previously, brosenberg42 wrote…
I implemented this and pushed the changes. There is an issue with this new code: while (true) {
logger.Info("Waiting for next job.");
auto job_context = job_receiver.GetJob();
if (!component.Supports(job_context)) {
job_receiver.ReportUnsupportedDataType(job_context);
continue;
}We can no longer assume that More generally, in the future, I don't see how it's possible to determine if C++ components support the all tracks method since the C++ components have to completely implement the API. We can't check if a method is missing from the implementation with Is that a problem for C++ implementations or is the default behavior of generating this exception acceptable? throw MPFDetectionException(MPFDetectionError::MPF_UNSUPPORTED_DATA_TYPE);Looking at that, again it assumes an unsupported data type when it may just be that the all tracks method isn't implemented. Seems like we would need a more generic NOT_IMPLEMENTED exception. |
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.
@brosenberg42 reviewed 6 of 6 files at r5, all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on @jrobble)
trunk/detection/executor/cpp/batch/PythonComponentHandle.cpp line 573 at r2 (raw file):
Previously, jrobble (Jeff Robble) wrote…
I implemented this and pushed the changes. There is an issue with this new code:
while (true) { logger.Info("Waiting for next job."); auto job_context = job_receiver.GetJob(); if (!component.Supports(job_context)) { job_receiver.ReportUnsupportedDataType(job_context); continue; }We can no longer assume that
Supports()fails due to a data type issue, so we can't callReportUnsupportedDataType(). I think we need to generate an exception inside ofSupports()with the error message. If that's the case, should we rename the call to something like "validates"?More generally, in the future, I don't see how it's possible to determine if C++ components support the all tracks method since the C++ components have to completely implement the API. We can't check if a method is missing from the implementation with
*_method.has_value().Is that a problem for C++ implementations or is the default behavior of generating this exception acceptable?
throw MPFDetectionException(MPFDetectionError::MPF_UNSUPPORTED_DATA_TYPE);Looking at that, again it assumes an unsupported data type when it may just be that the all tracks method isn't implemented. Seems like we would need a more generic NOT_IMPLEMENTED exception.
I was considering the case to be an unsupported job type. I see your point about it not really being an unsupported data type. In the code you posted, you can see we handle unsupported data type differently than other errors. I originally thought we should handle the issue in the same way. I see that the error messages are going to be confusing. I think you can just revert that change, sorry for the confusion.
As far as future changes go, I think we should remove Supports and rely on GetDetections throwing MPFDetectionException(MPFDetectionError::MPF_UNSUPPORTED_DATA_TYPE) to get the existing behavior. It can use a different error code if the problem is that it does not support multi-track jobs. To do that, we would also need to refactor the component executor and update the C++ components
This reverts commit 28bf135.
Issues:
Related PRs:
This change is