Skip to content

Support the SavedModel format #19

Merged
vpandiarajan20 merged 13 commits intomainfrom
support-savedmodel-format
Aug 18, 2025
Merged

Support the SavedModel format #19
vpandiarajan20 merged 13 commits intomainfrom
support-savedmodel-format

Conversation

@vpandiarajan20
Copy link
Contributor

@vpandiarajan20 vpandiarajan20 commented Aug 13, 2025

This allows us to run SavedModels on robot! Small changes to the way we do inference and format outputs, try this robot:
https://app.viam.com/machine/fbeabd00-80a0-4914-a67c-0d925804094b/control

@vpandiarajan20
Copy link
Contributor Author

Going to work on windows testing soon!

Copy link
Contributor

@bhaney bhaney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catches of other cases, but we will want to not assume a float input, and also please add unit tests.

The unit test i want to see is one that mocks different models with different callable signatures. The models themselves can be very dumb, and be fed noise as input.

Do not checkin a binary model, but create a simple tensorflow file of a mock model

Comment on lines +185 to +186
if np.any(data > 1.0):
data = data / 255.0
Copy link
Contributor

@bhaney bhaney Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a valid assumption. Some models do indeed take in uint8 tensors. You need to check the metadata of the model input and see if it expects floats or uint8.

Also, we expect this kind of preprocessing to be done before the input is fed into the module.

So please delete these line, and instead check to see what the model metadata expects, and put in an error that says something along of lines of "float expected, but got uint8"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm rereading the code now and I see the casting to the correct types immediately above, from line 165. However, I am unsure where the division by 255 is supposed to be happening, if not here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When testing earlier, I saw that the data tensor was numbers between 0-255 and the model was behaving improperly, this is why I added the division. I'm going to retest right now and verify.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified that the data tensor is numbers between 0-255 and the model needs between 0-1. Should we repackage the model with a preprocessing layer (not sure how to do this but I think it's possible)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

except (ValueError, TypeError, RuntimeError) as direct_err:
try:
f = self.model.signatures["serving_default"]
input_tensor = tf.convert_to_tensor(data, dtype=tf.float32)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, do not assume a float vector

try:
# Attempt direct call with raw data
res = self.model(data)
except (ValueError, TypeError, RuntimeError) as direct_err:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When would we get a RuntimeError in this scenario? I see the case for the other two errors

Copy link

@AGanguly13 AGanguly13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left one question, otherwise I agree with Bijan on the rest

Copy link

@AGanguly13 AGanguly13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all LGTM. I like how you broke off input and output processing into their own functions!

Comment on lines +189 to +190
else:
return {}
Copy link
Contributor

@bhaney bhaney Aug 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this isn't an error of some kind that should be raised to the user? Do we expect this to ever happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably raise an error, but I was just mimicking the logic that was here before. I'm pretty sure that it should never happen.

Copy link
Contributor

@bhaney bhaney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once you lint, it should be good

@bhaney
Copy link
Contributor

bhaney commented Aug 15, 2025

A question: you made an rc based on this branch, right? Once this is merged to main, you can make a full release

@vpandiarajan20 vpandiarajan20 merged commit dd11a02 into main Aug 18, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants