Torch Core¶
This module contains all the basic functions we need in other modules of the fastai library (split with core
that contains the ones not requiring pytorch). Its documentation can easily be skipped at a first read, unless you want to know what a given function does.
Global constants¶
AdamW = partial(optim.Adam, betas=(0.9,0.99))
bn_types = (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d)
defaults.device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
If you are trying to make fastai run on the CPU, simply change the default device: defaults.device = torch.device('cpu')
.
Alternatively, if not using wildcard imports: fastai.torch_core.defaults.device = torch.device('cpu')
.
Conversion functions¶
Flattens all the layers of m
into an array. This allows for easy access to the layers of the model and allows you to manipulate the model as if it was an array.
m = simple_cnn([3,6,12])
m
flatten_model(m)
show_doc(flatten_check)
Converting model parameters to half precision allows us to leverage fast FP16
arithmetic which can speed up the computations by 2-8 times. It also reduces memory consumption allowing us to train deeper models.
Note: Batchnorm layers are not converted to half precision as that may lead to instability in training.
m = simple_cnn([3,6,12], bn=True)
def show_params_dtype(state_dict):
"""Simple function to pretty print the dtype of the model params"""
for wt_name, param in state_dict.items():
print("{:<30}: {}".format(wt_name, str(param.dtype)))
print()
print("dtypes of model parameters before model2half: ")
show_params_dtype(m.state_dict())
# Converting model to half precision
m_half = model2half(m)
print("dtypes of model parameters after model2half: ")
show_params_dtype(m_half.state_dict())
It is a wrapper on top of Pytorch's torch.as_tensor
which converts numpy array to torch tensor, and additionally attempts to map all floats to torch.float32
and all integers to torch.int64
for consistencies in model data. Below is an example demonstrating it's functionality for floating number, similar functionality applies to integer as well.
a1 = np.ones((2, 3)).astype(np.float16)
a2 = np.ones((2, 3)).astype(np.float32)
a3 = np.ones((2, 3)).astype(np.float64)
b1 = np2model_tensor(a1) # Maps to torch.float32
b2 = np2model_tensor(a2) # Maps to torch.float32
b3 = np2model_tensor(a3) # Maps to torch.float32
print(f"Datatype of as': {a1.dtype}, {a2.dtype}, {a3.dtype}")
print(f"Datatype of bs': {b1.dtype}, {b2.dtype}, {b3.dtype}")
Performs both getting and setting of requires_grad
parameter of the tensors, which decided whether to accumulate gradients or not.
If
b
isNone
: The function gets therequires_grad
for the model parameter, to be more specific it returns therequires_grad
of the first element in the model.Else if
b
is passed (a boolean value),requires_grad
of all parameters of the model is set tob
.
# Any Pytorch model
m = simple_cnn([3, 6, 12], bn=True)
# Get the requires_grad of model
print("requires_grad of model: {}".format(requires_grad(m)))
# Set requires_grad of all params in model to false
requires_grad(m, False)
# Get the requires_grad of model
print("requires_grad of model: {}".format(requires_grad(m)))
Handy function when you want to convert any list type object to tensor, initialize your weights manually, and other similar cases.
NB: When passing multiple vectors, all vectors must be of same dimensions. (Obvious but can be forgotten sometimes)
# Conversion from any numpy array
b = tensor(np.array([1, 2, 3]))
print(b, type(b))
# Passing as multiple parameters
b = tensor(1, 2, 3)
print(b, type(b))
# Passing a single list
b = tensor([1, 2, 3])
print(b, type(b))
# Can work with multiple vectors / lists
b = tensor([1, 2], [3, 4])
print(b, type(b))
A wrapper on top of Pytorch's torch.Tensor.cpu()
function, which creates and returns a copy of a tensor or even a list of tensors in the CPU. As described in Pytorch's docs, if the tensor or list of tensor is already on the CPU, the exact data is returned and no copy is made.
Useful to convert all the list of parameters of the model to CPU in a single call.
if torch.cuda.is_available():
a = [torch.randn((1, 1)).cuda() for i in range(3)]
print(a)
print("Id of tensors in a: ")
for i in a: print(id(i))
# Getting a CPU version of the tensors in GPU
b = to_cpu(a)
print(b)
print("Id of tensors in b:")
for i in b: print(id(i))
# Trying to perform to_cpu on a list of tensor already in CPU
c = to_cpu(b)
print(c)
# The tensors in c has exact id as that of b. No copy performed.
print("Id of tensors in c:")
for i in c: print(id(i))
Returns the data attribute from the object or collection of objects that inherits from ItemBase
class. Useful to examine the exact values of the data, could be used to work with the data outside of fastai
classes.
# Default example examined
from fastai import *
from fastai.vision import *
path = untar_data(URLs.MNIST_SAMPLE)
data = ImageDataBunch.from_folder(path)
# Examin the labels
ys = list(data.y)
print("Category display names: ", [ys[0], ys[-1]])
print("Unique classes internally represented as: ", to_data([ys[0], ys[-1]]))
Converts the tensor or list of FP16
, resulting in less memory consumption and faster computations with the tensor. It does not convert torch.int
types to half precision.
a1 = torch.tensor([1, 2], dtype=torch.int64)
a2 = torch.tensor([1, 2], dtype=torch.int32)
a3 = torch.tensor([1, 2], dtype=torch.int16)
a4 = torch.tensor([1, 2], dtype=torch.float64)
a5 = torch.tensor([1, 2], dtype=torch.float32)
a6 = torch.tensor([1, 2], dtype=torch.float16)
print("dtype of as: ", a1.dtype, a2.dtype, a3.dtype, a4.dtype, a5.dtype, a6.dtype, sep="\t")
b1, b2, b3, b4, b5, b6 = to_half([a1, a2, a3, a4, a5, a6])
print("dtype of bs: ", b1.dtype, b2.dtype, b3.dtype, b4.dtype, b5.dtype, b6.dtype, sep="\t")
Internally puts the data to CPU, and converts to numpy.ndarray
equivalent of torch.tensor
by calling torch.Tensor.numpy()
.
a = torch.tensor([1, 2], dtype=torch.float64)
if torch.cuda.is_available():
a = a.cuda()
print(a, type(a), a.device)
b = to_np(a)
print(b, type(b))
# Converts floating point numbers to integer
print(try_int(12.5), type(try_int(12.5)))
# This is a Rank-1 ndarray, which ideally should not be converted to int
print(try_int(np.array([1.5])), try_int(np.array([1.5])).dtype)
# Numpy array with a single elements are converted to int
print(try_int(np.array(1.5)), type(try_int(np.array(1.5))))
print(try_int(torch.tensor(2.5)), type(try_int(torch.tensor(2.5))))
# Strings are not converted to int (of course)
print(try_int("12.5"), type(try_int("12.5")))
show_doc(to_float)
Functions to deal with model initialization¶
Functions to get information of a model¶
Functions to deal with BatchNorm layers¶
This is used by the optimizer to determine which params should be applied weight decay when using the option bn_wd=False
is used in a Learner
.
Functions to get random tensors¶
log_uniform(0.5,2,(8,))
rand_bool(0.5, 8)
uniform(0,1,(8,))
uniform_int(0,2,(8,))
Other functionality¶
class _T(Module):
def __init__(self): self.f = nn.Linear(2,1)
def forward(self,x): return self.f(x)
t = _T()
t(tensor(1.,2))
If splits
are layers, the model is split at those (not included) sequentially. If want_idxs
is True, the corresponding indexes are returned. If splits
are lists of layers, the model is split according to those.