To add to what @albanD wrote, here’s also a quick demo of  Autograd overhead.
class NoOp(torch.autograd.Function):
    def __init__(self):
        super().__init__()
        
    def forward(self, x):
        return x

def print_times(x, func, msg):
    start = time.time()
    for i in range(1000000):
        _ = func(x)
    t = time.time() - start
    print("{}: {:.5f}".format(msg, t))

tensor   = torch.randn(100, 500)
ndarray  = tensor.numpy()
variable = Variable(tensor)
    
print_times(tensor,   lambda x: x,             "Python noop")
print_times(ndarray,  lambda x: x.transpose(), "Numpy transpose")
print_times(tensor,   lambda x: x.t(),         "Torch transpose")
print_times(variable, lambda x: NoOp()(x),     "Autograd noop")
print_times(variable, lambda x: x.t(),         "Autograd transpose")

# output:
#
# Python noop: 0.07554
# Numpy transpose: 0.23783
# Torch transpose: 0.49813
# Autograd noop: 1.95098
# Autograd transpose: 3.72835