-
Notifications
You must be signed in to change notification settings - Fork 11
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
Update submodules to the latest changes #212
Conversation
b72ccd3
to
c589515
Compare
I have realised that I have updated the submodules, but I missed the actual part of running |
I tried to create a sketch to see what things have changed. One of the issues I have encountered, trying to update the spec and core bioimage repos, was the change of the v4 to v5 spec, and specifically the redesign of the concept of axis and shape. v4The input tensors could have axis with an explicit size e.g. number, that creates an explicit shape e.g. (1,2,3,4) or we can have a parameterized shape with the concept of minimum shape and step ( The output tensor could have axis with explicit size as well, or an implicit one with the concept of reference tensor, scale and offset ( v5Instead of defining a parameterized shape for inputs or an implicit shape for outputs, this information is encapsulated per axis. For example a tensor can have 4 axis, and per axis, we could have a parameterized (same concept with Also, more type of axis have been added that they don't fall to the category of parameterized or referenced, as shown in the sketch. IssueSo an input tensor with one axis having size as ConclusionI am not sure if I should proceed with a new redesign of the abstraction layer, and how this abstraction can happen. For example, is it possible the model info to have an interface only with explicit shapes, just numbers, and don't have to deal with all the implications on how axis size and shape is designed by the spec? This way it could actually create an abstraction, instead of the coupled interface that it has now. |
c589515
to
629893b
Compare
As we have seen in the PR of attempting to implement the GPU prompting, reasoning on the v4 of spec is redundant and erroneous #213 (comment). Thus, I have finally updated tiktorch to work with spec v5.
|
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.
Hey @thodkatz, this is really great. Awesome how much you could also simplify the code with the update!
I really like that the models are now fully mocked. Probably speeds up the tests, too.
I wish we would retain maybe one "integration" test with a real model. For me this also fulfills documentation purposes -> how does realistic usage look like.
I'm currently investigating test failures that seem to be on osx-only 🙄
Edit: errors on osx due to different default start method for processes - spawn
. Turns out mock objects cannot be pickled resulting in _pickle.PicklingError: args[0] from __newobj__ args has the wrong class
errors. Changing it to fork
resolves it, but apparently fork is not safe to use on osx.
Makefile
Outdated
install: clean | ||
conda run -n $(TIKTORCH_ENV_NAME) pip install -e $(ALL_PACKAGES) |
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.
1. pip installs additional packages
Currently this will install a few additional packages via pip:
Successfully installed
annotated-types-0.7.0
bioimageio.core-0.6.7
bioimageio.spec-0.5.3.post4
distro-1.9.0
dnspython-2.6.1
email-validator-2.2.0
fire-0.6.0
loguru-0.7.2
pooch-1.8.2
pydantic-2.8.2
pydantic-core-2.20.1
pydantic-settings-2.4.0
python-dotenv-1.0.1
ruyaml-0.91.0
termcolor-2.4.0
tiktorch-23.11.0
the bioimage ones and tiktorch are expected here of course, but having pip install additional packages is often not safe (I think it is in this instance it looks mostly benign) but in general it is better to have the environment solved fully by conda. I would suggest adding these to environment.yml
and double checking that during dev-env creation pip will not perform any installs other than tiktorch and the vendored packages.
2. I don't think pip install -e
with more than one path works as expected.
While the local packages are installed, but only the first packages is installed editable, the rest ends up in the site-packages folder and is not editable.
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, thanks for noticing :) I will add them to the
environment.yml
2. I was shaving this problem pypa/pip#11467, when trying to use pip install -e <submodule path>
, I couldn't find a workaround so we have pip install <submodule path>
. The issue with the last one is that creates a build directory. If the build directory isn't cleaned, then subsequent attempts of re-installing new commits of the submodule won't be updated. That's why I added this thing with the clean
target, and separating the install
submodules process as well. I am not sure if I am missing something.
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.
Btw, for the first one, is it a good practise to declare indirect dependencies? All these packages installed by pip are coming from the dependencies of bioimageio packages. I could update the conda env file to use:
- pip:
- -e .
But I am sorry actually I didn't get the point of the first one.
But it is true that in the setup.py we have as well
"grpcio>=1.31",
"numpy",
"protobuf",
"pyyaml",
"xarray",
, that could be for sure part of the env if I am not mistaken, I am not sure why they have been declated in the setup.py in the first place.
@@ -9,7 +9,7 @@ | |||
from typing import Any, List, Optional, Type, TypeVar | |||
from uuid import uuid4 | |||
|
|||
from bioimageio.core.resource_io import nodes | |||
from bioimageio.spec.model import v0_5 |
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.
phew... Not sure my take here is correct, but this does mean we limit ourselves to 0.5 models only? I don't think there are many 0.5 models in the wild, currently. I'm not really against limiting tiktorch to these only. But this will have consequences as to when we can switch to the new versions in ilastik (once the models in the zoo have been updated to 0.5). Since this PR removes the 0.4 functionality it's obvious how much of simplification it is to only support 0.5 :).
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.
that's a good point. But regarding the discussion we had for #215, one of the major points for doing that is that bioimage is responsible for backwards compatibility right? So in theory a v0_4 model could provide a partial v0_5, so we don't have to deal with maintaining the abstraction layers of the bioimage. I am not sure if I misunderstood something. Otherwise, we have again to introduce something similar to model info to make v4 and v5 to work with tiktorch.
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, with the library one could get a 0.5 from a 0.4 :)
tests/conftest.py
Outdated
""" | ||
|
||
mocked_input1 = create_autospec(v0_5.InputTensorDescr) | ||
mocked_input1.id = "input1" | ||
mocked_input1.axes = [ | ||
v0_5.BatchAxis(), | ||
v0_5.ChannelAxis(channel_names=["channel1", "channel2"]), | ||
v0_5.SpaceInputAxis(id=AxisId("x"), size=10), | ||
v0_5.SpaceInputAxis(id=AxisId("y"), size=v0_5.SizeReference(tensor_id="input3", axis_id="x")), | ||
] | ||
|
||
mocked_input2 = create_autospec(v0_5.InputTensorDescr) | ||
mocked_input2.id = "input2" | ||
mocked_input2.axes = [ | ||
v0_5.BatchAxis(), | ||
v0_5.ChannelAxis(channel_names=["channel1", "channel2"]), | ||
v0_5.SpaceInputAxis(id=AxisId("x"), size=v0_5.ParameterizedSize(min=10, step=2)), | ||
v0_5.SpaceInputAxis(id=AxisId("y"), size=v0_5.ParameterizedSize(min=10, step=5)), | ||
] | ||
|
||
mocked_input3 = create_autospec(v0_5.InputTensorDescr) | ||
mocked_input3.id = "input3" | ||
mocked_input3.axes = [ | ||
v0_5.BatchAxis(), | ||
v0_5.ChannelAxis(channel_names=["channel1", "channel2"]), | ||
v0_5.SpaceInputAxis(id="x", size=v0_5.SizeReference(tensor_id="input2", axis_id="x")), | ||
v0_5.SpaceInputAxis(id="y", size=10), | ||
] |
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.
amazing what's possible in 0.5... input1.y <- input3.x <-- input2.x
good to have a non-trivial test case :)
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 was very skeptical about this when implementing the _realize_size_reference functionality :) I am not sure if it is an overkill
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.
Not valid anymore, see #212 (comment)
@@ -39,9 +38,7 @@ def has_work(self): | |||
return self._pipeline.max_num_iterations and self._pipeline.max_num_iterations > self._pipeline.iteration_count | |||
|
|||
def forward(self, input_tensors): |
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.
def forward(self, input_tensors): | |
def forward(self, input_tensors: Sample): |
at least in my pyright setup this is not inferred.
tiktorch/server/session/process.py
Outdated
class InputTensorValidator: | ||
def __init__(self, input_specs: List[nodes.InputTensor]): | ||
self._input_specs = input_specs | ||
class SampleValidator: |
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.
Could you maybe clarify what this class is intended for? I see it takes potentially input, but also output descriptions. _get_spec
seems to imply one can only check input tensors. So it's an InputSampleValidator
?!
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, sorry the name should be InputSampleValidator
and should get only the InputTensor
tiktorch/server/session/process.py
Outdated
def __init__(self, input_specs: List[nodes.InputTensor]): | ||
self._input_specs = input_specs | ||
class SampleValidator: | ||
def __init__(self, specs: Union[List[v0_5.InputTensorDescr], List[v0_5.OutputTensorDescr]]): |
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.
are the types here as intended? Or should it be List[Union[v0_5.InputTensorDescr, v0_5.OutputTensorDescr]]
?
def valid_model_request(device_ids=None): | ||
ret = inference_pb2.CreateModelSessionRequest( | ||
model_blob=inference_pb2.Blob(content=b""), deviceIds=device_ids or ["cpu"] | ||
) | ||
return ret |
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.
is an empty model_blob
part of a valid ModelSessionRequest
?
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.
It has changed in this commit 16ccbe4 :)
d84c70f
to
16ccbe4
Compare
By reproducing the issue that @k-dominik mentioned #212 (review), with The idea of using mocks, seems convenient, but actually, I noticed that it can have some pitfalls. For example, by mocking the Another thing that I noticed, is that previously the main process used to create a prediction pipeline object before starting the child process here (16ccbe4#diff-6aceb0322a663f6cc7ec8ab717637f2f1a0cab3c8a6a57c57f0c18903d8d2a36L144). Then this object is transferred to the child process. This is redundant, since we already have a bytes object ( TODO:
|
439149a
to
6de95c7
Compare
I have included tests for simple use cases of v4 models and I added parameterization for different weight formats e.g. As I was trying to avoid using files, and creating objects from scratch, I have stumbled upon a few issues, when trying to work with v4 models. I managed to find a workflow that it works though :) I have created an issue in bioimageio spec. I could work on this for sure, if we want to support v4. |
6de95c7
to
ad5b34d
Compare
ad5b34d
to
bfac267
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #212 +/- ##
==========================================
- Coverage 65.50% 64.77% -0.74%
==========================================
Files 40 40
Lines 2267 2183 -84
==========================================
- Hits 1485 1414 -71
+ Misses 782 769 -13 ☔ View full report in Codecov by Sentry. |
91e34c8
to
eb2b18b
Compare
For the windows failing tests, I have submitted an issue in bioimageio spec bioimage-io/spec-bioimage-io#633 |
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.
Really great, I had only small comments.
Great to have code now to generate various models - if I want to create a model in the future, I'll probably look here for minimal examples :)
Also okay to merge now, without fixing bioimage first (it will need fixing before i2k though).
tests/conftest.py
Outdated
""" | ||
Mocked bioimageio prediction pipeline with three inputs single output | ||
""" | ||
test_tensor1 = np.arange(1 * 2 * 10 * 10, dtype="float32").reshape(1, 2, 10, 10) |
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.
out of paranoia I'd avoid square test tensors (of fear that something somewhere might transpose and I wouldn't notice...)
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.
Fixed 42210b7 :)
def test_call_predict_valid_explicit(self, grpc_stub, bioimage_model_explicit_siso): | ||
model_bytes, expected_output = bioimage_model_explicit_siso | ||
model = grpc_stub.CreateModelSession(valid_model_request(model_bytes)) | ||
arr = xr.DataArray(np.arange(2 * 10 * 10).reshape(1, 2, 10, 10), dims=("batch", "channel", "x", "y")) |
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.
for convenience the fixture could also return the input that produces the expected output (just because now one has to check the code in order to build arr
.
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.
Returning the expected_output
, I think brough the confusion. The thing is that each fixture has a hardcoded dummy network defined in the conftest.py
, and for simplicity this network returns a fixed output. But there isn't an actual input that produces it. The test should be responsible to create a valid input.
So, to avoid this confusion, I have changed the fixture to return the network (73e4fb4). So now from the test we need to define a valid input, and use the network to get the expected output, asserting that the Predict
returns the same output.
But still we need to check how the input axes were created for each bioimageio fixture to create valid inputs. But I think that is part of the testing and we need to do it for the actual validation.
What do you think :) ? @k-dominik
The fix was a minor one to resolve the spec issue, I have opened a PR to resolve it bioimage-io/spec-bioimage-io#634. Thanks @k-dominik for the review! I will address them :) |
73e4fb4
to
e5f786a
Compare
- bioimageio.spec==0.5.3.post4 - bioimageio.core==0.6.7
- For non-unix systems, when launching a new process, `spawn` can be used instead of `fork`. With `spawn`, the memory of the parent process isn't copied to the child one as `fork`. Mock objects can't be serialized, and tests were failing due to this. - The `PredictionPipeline` object was created in the main process before the creation of the child process, and then it was serialized to be transferred to the child one. Then again it was deserialized. This is redundant, since initially the `PredictionPipeline` is created by a bytes value. So both the parent and the child process use the bytes to construct the same `PredictionPipeline`.
- Weights are parameterized for pytorch and torchscript workflows
Fixtures are bioimageio models with dummy networks that do simple operations such as add one to the input. To test that, and to know what a particular model does, we encode it within the name of the fixture e.g. modelAddOne
e5f786a
to
7877797
Compare
Hey!
This is a small PR, that updates the submodules to the latest changes (
git submodules update --remote --merge
).It seems there were no conflicts, and tests are passing without any source code changes.
Initially when I have attempted to clone the repo, and run the tests:
I have stumbled upon this issue pytorch/pytorch#123097.
To resolve this, I have added in the
environment.yml
file, the-mlk!=2024.1
.The same problem has occured for ilastik too, and it is already listed there https://github.com/ilastik/ilastik/blob/main/dev/environment-dev.yml#L72
I have fixed also a broken link :)