In [1]:
import torch
import numpy as np
from __future__ import print_function

What is a Tensor?

  • Scalar is a single number.
  • Vector is an array of numbers.
  • Matrix is a 2-D array of numbers.
  • Tensors are N-D arrays of numbers.

In [2]:
x = torch.Tensor(5, 3)
print(x)


 8.5289e+30  4.5849e-41  8.5289e+30
 4.5849e-41  0.0000e+00  0.0000e+00
 0.0000e+00  0.0000e+00  0.0000e+00
 0.0000e+00  0.0000e+00  0.0000e+00
 8.9683e-44  0.0000e+00  1.5695e-43
[torch.FloatTensor of size 5x3]


In [3]:
x.zero_()


Out[3]:
 0  0  0
 0  0  0
 0  0  0
 0  0  0
 0  0  0
[torch.FloatTensor of size 5x3]

In [4]:
torch.Tensor([[1, 2, 3],  # rank 2 tensor
              [4, 5, 6],
              [7, 8, 9]])


Out[4]:
 1  2  3
 4  5  6
 7  8  9
[torch.FloatTensor of size 3x3]

In [5]:
x.size()


Out[5]:
torch.Size([5, 3])

In [6]:
x = torch.rand(5, 3)
print(x)


 0.6483  0.0793  0.5400
 0.4856  0.7982  0.0293
 0.5717  0.4678  0.6365
 0.8806  0.0632  0.2726
 0.3934  0.7143  0.9290
[torch.FloatTensor of size 5x3]


In [7]:
npy = np.random.rand(5, 3)
y = torch.from_numpy(npy)
print(y)


 0.0576  0.1174  0.9857
 0.6809  0.1037  0.7149
 0.2107  0.7510  0.7408
 0.3281  0.5182  0.5043
 0.7946  0.7321  0.0289
[torch.DoubleTensor of size 5x3]


In [40]:
z = x + y  #can we do this addition?

In [9]:
x.type(), y.type()


Out[9]:
('torch.FloatTensor', 'torch.DoubleTensor')

In [10]:
z = x + y.float()
print(z)


 0.7059  0.1967  1.5258
 1.1665  0.9019  0.7442
 0.7824  1.2188  1.3774
 1.2087  0.5815  0.7768
 1.1880  1.4464  0.9579
[torch.FloatTensor of size 5x3]


In [11]:
torch.add(x, y.float())


Out[11]:
 0.7059  0.1967  1.5258
 1.1665  0.9019  0.7442
 0.7824  1.2188  1.3774
 1.2087  0.5815  0.7768
 1.1880  1.4464  0.9579
[torch.FloatTensor of size 5x3]

In [12]:
x


Out[12]:
 0.6483  0.0793  0.5400
 0.4856  0.7982  0.0293
 0.5717  0.4678  0.6365
 0.8806  0.0632  0.2726
 0.3934  0.7143  0.9290
[torch.FloatTensor of size 5x3]

In [13]:
x.add_(1)


Out[13]:
 1.6483  1.0793  1.5400
 1.4856  1.7982  1.0293
 1.5717  1.4678  1.6365
 1.8806  1.0632  1.2726
 1.3934  1.7143  1.9290
[torch.FloatTensor of size 5x3]

In [14]:
x


Out[14]:
 1.6483  1.0793  1.5400
 1.4856  1.7982  1.0293
 1.5717  1.4678  1.6365
 1.8806  1.0632  1.2726
 1.3934  1.7143  1.9290
[torch.FloatTensor of size 5x3]

In [15]:
x[:2, :2]


Out[15]:
 1.6483  1.0793
 1.4856  1.7982
[torch.FloatTensor of size 2x2]

In [16]:
x * y.float()


Out[16]:
 0.0950  0.1267  1.5181
 1.0116  0.1864  0.7359
 0.3312  1.1023  1.2124
 0.6170  0.5510  0.6417
 1.1072  1.2550  0.0557
[torch.FloatTensor of size 5x3]

In [17]:
torch.exp(x)


Out[17]:
 5.1981  2.9428  4.6647
 4.4176  6.0391  2.7991
 4.8146  4.3398  5.1374
 6.5573  2.8957  3.5701
 4.0286  5.5531  6.8828
[torch.FloatTensor of size 5x3]

In [18]:
torch.transpose(x, 0, 1)


Out[18]:
 1.6483  1.4856  1.5717  1.8806  1.3934
 1.0793  1.7982  1.4678  1.0632  1.7143
 1.5400  1.0293  1.6365  1.2726  1.9290
[torch.FloatTensor of size 3x5]

In [19]:
#transposing, indexing, slicing, mathematical operations, linear algebra, random numbers

In [20]:
torch.trace(x)


Out[20]:
5.0830910205841064

In [21]:
x.numpy()


Out[21]:
array([[ 1.64829206,  1.0793463 ,  1.54002655],
       [ 1.48560095,  1.79824984,  1.02928591],
       [ 1.57166302,  1.46782982,  1.63654912],
       [ 1.88058376,  1.06322587,  1.27258039],
       [ 1.39342725,  1.71434927,  1.9290216 ]], dtype=float32)

In [22]:
torch.cuda.is_available()


Out[22]:
True

In [23]:
if torch.cuda.is_available():
    x_gpu = x.cuda()
    print(x_gpu)


 1.6483  1.0793  1.5400
 1.4856  1.7982  1.0293
 1.5717  1.4678  1.6365
 1.8806  1.0632  1.2726
 1.3934  1.7143  1.9290
[torch.cuda.FloatTensor of size 5x3 (GPU 0)]


In [24]:
from torch.autograd import Variable

In [25]:
x = torch.rand(5, 3)
print(x)


 0.5759  0.1624  0.1933
 0.6926  0.3969  0.3648
 0.0467  0.9384  0.9780
 0.0718  0.2979  0.9483
 0.1604  0.4656  0.2753
[torch.FloatTensor of size 5x3]


In [26]:
x = Variable(torch.rand(5, 3))
print(x)


Variable containing:
 0.7786  0.9588  0.3944
 0.2147  0.5184  0.6126
 0.2722  0.9937  0.2327
 0.9567  0.5470  0.4463
 0.6881  0.2854  0.4447
[torch.FloatTensor of size 5x3]

Each variable holds data, a gradient, and information about the function that created it. <img src="figures/intro_to_pytorch/pytorch_variable.svg",width=400,height=400>


In [28]:
x.data


Out[28]:
 0.7786  0.9588  0.3944
 0.2147  0.5184  0.6126
 0.2722  0.9937  0.2327
 0.9567  0.5470  0.4463
 0.6881  0.2854  0.4447
[torch.FloatTensor of size 5x3]

In [29]:
# should be nothing right now
assert x.grad_fn is None
assert x.grad is None

In [31]:
x = Variable(torch.Tensor([2]), requires_grad=True)
w = Variable(torch.Tensor([3]), requires_grad=True)
b = Variable(torch.Tensor([1]), requires_grad=True)

z = x * w
y = z + b

y


Out[31]:
Variable containing:
 7
[torch.FloatTensor of size 1]

Compare the above computations to the below graph.. and then the one below that!


In [32]:
y.backward()

In [33]:
y, b


Out[33]:
(Variable containing:
  7
 [torch.FloatTensor of size 1], Variable containing:
  1
 [torch.FloatTensor of size 1])

Since the derivative of w*x wrt x is w, and vice versa:


In [34]:
w.grad, w


Out[34]:
(Variable containing:
  2
 [torch.FloatTensor of size 1], Variable containing:
  3
 [torch.FloatTensor of size 1])

In [35]:
x.grad, x


Out[35]:
(Variable containing:
  3
 [torch.FloatTensor of size 1], Variable containing:
  2
 [torch.FloatTensor of size 1])

$ y = 2w + b$, since $x = 2$

Say we want: $\displaystyle\frac{\partial y}{\partial w}$


In [36]:
a = Variable(torch.Tensor([2]), requires_grad=True)

Let's compute, $\displaystyle\frac{\partial}{\partial a}(3a^2 + 2a + 1)$ when $a = 2$


In [37]:
y = 3*a*a + 2*a + 1

In [38]:
y.backward()

In [39]:
a.grad


Out[39]:
Variable containing:
 14
[torch.FloatTensor of size 1]

checks out, since $\displaystyle\frac{\partial}{\partial a}(3a^2 + 2a + 1) = 6a + 2$ and $a = 2$