Pytorch For Beginners
Pytorch For Beginners
Pytorch For Beginners
import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
print(torch.__version__)
2.3.1+cu121
Introduction to Tensors
Creating tensors
# scaler
scaler = torch.tensor(8)
scaler
tensor(8)
type(scaler)
torch.Tensor
# dimension
scaler.ndim
scaler.item()
Vector
# vector
vector = torch.tensor([1,2])
vector
tensor([1, 2])
vector.ndim
vector
tensor([1, 2])
vector.shape
torch.Size([2])
# MATRIX
MATRIX = torch.tensor([[7,8],
[9,10]])
MATRIX
tensor([[ 7, 8],
[ 9, 10]])
MATRIX.ndim
MATRIX[1]
tensor([ 9, 10])
MATRIX.shape
torch.Size([2, 2])
# TENSOR
TENSOR = torch.tensor([[[1,2,3],
[3,6,9],
[2,4,5]]])
TENSOR
tensor([[[1, 2, 3],
[3, 6, 9],
[2, 4, 5]]])
TENSOR.ndim
TENSOR.shape
torch.Size([1, 3, 3])
TENSOR = torch.tensor([[[1,2,3],
[3,6,9],
[2,4,5]],
[[1,2,3],
[3,6,9],
[2,4,5]]])
TENSOR
tensor([[[1, 2, 3],
[3, 6, 9],
[2, 4, 5]],
[[1, 2, 3],
[3, 6, 9],
[2, 4, 5]]])
TENSOR.shape
torch.Size([2, 3, 3])
TENSOR[0]
tensor([[1, 2, 3],
[3, 6, 9],
[2, 4, 5]])
Random tensors
Why random tensors?
Random tensors are important because they way many neural networks learn is that they start with tensors full of random numbers and
then adjust those random numbers to better represent the data.
Start with random numbers -> look at the data -> update random numbers -> look at data -> update
random numbers
random_tensor
random_tensor.ndim
random_tensor = torch.rand(2,3,4)
random_tensor
random_tensor.ndim
3
zeros * random_tensor
ones.dtype
torch.float32
random_tensor.dtype
torch.float32
# Use torch.range()
torch.range(0,10)
torch.arange(0,10)
tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
one_to_ten = torch.arange(1,11)
one_to_ten
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
tensor([ 0, 77, 154, 231, 308, 385, 462, 539, 616, 693, 770, 847, 924])
# Create tensors like -> same shape like one_to_ten and value is 0
ten_zeros = torch.zeros_like(input = one_to_ten)
ten_zeros
tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Tensor Datatype
Note: Tensor datatypes is one of the 3 big errors you'll run into with PyTorch & deep Learning:
# Float 32 tensor
float_32_tensor = torch.tensor([3.0, 6.0, 9.0],
dtype = None)
float_32_tensor
float_32_tensor.dtype
torch.float32
float_32_tensor.dtype
torch.float16
float_16_tensor = float_32_tensor.type(torch.float16)
float_16_tensor
float_16_tensor * float_32_tensor
float_32_tensor * int_32_tensors
tensor([3, 6, 9])
int_long_tensors * float_16_tensor
# create a tensor
some_tensor = torch.rand(3,4)
some_tensor
Addition
Substraction
Multiplication (element - wise)
Division
Matrix multiplication
# Create a tensor
tensor = torch.tensor([1,2,3])
tensor + 10
# Multiply tensor by 10
tensor * 10
# subtract 10
tensor - 10
Matrix multiplication
http://matrixmultiplication.xyz/
Two main ways of performing multiplications in neural networks and deep learning:
1. Element-wise multiplication
2. Matrix multiplication(dot product)
There are two main rules that performing matrix multiplication needs to satisfy:
# Matrix multiplication
torch.matmul(tensor , tensor)
tensor(14)
tensor @ tensor
tensor(14)
%%time
value = 0
for i in range(len(tensor)):
value += tensor[i] * tensor[i]
print(value)
tensor(14)
CPU times: user 1.47 ms, sys: 81 µs, total: 1.55 ms
Wall time: 1.42 ms
%%time
torch.matmul(tensor,tensor)
# torch.mm(tensor_A, tensor_B) # torch.mm is the same as torch.matmul (its an alias for writng less code)
torch.matmul(tensor_A, tensor_B)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-118-9cf80e10b890> in <cell line: 11>()
9
10 # torch.mm(tensor_A, tensor_B) # torch.mm is the same as torch.matmul (its an alias for writng less cod
e)
---> 11 torch.matmul(tensor_A, tensor_B)
RuntimeError: mat1 and mat2 shapes cannot be multiplied (3x2 and 3x2)
tensor_A.shape, tensor_B.shape
To fix our tensor shape issues, we can manipulate the shape of one of our tensors using a transpose
tensor_B
tensor([[ 7, 8],
[ 8, 11],
[ 9, 12]])
tensor_B.T
tensor([[ 7, 8, 9],
[ 8, 11, 12]])
tensor([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
(tensor(0), tensor(0))
(tensor(90), tensor(90))
# Find the mean - note: the torch.mean() function requires a tensor of float32f datatype to work
torch.mean(x.type(torch.float32)), x.type(torch.float32)
(tensor(45.), tensor([ 0., 10., 20., 30., 40., 50., 60., 70., 80., 90.]))
(tensor(450), tensor(450))
tensor([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
''' find the positiioin in tensor that has the minimum value
with argmin() -> returns index position of target tensor where the minimum value occurs '''
x.argmin()
tensor(0)
x[0]
tensor(0)
# Find the position in tensor that has the maximum value with argmax()
x.argmax()
tensor(9)
x[9]
tensor(90)
https://pytorch.org/docs/stable/generated/torch.squeeze.html
Unsqueeze - add a 1 dimension to a target tensor
https://pytorch.org/docs/stable/generated/torch.unsqueeze.html
Permute - Return a view of the input with dimensions permuted (swapped) in a certain way
https://pytorch.org/docs/stable/generated/torch.permute.html
(tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.]), torch.Size([9]))
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-134-8b576cbba5d6> in <cell line: 2>()
1 # add an extra dimension
----> 2 x_reshaped = x.reshape(1,7) #1*7 = 7 but element is 10. So, not possible to reshape
3 x_reshaped, x_reshaped.shape
x_reshaped = x.reshape(9,1)
x_reshaped, x_reshaped.shape
(tensor([[1.],
[2.],
[3.],
[4.],
[5.],
[6.],
[7.],
[8.],
[9.]]),
torch.Size([9, 1]))
y = torch.arange(1., 15.)
y, y.shape
(tensor([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14.]),
torch.Size([14]))
y_reshaped = y.reshape(2,7) # 2*7 = 14 and elements also 14. So, which means this is possible to reshape
y_reshaped, y_reshaped.shape
x_reshaped = x.reshape(1,9)
x_reshaped, x_reshaped.shape
(tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]]), torch.Size([1, 9]))
(tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]]), torch.Size([1, 9]))
# Changing z changes x (because a view of a tensor shares the same memory as the original input)
z[:, 0] = 5
z, x
# vstack
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
torch.vstack((a,b))
tensor([[1, 2, 3],
[4, 5, 6]])
a = torch.tensor([[1],[2],[3]])
b = torch.tensor([[4],[5],[6]])
torch.vstack((a,b))
tensor([[1],
[2],
[3],
[4],
[5],
[6]])
# hstack
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
torch.hstack((a,b))
tensor([1, 2, 3, 4, 5, 6])
a = torch.tensor([[1],[2],[3]])
b = torch.tensor([[4],[5],[6]])
torch.hstack((a,b))
tensor([[1, 4],
[2, 5],
[3, 6]])
Previous tensor:tensor([[5., 2., 3., 4., 5., 6., 7., 8., 9.]])
Previous shape:torch.Size([1, 9])
New tensor:tensor([5., 2., 3., 4., 5., 6., 7., 8., 9.])
New shape:torch.Size([9])
Previous target:tensor([5., 2., 3., 4., 5., 6., 7., 8., 9.])
Previous shape:torch.Size([9])
New tensor:tensor([[5., 2., 3., 4., 5., 6., 7., 8., 9.]])
New shape:torch.Size([1, 9])
print(f"Previous target:{x_squeezed}")
print(f"Previous shape:{x_squeezed.shape}")
Previous target:tensor([5., 2., 3., 4., 5., 6., 7., 8., 9.])
Previous shape:torch.Size([9])
New tensor:tensor([[5.],
[2.],
[3.],
[4.],
[5.],
[6.],
[7.],
[8.],
[9.]])
New shape:torch.Size([9, 1])
torch.Size([5, 2, 3])
# Permute the original tensor to rearrange the axis (or dim) order
x_permuted = x_original.permute(2,0,1) # shifts axis 0->1 , 1 -> 2, 2 -> 0
torch.rand(size = (3,3,5))
# Create a tensor
import torch
x = torch.arange(1,10).reshape(1,3,3)
x, x.shape
(tensor([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]]),
torch.Size([1, 3, 3]))
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
tensor([1, 2, 3])
tensor(1)
x[0][2][2]
tensor(9)
tensor([[1, 2, 3]])
# Get all values of 0th and 1st dimensions but only index 1 of 2nd dimension
x[:,:,1]
tensor([[2, 5, 8]])
# Get all values of the 0th dimension but only the 1 index value of 1st and 2nd dimension
x[:,1,1]
tensor([5])
# Get index 0 of 0th and 1st dimension and all values of 2nd dimension
x[0,0,:]
tensor([1, 2, 3])
# Index on x to return 9
print(x[0][2][2])
# Index on x to return 3, 6, 9
print(x[:,:,2])
tensor(9)
tensor([[3, 6, 9]])
array.dtype
dtype('float64')
torch.arange(1.0, 8.0).dtype
torch.float32
tensor = torch.from_numpy(array).type(torch.float32)
tensor.dtype
torch.float32
array = array + 1
array, tensor
(array([2., 3., 4., 5., 6., 7., 8.]), tensor([1., 2., 3., 4., 5., 6., 7.]))
tensor.dtype
torch.float32
start with random numbers -> tensor operations -> update random numbers to try and make them better
representations of the data -> again -> again -> again...
To reduce the randomness in neural networks and PyTorch comes the concept of a random seed>
https://pytorch.org/docs/stable/notes/randomness.html
import torch
print(random_tensor_A)
print(random_tensor_B)
print(random_tensor_A == random_tensor_B)
torch.manual_seed(RANDOM_SEED)
random_tensor_D = torch.rand(3, 4)
print(random_tensor_C)
print(random_tensor_D)
print(random_tensor_C == random_tensor_D)