Introduce namespaces for tensor node IDs
This is critical for "model surgery": being able to load weights of independently developed models, or weights of two snapshots of the same model.
We add a type Tnode.id = { namespace : string; s_id : int } where s_id is the consecutive number for nodes created in the current session. As before, this type is used for both Tnode.t and Tensor.t IDs. Tensor.unsafe_reinitialize ~namespace is the only way to change the namespace of newly created tensors, and the default namespace is ocannl.
s_id of Tnode.id is a double-mnemonic for within-session id and self id. We make the operation Embed_self_id use just the s_id part so that it is invariant to namespace change -- specifically namespace prefixing.
In the future we will have a few ways of loading back tensors: load ?prefix_namespace will optionally prefix the namespaces of all the tensors stored in a file, check that there is no clash of loaded tensors with any existing tensors (via the registry) -- raising error on a clash, and will return the resulting set of tensors. restore t_set will take a set of tensors, find them in the file as-is and update the hosted buffers from the stored values -- raising error if a given tensor is missing in the file. I will add this as a separate issue, it is out of scope for this issue and mentioned here to provide some motivation for namespaces.