google / TensorNetwork

A library for easy and efficient manipulation of tensor networks.
Apache License 2.0
1.82k stars 357 forks source link

Reusing contraction paths #175

Open stavros11 opened 5 years ago

stavros11 commented 5 years ago

Since many contractors are based on opt_einsum it might be useful to add support for its path reuse functionality. This would save time when contracting the same network multiple times (for example during optimization).

chaserileyroberts commented 5 years ago

Good idea! This is also similar to https://github.com/google/TensorNetwork/issues/73, which we wanted to build for path reuse and parallel/distributed contraction.

MichaelMarien commented 5 years ago

How'd you image the API? Explicit like,

resulting_net, optimal_path= path_algorithm(net) ... path_algorithm(another_net, optimal_path)?

That would be straightforward to implement imo, if @stavros11 has no time, I could take a look for sure.

stavros11 commented 5 years ago

This API would work at least for the optimization example. This would look like:

tensors = ... # initialize tensors
net = create_network(tensors)
optimal_path = None
for _ in range(num_epochs):
  result, optimal_path = path_algorithm(net, optimal_path)
  update(tensors) # update tensors using result, gradients, etc.
  net = create_network(tensors)

So path_algorithm should calculate the optimal path only when it is None, otherwise it should use the given path. I don't have problem with time but feel free to take a look if you like, if other people also agree with this API.

Another concern I have is that the optimal path returned by opt_einsum assumes an ordering of nodes in the network, while TensorNetwork stores them in a set which is unordered. If the TensorNetwork ordering changes every time you create a new network (I am not sure if it does), then this strategy won't work.

chaserileyroberts commented 5 years ago

Let me think about the API a little bit longer.

Originally we planned to have ContractionTree proto and ContractionNetwork objects to do something similar. So that would look like this:

# ContractionNetwork is exactly the same as a `TensorNetwork`, except without
# concrete tensors, only `ShapeTensor`s.
net = build_network(...)
shell_network = tensornetwork.ContractionNetwork(net)
# Since ContractionNetwork has the same API as TensorNetwork,
# this should just work.
shell_network = path_algorithm(shell_network)
# The ContractionNetwork will keep track of the ContractionTree,
# which will be implemented as a proto, and thus allows easy
# saving/loading from disk 
save_tree(shell_network.tree, "/path/to/file.pb")
# Networks that are created in the same way as the previous
# network can use the same tree for contraction.
saved_contraction_tree = load("/path/to/file.pb")
new_net = build_network(...)
# And we can contract the new network with the old ContractionTree definition.
new_net = tensornetwork.contract_from_tree_def(new_net, saved_contraction_tree)

I'm not sure this is the BEST way of doing it, but it seems pretty nice. (of course the function names are likely to change).

This also allows for easy distribution of computation, since each branch of the contraction tree can run on independent workers, minimizing communication until absolutely necessary. And that API would just look like

net = build_network(...)
shell_network = tensornetwork.ContractionNetwork(net)
shell_network = path_algorithm(shell_network)
workers = ["list", "of", "remote", "workers", ...]
net = tensornetwork.async_contraction(net, shell_network.tree, workers).
chaserileyroberts commented 5 years ago

Another concern I have is that the optimal path returned by opt_einsum assumes an ordering of nodes in the network, while TensorNetwork stores them in a set which is unordered. If the TensorNetwork ordering changes every time you create a new network (I am not sure if it does), then this strategy won't work.

Nodes have signatures based on the order they are created in the network. As long as you use the same code to contract the network, it should be fine.

MichaelMarien commented 5 years ago

Let me think about the API a little bit longer.

@Thenerdstation ,sure just give a bump here when you settle on the API, I can take it up.

amilsted commented 5 years ago

Just pointing out here that one can also use graph-building or JIT to make path finding a one-time cost.

That said, I think it would be great to have ContractionTree objects, which could also form the basis for automatic parallelization of contractions, efficient computation of multiple derivatives (environments) of tensor networks, and would also be handy for querying the contraction produced by a Contractor (say, to find out the order used, or the cost of each step).