-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Handle attributes returned from nuclio detector #3917
Conversation
@bsekachev @nmanovic could you please comment if cvat-ui version should be bumped in package.json in case of such change? |
Hi, any case (if the patch changes anything). Here, I think need to update patch version number ( |
@@ -1037,7 +1037,10 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> { | |||
frame, | |||
occluded: false, | |||
source: 'auto', | |||
attributes: {}, | |||
attributes: data.attributes.reduce(function(attrs_map: any, attr: any) { | |||
attrs_map[attr.spec_id] = attr.value; |
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.
as far as I understand, attr.spec_id
is returned by nuclio function.
At the same time spec_id
is the CVAT specific thing which additionally differs task by task. It means that nuclio function should not return these ids, only attribute names and matching should be implemented on CVAT side.
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.
Ok, it does make sense. And I guess the same is applicable for the changes in backend?
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.
Yep. Matching better to be implemented on backend (for both methods, when call automatic annotation for one frame and for a whole task)
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.
The only one question which I have so far is how to avoid attribute names and spec ids matching on client side in case of one frame auto annotation.
What I could figure out so far regarding attributes adding, is that attrs format expected to be like {spec_id: value}
and checked here. So in runInference
method I can't create some temporary attribute basing only on name and value, and then in the backend match label+attr_name coming from frontend into spec_id (at least without deeper code changes).
My current implementation of runInference looks like that (not pushed yet until agreement):
runInference={async (task: any, model: Model, body: object) => {
try {
this.setState({ mode: 'detection', fetching: true });
const result = await core.lambda.call(task, model, { ...body, frame })
let mapping = {};
task.labels.forEach((label: any) => {
mapping[label.name] = {};
label.attributes.forEach((attr: any) => {
mapping[label.name][attr.name] = attr.id;
})
});
const states = result.map(
(data: any): any =>
new core.classes.ObjectState({
shapeType: data.type,
label: task.labels.filter((label: any): boolean => label.name === data.label)[0],
points: data.points,
objectType: ObjectType.SHAPE,
frame,
occluded: false,
source: 'auto',
attributes: data.attributes.reduce(function(attrs_map: any, attr: any) {
attrs_map[mapping[data.label][attr.name]] = attr.value;
return attrs_map;
}, {}),
zOrder: curZOrder,
}),
);
Finally, my questions 😄
- Is it ok to keep mapping of attr_name returned from nuclio to spec_id in the FE?
- If it's ok to keep mapping in the FE, which approach is more preferable, to build
mapping
object from the code snippet above on render stage or on inference stage?
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.
@mikhail-treskin , could you please look how it is done for labels? For attributes we need to have mostly the same functionality. A serverless function should declare which attributes it supports (as it is done for labels). Based on the information, it is necessary map attributes per task.
Current patch cannot be applied as is to multiple tasks because spec_id will be different for different tasks.
Please let me know if you want to contribute the functionality. It can be quite complex if it is done in production quality. Also need to have a severless function which supports attributes. It will be an example and can be used for testing. I will move the patch into WIP for now.
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.
@nmanovic, yes the PR is definitely WIP, just forgot to mark it properly.
Could you please have a look on changes in latest commit? as @bsekachev proposed previously i'm handling attributes returned from nuclio by name and then maps them into spec_id basing on db task data. In context of your request to declare supported attributes in function config it's not a finall solution, but I suppose that in general functionality will be almost the same.
could you please look how it is done for labels? For attributes we need to have mostly the same functionality. A serverless function should declare which attributes it supports (as it is done for labels). Based on the information, it is necessary map attributes per task.
Does it presume that we also need to have functionality for attributes mapping in UI like it's done for labels?
Also need to have a severless function which supports attributes
As an example can propose pipeline of few OMZ models like face_detection->emotion_recognition+age_gender_recognition (or only on of _recognition)
In general, we really need this functionality for our production usage of CVAT, so will be really appreciated if if you could assist with PR productisation. Don't want to keep it in the fork and struggle with rebases 😄
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.
@mikhail-treskin , the updated patch looks much better. We are more than happy to accept any contribution from our community. Also I will be happy to understand how you are using CVAT in your company and which features are missing. Probably it can be a meeting. Let me know if you are ready to share the information.
An example with OMZ models will be great. Could you please add one or several of them to the PR as serverless functions? If you have any requests to these models, please ping @snosov1. Probably he can help somehow. He also is responsible for OTE: https://github.com/openvinotoolkit/training_extensions
It will be great to map attributes in UI in the future. But let's consider the feature as an optional recommendation. It should not block the PR. I will merge it without the functionality.
Better to decelerate attributes in yml config for a serverless function. Thus it is easy to understand what the function supports.
If you can extend the tutorial: https://openvinotoolkit.github.io/cvat/docs/manual/advanced/serverless-tutorial/, it will be great. But it is an optional recommendation as well.
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.
@nmanovic could you please have a look on serverless function?
I'm not sure regarding face-detection model, tried to choose between 0206 and 0205, looks like 0206 more accurate but much slower than 0205, not sure what is more preferable in case of automatic annotation scenario.
1c038bb
to
5f026f0
Compare
c1756a0
to
5aaf0b5
Compare
431e6a3
to
041d80b
Compare
35dd7e6
to
56a2e46
Compare
@mikhail-treskin , is the PR ready for review? |
Yep, I guess so. Had the question above regarding omz model
maybe better to address it to @snosov1? |
56a2e46
to
d94c8c7
Compare
# attribute names have to be the same as in annotated task, otherwise values will be ignored | ||
spec: | | ||
[ | ||
{ "id": 0, "name": "face", "attributes": ["age", "gender", "emotion"]} |
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.
@mikhail-treskin , thanks for the great PR. Could you please help us to polish the functionality? Each attribute should have a type and possible values. For example, when CVAT returns an attribute (e.g. GET /api/v1/tasks), it returns something like the structure below:
"labels": [
{
"id": 0,
"name": "age",
"attributes": [
{
"id": 0,
"name": "age",
"input_type": "number",
"default_value": "25",
"values": [
"0",
"150",
"1"
]
}
]
}
],
Do you think it is valuable to have something like that here? Otherwise it is unclear which values each attribute has. Also it will be difficult to much them to a corresponding task. Basically, I should be able to take labels and attributes from the definition as is and create a task with them.
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.
Yes, I agree that possible values should be part of function config.
But what about attribute type, i'm not really sure that it does make sense to store it in function config since attribute types is CVAT specific information. Maybe it make sense to add additional attributes verification on backend side, e.g. if certain attribute has type "Select" or "Radio" only one value can be accepted, and check if "Number" attribute coming from nuclio is really convertible to number. Otherwise exception can be raised or fallback to default attribute value.
What do you think about such an approach?
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.
@mikhail-treskin , spec
section inside function.yaml is also CVAT specific. Basically I believe that CVAT labels and attributes definition and serverless labels and attributes definition should correspond to each other. Also in the future it is good to implement matching of attributes by name in UI (as it is implemented for labels). It will be necessary to understand the type of an attribute and possible values. I don't suggest implementing matching in UI for the PR. It is another story.
Proposal:
- Let's have the same definition for attributes as CVAT server support (see an example above).
- If an attribute is supported by a serverless function, but it isn't supported by a corresponding label in CVAT, it should be ignored.
- If attributes are matched by name, it is necessary to see if we can cast it to a corresponding type. For example, any attribute can be converted to
text
type. At the same timetext
type cannot be converted toselect
. An attribute, which is matched by name but cannot be casted, should be ignored.
Thus we have a set of labels with attributes from a task. Also we have a number of labels with attributes from a serverless function. We match labels by name. After that we match attributes by name. After that we match attributes by type. During the process some labels and attributes will be filtered. The final list of labels with reduced number of attributes can be covered by our serverless function.
It is a typical case when a serverless function supports more labels and attributes when it is necessary. All of them should be ignored as it is implemented for labels.
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.
@mikhail-treskin , could you please help us to fix eslint and pylint linters warnings for the PR? I believe the PR is a great improvement. We definitely want to have it inside the develop branch. Could you please resolve mentioned issues and I will merge it. |
d94c8c7
to
8b0d4a7
Compare
Yes, sure. Should be fixed in latest commit. |
cvat/apps/lambda_manager/views.py
Outdated
@@ -138,6 +144,10 @@ def to_dict(self): | |||
response.update({ | |||
'state': self.state | |||
}) | |||
if self.kind is LambdaType.DETECTOR: | |||
response.update({ | |||
'attributes': self.attributes |
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.
@mikhail-treskin , Probably it is slightly better to return attributes together with labels.
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.
In general I agree but I was afraid that response structure changing may broke compatibility between BE and FE in some cases which I'm not aware. If it will not affect any functionality I definitely can change the code to return attributes along with labels.
@mikhail-treskin , thanks for all your time and contribution. Will you be able to continue improving the PR? |
0774a4c
to
b232f10
Compare
b232f10
to
18d4b19
Compare
emotions_model_xml = os.path.join(emotions_base_dir, "emotions-recognition-retail-0003.xml") | ||
emotions_model_bin = os.path.join(emotions_base_dir, "emotions-recognition-retail-0003.bin") | ||
self.emotions_model = ModelLoader(emotions_model_xml, emotions_model_bin) | ||
self.genders_map = ["female", "male"] |
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.
@mikhail-treskin , better to load these data from function.yaml.
emotions_model_bin = os.path.join(emotions_base_dir, "emotions-recognition-retail-0003.bin") | ||
self.emotions_model = ModelLoader(emotions_model_xml, emotions_model_bin) | ||
self.genders_map = ["female", "male"] | ||
self.emotions_map = ["neutral", "happy", "sad", "surprise", "anger"] |
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.
@mikhail-treskin , better to load these data from function.yaml.
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.
LGTM
Motivation and context
Currently CVAT ignores attributes info coming from nuclio detection function along with boxes. Such functionality is required for pipelined inference of several models e.g. detector->age/gender/pose recognition.
How has this been tested?
Tested with corresponding "..: test" targets from vscode configurations (logs may be attached if needed).
Manually checked that attributes returned from nuclio applied both in task auto annotation case and using AI tools in annotation mode for certain frame.
Checklist
develop
branchcvat-core, cvat-data and cvat-ui)
License
Feel free to contact the maintainers if that's a concern.