# PyTorch

Published:

This lesson covers PyTorch Tutorial, https://pytorch.org/tutorials/beginner/basics/intro.html

# Tensors

topic = "pytorch"
lesson = 2

from n import *
home, models_path = get_project_dir("FashionMNIST")
print(home)

/home/naneja/datasets/n/FashionMNIST

import torch
import numpy as np


## Initializing a Tensor

# directly from data
data = [[1, 2], [3, 4]]

x_data = torch.tensor(data)
print_(f"x_data={x_data}")


x_data = tensor([[1, 2], [3, 4]])

# from NumPy array

data = [[1, 2], [3, 4]]

np_array = np.array(data)
print_(f"np_array={np_array}")

x_np = torch.from_numpy(np_array)
print_(f"x_np={x_np}")


np_array = [[1 2] [3 4]]

x_np = tensor([[1, 2], [3, 4]])

# from another array

data = [[1, 2], [3, 4]]

x_data = torch.tensor(data)
print_(f"x_data={x_data}")

# retains the properties (shape, datatype)
x_ones = torch.ones_like(x_data)

# retains shape but overrides the datatype
x_rand = torch.rand_like(x_data, dtype=torch.float)

print_("Ones Tensor:", x_ones)
#print(x_ones)

print_("Random Tensor:", x_rand)
#print(x_rand)



x_data = tensor([[1, 2], [3, 4]])

Ones Tensor:

tensor([[1, 1],
[1, 1]])


Random Tensor:

tensor([[0.5770, 0.4122],
[0.3629, 0.4553]])

# With random or constant values
shape = (2,3,)

rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print_("Random Tensor:", rand_tensor)

print_("Ones Tensor:", ones_tensor)

print_("Zeros Tensor:", zeros_tensor)


Random Tensor:

tensor([[0.7589, 0.4365, 0.9772],
[0.6484, 0.0067, 0.0211]])


Ones Tensor:

tensor([[1., 1., 1.],
[1., 1., 1.]])


Zeros Tensor:

tensor([[0., 0., 0.],
[0., 0., 0.]])


## Attributes of a Tensor

• shape
• datatype
• device on which they are stored
tensor = torch.rand(3,4)

print_(f"Shape of tensor: {tensor.shape}")
print_(f"Datatype of tensor: {tensor.dtype}")
print_(f"Device tensor is stored on: {tensor.device}")


Shape of tensor: torch.Size([3, 4])

Datatype of tensor: torch.float32

Device tensor is stored on: cpu

## Operations on Tensors

• https://pytorch.org/docs/stable/torch.html
print_("https://pytorch.org/docs/stable/torch.html")


https://pytorch.org/docs/stable/torch.html

# Move to the GPU if available
tensor = torch.rand(3,4)
print_(f"tensor", tensor)

if torch.cuda.is_available():
tensor = tensor.to("cuda")
print_(f"tensor", tensor)

tensor = tensor.to("cpu")
print_(f"tensor", tensor)


tensor

tensor([[0.5592, 0.6119, 0.9760, 0.5708],
[0.1763, 0.5915, 0.8959, 0.7148],
[0.2837, 0.7816, 0.9187, 0.6705]])


tensor

tensor([[0.5592, 0.6119, 0.9760, 0.5708],
[0.1763, 0.5915, 0.8959, 0.7148],
[0.2837, 0.7816, 0.9187, 0.6705]], device='cuda:0')


tensor

tensor([[0.5592, 0.6119, 0.9760, 0.5708],
[0.1763, 0.5915, 0.8959, 0.7148],
[0.2837, 0.7816, 0.9187, 0.6705]])

# Standard numpy-like indexing and slicing:

tensor = torch.ones(4, 4)

print_("tensor", tensor)

print_(f"First row: {tensor[0]}")

print_(f"First column: {tensor[:, 0]}") # column = 0

print_(f"Last column: {tensor[..., -1]}") # column = -1

tensor[:, 1] = 0 # 1st index 1 and any zeroth index = 0

print_("tensor", tensor)


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


First row: tensor([1., 1., 1., 1.])

First column: tensor([1., 1., 1., 1.])

Last column: tensor([1., 1., 1., 1.])

tensor

tensor([[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.],
[1., 0., 1., 1.]])

# Joining tensors

tensor = torch.ones(4, 4)

t1 = torch.cat([tensor, tensor, tensor], dim=1)

t0 = torch.cat([tensor, tensor, tensor], dim=0)

print_("tensor", tensor)

print_("dim=1", t1)

print_("dim=0", t0)


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


dim = 1

tensor([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]])


dim = 0

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


### Arithmetic operations

# Matrix Multiplications

tensor = torch.ones(4, 4)
print_("tensor")
print(tensor)

# Matrix multiplication between two tensors
y1 = tensor @ tensor.T
print_("tensor @ tensor.T")
print(y1)

y2 = tensor.matmul(tensor.T)
print_("tensor.matmul(tensor.T)")
print(y2)

out = torch.rand(4,4)
y3 = torch.matmul(tensor, tensor.T, out=out)
print_("torch.matmul(tensor, tensor.T, out=torch.rand(4,4))")
print(y3)


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


tensor @ tensor.T

tensor([[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]])


tensor.matmul(tensor.T)

tensor([[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]])


torch.matmul(tensor, tensor.T, out = torch.rand(4,4))

tensor([[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]])

# Element-wise product

tensor = torch.ones(4, 4)
print_("tensor")
print(tensor)

z1 = tensor * tensor
print_("tensor * tensor")
print(z1)

z2 = tensor.mul(tensor)
print_("tensor.mul(tensor)")
print(z2)

out = torch.rand(4,4)
z3 = torch.mul(tensor, tensor, out=out)
print_("torch.mul(tensor, tensor, out=torch.rand(4,4))")
print(z3)


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


tensor * tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


tensor.mul(tensor)

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


torch.mul(tensor, tensor, out = torch.rand(4,4))

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


### Single-element tensors

tensor = torch.ones(4, 4)
print_("tensor")
print(tensor)

# One element tensor
print_("tensor.sum()")
print(tensor.sum())

# One element tensor converted to numpy
print_("tensor.sum().item()")
print(tensor.sum().item())


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


tensor.sum()

tensor(16.)


tensor.sum().item()

16.0


### In-place Operations

• save some memory, but can be problematic when computing derivatives because of an immediate loss of history
• Hence, their use is discouraged
tensor = torch.ones(4, 4)
print_("tensor")
print(tensor)

print_("tensor")
print(tensor)

print_("tensor")
print(tensor)


tensor

tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])


tensor

tensor([[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.],
[4., 4., 4., 4.]])


tensor

tensor([[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.],
[7., 7., 7., 7.]])


## Bridge with NumPy

• Tensors on the CPU and NumPy arrays can share their underlying memory locations, and changing one will change the other
t = torch.ones(5)
print_(f"t = {t}")

n = t.numpy()
print_(f"n = {n}")

# change in the tensor reflects in the NumPy array

print_(f"t = {t}")
print_(f"n = {n}")


t = tensor([1., 1., 1., 1., 1.])

n = [1. 1. 1. 1. 1.]

t = tensor([2., 2., 2., 2., 2.])

n = [2. 2. 2. 2. 2.]

# NumPy array to Tensor

n = np.ones(5)
t = torch.from_numpy(n)

print_(f"n = {n}")
print_(f"t = {t}")


n = [4. 4. 4. 4. 4.]

t = tensor([4., 4., 4., 4., 4.], dtype = torch.float64)

n = np.ones(5)
t = torch.from_numpy(n)

print_(f"n = {n}")
print_(f"t = {t}")


n = [4. 4. 4. 4. 4.]

t = tensor([4., 4., 4., 4., 4.], dtype = torch.float64)




Tags: