You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The last version on which the following example runs through is distributed==2.30.1. Thereafter it always fails. Note that failure will not occur with optimize_graph=True. However, I am busy experimenting with annotations and I need to disable task fusion.
I'm able to reproduce. It looks like the root cause is that Blockwise.__dask_distributed_pack__ can return inputs that aren't msgpack serializable. In this case, the blockwise layer's .indices includes the ndarray np.array([1.]).
@madsbk I'd be curious to get your thoughts here. Do we require that the values in __dask_distributed_pack__ be msgpack serializable?
Yes because of the new high level graph da.blockwise doesn't support numpy arrays directly. E.g. the da.ufunc class calls da.asarray() on the inputs to make sure that they are dask arrays, which in turn makes them compatible with __dask_distributed_pack__.
If I may ask @madsbk, is it expected that the last example I posted above used to work and now doesn't? That seems like it might be a regression, but I appreciate that I am no expert.
I think this is a regression, because if the argument index is None, then the docs say that the argument is treated as literal, not a dask array. Hence any literal will now need to be msgpackable, whereas previously it would all go through dask's dask.protocol.serialize.{serialize,deserialize} functionality.
We've been discussing optimizing the serialization pipeline to go through MsgPack more directly (with fewer passes over the data) ( #4379 ). The interest being to improve performance of serialization and simplify that code. This would effectively include 2. Though it doesn't preclude us from doing other things as well in the interim
What if np.dtype("u2") is used instead? Or even just"u2"? Maybe something peculiar about np.uint16 as opposed to a dtype object
I have tried this - it doesn't matter what the specific type is. I have tried several and they all fail (np.float64 and np.dtype('f8') both fail, as an example). I think it just boils down to none of them being msgpack serializable.
Or perhaps it is just the scalar value? Can 0 be used without typing?
Scalar values work but likely only because msgpack can cope with Python's builtins. np.float32(0) does not work, for example.
Right so I think we are getting the crux of the issue. Namely I don’t think Dask (currently) handles serialization of NumPy scalars. I think this support could be added and should be pretty straightforward. Is this something you would be interested in doing? 🙂
Right so I think we are getting the crux of the issue. Namely Dask doesn’t (currently) handle serialization of NumPy scalars. I think this support could be added and should be pretty straightforward. Is this something you would be interested in doing? slightly_smiling_face
I don't believe this only affects numpy scalars and arrays, as the following example demonstrates:
With optimisation (the default distributed/dask behaviour for a long time), the above succeeds, because dask.protocol.serialize.{serialize,deserialize} is invoked on the optimised low-level graph. dask.protocol.serialize.{serialize,deserialize} can defer to custom serialisation routines, in addition to standard pickle. blockwise does support embedding literals (presumably of any type) in the graph.
Without optimisation, the above fails because dask.protocol.highlevelgraph.highlevelgraph_pack is invoked on the HLG, which only supports msgpack as a serialisation protocol.
This regression is only exposed when graph optimisation is turned off.
I think the way forward here is to determine why msgpack is the only serialisation option for HLG's. IIRC this is to avoid remote code execution on the scheduler?
If not, would it be possible to use distributed standard serialisation routines for HLG serialisation?
I believe (though Mads may correct me) the reason for HLG using only msgpack is to keep serialization efficient.
There’s some additional overhead we have been finding in Dask’s custom serialization, but we are looking at reworking that to be more performant ( #4531 )
I think the way forward here is to determine why msgpack is the only serialisation option for HLG's. IIRC this is to avoid remote code execution on the scheduler?
Yes, this is primarily to avoid remote code execution on the scheduler.
Since the literals are not need by the scheduler but by the workers, we can make Blockwise.__dask_distributed_pack__ serialize them using to_serialize(). This should be fairly straightforward to handle once #4531 is in. If there is no rush, I can put it on my to do list.
Thanks @madsbk, I would appreciate that! As mentioned, I have managed to use msgpack-numpy to unblock myself in the interim so I am not in a particular rush.
This seems to have resolved the problem! Thanks @madsbk! I will be doing further testing over the coming week and will let you know if I encounter any further issues.
Reacted by Mads R. B. Kristensen, James Bourbeau and jakirkham
Activity
JSKenyon commentedon Feb 15, 2021
The following also fails:
JSKenyon commentedon Feb 15, 2021
I have confirmed that this bug is also present in the latest release (distributed==2021.2.0).
JSKenyon commentedon Feb 15, 2021
The last version on which the following example runs through is distributed==2.30.1. Thereafter it always fails. Note that failure will not occur with
optimize_graph=True. However, I am busy experimenting with annotations and I need to disable task fusion.TomAugspurger commentedon Feb 15, 2021
Thanks for the report. Taking a look now.
TomAugspurger commentedon Feb 15, 2021
I'm able to reproduce. It looks like the root cause is that
Blockwise.__dask_distributed_pack__can return inputs that aren't msgpack serializable. In this case, the blockwise layer's.indicesincludes the ndarraynp.array([1.]).@madsbk I'd be curious to get your thoughts here. Do we require that the values in
__dask_distributed_pack__be msgpack serializable?madsbk commentedon Feb 16, 2021
Yes because of the new high level graph
da.blockwisedoesn't support numpy arrays directly. E.g. theda.ufuncclass callsda.asarray()on the inputs to make sure that they are dask arrays, which in turn makes them compatible with__dask_distributed_pack__.The following should work:
Having said that, we might consider making
da.blockwisesupport NumPy arrays directly.JSKenyon commentedon Feb 16, 2021
If I may ask @madsbk, is it expected that the last example I posted above used to work and now doesn't? That seems like it might be a regression, but I appreciate that I am no expert.
sjperkins commentedon Feb 16, 2021
I think this is a regression, because if the argument index is None, then the docs say that the argument is treated as literal, not a dask array. Hence any literal will now need to be msgpackable, whereas previously it would all go through dask's
dask.protocol.serialize.{serialize,deserialize}functionality.madsbk commentedon Feb 16, 2021
I agree, this is a regression and if it something that is useful for people we should support it :)
JSKenyon commentedon Feb 16, 2021
This is quite critical/useful to my project (I am already using this behaviour), so a definite thumbs up from me.
TomAugspurger commentedon Feb 16, 2021
@madsbk do you have a sense for what the best path forward is?
Blockwise.__dask_distributed_pack__use dask-serializedumps_msgpackhow to handle ndarrayshighlevelgraph_packandhighlevelgraph_unpackuse / optionally fall back to dask's serialization?jakirkham commentedon Feb 16, 2021
We've been discussing optimizing the serialization pipeline to go through MsgPack more directly (with fewer passes over the data) ( #4379 ). The interest being to improve performance of serialization and simplify that code. This would effectively include 2. Though it doesn't preclude us from doing other things as well in the interim
JSKenyon commentedon Feb 23, 2021
It seems that
msgpack-numpyis an adequate workaround in the interim. Not sure if it is something to rely on, but it unblocks me for now.jakirkham commentedon Feb 23, 2021
Sorry if I overlooked it, but what NumPy version is this using?
JSKenyon commentedon Feb 23, 2021
numpy==1.20.02 remaining items
JSKenyon commentedon Feb 23, 2021
I have tested
numpy==1.19.5and, unfortunately, the problem persists.jakirkham commentedon Feb 23, 2021
Interesting thanks for the update
What if
np.dtype("u2")is used instead? Or even just"u2"? Maybe something peculiar aboutnp.uint16as opposed to a dtype objectOr perhaps it is just the scalar value? Can
0be used without typing?JSKenyon commentedon Feb 23, 2021
I have tried this - it doesn't matter what the specific type is. I have tried several and they all fail (
np.float64andnp.dtype('f8')both fail, as an example). I think it just boils down to none of them being msgpack serializable.Scalar values work but likely only because msgpack can cope with Python's builtins.
np.float32(0)does not work, for example.jakirkham commentedon Feb 23, 2021
Right so I think we are getting the crux of the issue. Namely I don’t think Dask (currently) handles serialization of NumPy scalars. I think this support could be added and should be pretty straightforward. Is this something you would be interested in doing? 🙂
sjperkins commentedon Feb 23, 2021
I don't believe this only affects numpy scalars and arrays, as the following example demonstrates:
With optimisation (the default distributed/dask behaviour for a long time), the above succeeds, because
dask.protocol.serialize.{serialize,deserialize}is invoked on the optimised low-level graph.dask.protocol.serialize.{serialize,deserialize}can defer to custom serialisation routines, in addition to standard pickle. blockwise does support embedding literals (presumably of any type) in the graph.Without optimisation, the above fails because
dask.protocol.highlevelgraph.highlevelgraph_packis invoked on the HLG, which only supports msgpack as a serialisation protocol.This regression is only exposed when graph optimisation is turned off.
sjperkins commentedon Feb 23, 2021
I think the way forward here is to determine why msgpack is the only serialisation option for HLG's. IIRC this is to avoid remote code execution on the scheduler?
If not, would it be possible to use distributed standard serialisation routines for HLG serialisation?
jakirkham commentedon Feb 23, 2021
I believe (though Mads may correct me) the reason for HLG using only msgpack is to keep serialization efficient.
There’s some additional overhead we have been finding in Dask’s custom serialization, but we are looking at reworking that to be more performant ( #4531 )
madsbk commentedon Feb 23, 2021
Yes, this is primarily to avoid remote code execution on the scheduler.
Since the literals are not need by the scheduler but by the workers, we can make
Blockwise.__dask_distributed_pack__serialize them usingto_serialize(). This should be fairly straightforward to handle once #4531 is in. If there is no rush, I can put it on my to do list.JSKenyon commentedon Feb 24, 2021
Thanks @madsbk, I would appreciate that! As mentioned, I have managed to use
msgpack-numpyto unblock myself in the interim so I am not in a particular rush.JSKenyon commentedon Feb 24, 2021
Turns out that my
msgpack-numpytrick only works in some cases. So this is perhaps a little more urgent than I thought.jakirkham commentedon Mar 12, 2021
@JSKenyon can you please test with Mads PR ( dask/dask#7353 ) (just merged)? 🙂
JSKenyon commentedon Mar 15, 2021
@jakirkham Will do! If not today, then tomorrow.
JSKenyon commentedon Mar 15, 2021
This seems to have resolved the problem! Thanks @madsbk! I will be doing further testing over the coming week and will let you know if I encounter any further issues.
jrbourbeau commentedon Mar 15, 2021
Awesome, thanks @JSKenyon