new function.



torch.dot                            # [D], [D] -> []
batched_dot = torch.func.vmap(torch.dot)  # [N, D], [N, D] -> [N]
x, y = torch.randn(2, 5), torch.randn(2, 5)
batched_dot(x, y)



"vmap()" can be helpful in hiding batch dimensions, leading to a
   simpler model authoring experience.



batch_size, feature_size = 3, 5
weights = torch.randn(feature_size, requires_grad=True)
def model(feature_vec):
    # Very simple linear model with activation
    return feature_vec.dot(weights).relu()
examples = torch.randn(batch_size, feature_size)
result = torch.vmap(model)(examples)



"vmap()" can also help vectorize computations that were previously
   difficult or impossible to batch. One example is higher-order
   gradient computation. The PyTorch autograd engine computes vjps
   (vector-Jacobian products). Computing a full Jacobian matrix for
   some function f: R^N -> R^N usually requires N calls to