Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rasbt
GitHub Repository: rasbt/machine-learning-book
Path: blob/main/ch12/ch12_part1.ipynb
1247 views
Kernel: Python 3 (ipykernel)

Machine Learning with PyTorch and Scikit-Learn

-- Code Examples

Package version checks

Add folder to path in order to load from the check_packages.py script:

import sys sys.path.insert(0, '..')

Check recommended package versions:

from python_environment_check import check_packages d = { 'numpy': '1.21.2', 'matplotlib': '3.4.3', 'torch': '1.9.0', } check_packages(d)
[OK] Your Python version is 3.9.6 | packaged by conda-forge | (default, Jul 11 2021, 03:35:11) [Clang 11.1.0 ] [OK] numpy 1.21.4 [OK] matplotlib 3.5.1 [OK] torch 1.10.0

Chapter 12: Parallelizing Neural Network Training with PyTorch (Part 1/2)

Note that the optional watermark extension is a small IPython notebook plugin that I developed to make the code reproducible. You can just skip the following line(s).

from IPython.display import Image as IPythonImage %matplotlib inline

PyTorch and training performance

Performance challenges

IPythonImage(filename='figures/12_01.png', width=500)
Image in a Jupyter notebook

What is PyTorch?

IPythonImage(filename='figures/12_02.png', width=500)
Image in a Jupyter notebook

How we will learn PyTorch

First steps with PyTorch

Installing PyTorch

#! pip install torch
import torch import numpy as np print('PyTorch version:', torch.__version__) np.set_printoptions(precision=3)
PyTorch version: 1.10.0
! python -c 'import torch; print(torch.__version__)'
1.10.0

Creating tensors in PyTorch

a = [1, 2, 3] b = np.array([4, 5, 6], dtype=np.int32) t_a = torch.tensor(a) t_b = torch.from_numpy(b) print(t_a) print(t_b)
tensor([1, 2, 3]) tensor([4, 5, 6], dtype=torch.int32)
torch.is_tensor(a), torch.is_tensor(t_a)
(False, True)
t_ones = torch.ones(2, 3) t_ones.shape
torch.Size([2, 3])
print(t_ones)
tensor([[1., 1., 1.], [1., 1., 1.]])
rand_tensor = torch.rand(2,3) print(rand_tensor)
tensor([[0.8081, 0.8601, 0.0870], [0.6340, 0.1330, 0.5721]])

Manipulating the data type and shape of a tensor

t_a_new = t_a.to(torch.int64) print(t_a_new.dtype)
torch.int64
t = torch.rand(3, 5) t_tr = torch.transpose(t, 0, 1) print(t.shape, ' --> ', t_tr.shape)
torch.Size([3, 5]) --> torch.Size([5, 3])
t = torch.zeros(30) t_reshape = t.reshape(5, 6) print(t_reshape.shape)
torch.Size([5, 6])
t = torch.zeros(1, 2, 1, 4, 1) t_sqz = torch.squeeze(t, 2) print(t.shape, ' --> ', t_sqz.shape)
torch.Size([1, 2, 1, 4, 1]) --> torch.Size([1, 2, 4, 1])

Applying mathematical operations to tensors

torch.manual_seed(1) t1 = 2 * torch.rand(5, 2) - 1 t2 = torch.normal(mean=0, std=1, size=(5, 2))
t3 = torch.multiply(t1, t2) print(t3)
tensor([[ 0.4426, -0.3114], [ 0.0660, -0.5970], [ 1.1249, 0.0150], [ 0.1569, 0.7107], [-0.0451, -0.0352]])
t4 = torch.mean(t1, axis=0) print(t4)
tensor([-0.1373, 0.2028])
t5 = torch.matmul(t1, torch.transpose(t2, 0, 1)) print(t5)
tensor([[ 0.1312, 0.3860, -0.6267, -1.0096, -0.2943], [ 0.1647, -0.5310, 0.2434, 0.8035, 0.1980], [-0.3855, -0.4422, 1.1399, 1.5558, 0.4781], [ 0.1822, -0.5771, 0.2585, 0.8676, 0.2132], [ 0.0330, 0.1084, -0.1692, -0.2771, -0.0804]])
t6 = torch.matmul(torch.transpose(t1, 0, 1), t2) print(t6)
tensor([[ 1.7453, 0.3392], [-1.6038, -0.2180]])
norm_t1 = torch.linalg.norm(t1, ord=2, dim=1) print(norm_t1)
tensor([0.6785, 0.5078, 1.1162, 0.5488, 0.1853])
np.sqrt(np.sum(np.square(t1.numpy()), axis=1))
array([0.678, 0.508, 1.116, 0.549, 0.185], dtype=float32)

Split, stack, and concatenate tensors

torch.manual_seed(1) t = torch.rand(6) print(t) t_splits = torch.chunk(t, 3) [item.numpy() for item in t_splits]
tensor([0.7576, 0.2793, 0.4031, 0.7347, 0.0293, 0.7999])
[array([0.758, 0.279], dtype=float32), array([0.403, 0.735], dtype=float32), array([0.029, 0.8 ], dtype=float32)]
torch.manual_seed(1) t = torch.rand(5) print(t) t_splits = torch.split(t, split_size_or_sections=[3, 2]) [item.numpy() for item in t_splits]
tensor([0.7576, 0.2793, 0.4031, 0.7347, 0.0293])
[array([0.758, 0.279, 0.403], dtype=float32), array([0.735, 0.029], dtype=float32)]
A = torch.ones(3) B = torch.zeros(2) C = torch.cat([A, B], axis=0) print(C)
tensor([1., 1., 1., 0., 0.])
A = torch.ones(3) B = torch.zeros(3) S = torch.stack([A, B], axis=1) print(S)
tensor([[1., 0.], [1., 0.], [1., 0.]])

Building input pipelines in PyTorch

Creating a PyTorch DataLoader from existing tensors

from torch.utils.data import DataLoader t = torch.arange(6, dtype=torch.float32) data_loader = DataLoader(t)
for item in data_loader: print(item)
tensor([0.]) tensor([1.]) tensor([2.]) tensor([3.]) tensor([4.]) tensor([5.])
data_loader = DataLoader(t, batch_size=3, drop_last=False) for i, batch in enumerate(data_loader, 1): print(f'batch {i}:', batch)
batch 1: tensor([0., 1., 2.]) batch 2: tensor([3., 4., 5.])

Combining two tensors into a joint dataset

from torch.utils.data import Dataset class JointDataset(Dataset): def __init__(self, x, y): self.x = x self.y = y def __len__(self): return len(self.x) def __getitem__(self, idx): return self.x[idx], self.y[idx]
torch.manual_seed(1) t_x = torch.rand([4, 3], dtype=torch.float32) t_y = torch.arange(4) joint_dataset = JointDataset(t_x, t_y) # Or use TensorDataset directly from torch.utils.data import TensorDataset joint_dataset = TensorDataset(t_x, t_y) for example in joint_dataset: print(' x: ', example[0], ' y: ', example[1])
x: tensor([0.7576, 0.2793, 0.4031]) y: tensor(0) x: tensor([0.7347, 0.0293, 0.7999]) y: tensor(1) x: tensor([0.3971, 0.7544, 0.5695]) y: tensor(2) x: tensor([0.4388, 0.6387, 0.5247]) y: tensor(3)

Shuffle, batch, and repeat

torch.manual_seed(1) data_loader = DataLoader(dataset=joint_dataset, batch_size=2, shuffle=True) for i, batch in enumerate(data_loader, 1): print(f'batch {i}:', 'x:', batch[0], '\n y:', batch[1]) for epoch in range(2): print(f'epoch {epoch+1}') for i, batch in enumerate(data_loader, 1): print(f'batch {i}:', 'x:', batch[0], '\n y:', batch[1])
batch 1: x: tensor([[0.3971, 0.7544, 0.5695], [0.7576, 0.2793, 0.4031]]) y: tensor([2, 0]) batch 2: x: tensor([[0.7347, 0.0293, 0.7999], [0.4388, 0.6387, 0.5247]]) y: tensor([1, 3]) epoch 1 batch 1: x: tensor([[0.7576, 0.2793, 0.4031], [0.3971, 0.7544, 0.5695]]) y: tensor([0, 2]) batch 2: x: tensor([[0.7347, 0.0293, 0.7999], [0.4388, 0.6387, 0.5247]]) y: tensor([1, 3]) epoch 2 batch 1: x: tensor([[0.4388, 0.6387, 0.5247], [0.3971, 0.7544, 0.5695]]) y: tensor([3, 2]) batch 2: x: tensor([[0.7576, 0.2793, 0.4031], [0.7347, 0.0293, 0.7999]]) y: tensor([0, 1])

Creating a dataset from files on your local storage disk

import pathlib imgdir_path = pathlib.Path('cat_dog_images') file_list = sorted([str(path) for path in imgdir_path.glob('*.jpg')]) print(file_list)
['cat_dog_images/cat-01.jpg', 'cat_dog_images/cat-02.jpg', 'cat_dog_images/cat-03.jpg', 'cat_dog_images/dog-01.jpg', 'cat_dog_images/dog-02.jpg', 'cat_dog_images/dog-03.jpg']
import matplotlib.pyplot as plt import os from PIL import Image fig = plt.figure(figsize=(10, 5)) for i, file in enumerate(file_list): img = Image.open(file) print('Image shape: ', np.array(img).shape) ax = fig.add_subplot(2, 3, i+1) ax.set_xticks([]); ax.set_yticks([]) ax.imshow(img) ax.set_title(os.path.basename(file), size=15) #plt.savefig('figures/12_03.pdf') plt.tight_layout() plt.show()
Image shape: (900, 1200, 3) Image shape: (900, 1200, 3) Image shape: (900, 742, 3) Image shape: (800, 1200, 3) Image shape: (800, 1200, 3) Image shape: (900, 1200, 3)
Image in a Jupyter notebook
labels = [1 if 'dog' in os.path.basename(file) else 0 for file in file_list] print(labels)
[0, 0, 0, 1, 1, 1]
class ImageDataset(Dataset): def __init__(self, file_list, labels): self.file_list = file_list self.labels = labels def __getitem__(self, index): file = self.file_list[index] label = self.labels[index] return file, label def __len__(self): return len(self.labels) image_dataset = ImageDataset(file_list, labels) for file, label in image_dataset: print(file, label)
cat_dog_images/cat-01.jpg 0 cat_dog_images/cat-02.jpg 0 cat_dog_images/cat-03.jpg 0 cat_dog_images/dog-01.jpg 1 cat_dog_images/dog-02.jpg 1 cat_dog_images/dog-03.jpg 1
import torchvision.transforms as transforms class ImageDataset(Dataset): def __init__(self, file_list, labels, transform=None): self.file_list = file_list self.labels = labels self.transform = transform def __getitem__(self, index): img = Image.open(self.file_list[index]) if self.transform is not None: img = self.transform(img) label = self.labels[index] return img, label def __len__(self): return len(self.labels) img_height, img_width = 80, 120 transform = transforms.Compose([ transforms.ToTensor(), transforms.Resize((img_height, img_width)), ]) image_dataset = ImageDataset(file_list, labels, transform)
fig = plt.figure(figsize=(10, 6)) for i, example in enumerate(image_dataset): ax = fig.add_subplot(2, 3, i+1) ax.set_xticks([]); ax.set_yticks([]) ax.imshow(example[0].numpy().transpose((1, 2, 0))) ax.set_title(f'{example[1]}', size=15) plt.tight_layout() plt.savefig('figures/12_04.pdf') plt.show()
Image in a Jupyter notebook

Fetching available datasets from the torchvision.datasets library

# ! pip install torchvision
import torchvision

Fetching CelebA dataset


  1. Downloading the image files manually

    • You can try setting download=True below. If this results in a BadZipfile error, we recommend downloading the img_align_celeba.zip file manually from http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html. In the Google Drive folder, you can find it under the Img folder as shown below:

IPythonImage(filename='figures/gdrive-download-location-1.png', width=500)
Image in a Jupyter notebook
  1. Next, you need to download the annotation files and put them into the same ./celeba subfolder. The annotation files can be found under Anno:

IPythonImage(filename='figures/gdrive-download-location-2.png', width=300)
Image in a Jupyter notebook
IPythonImage(filename='figures/gdrive-download-location-3.png', width=300)
Image in a Jupyter notebook
  1. Lastly, you need to download the file list_eval_partition.txt and place it under ./celeba:

After completing steps 1-3 above, please ensure you have the following files in your ./celeba subfolder, and the files are non-empty (that is, they have similar file sizes as shown below):

IPythonImage(filename='figures/celeba-files.png', width=400)
Image in a Jupyter notebook

image_path = './' celeba_dataset = torchvision.datasets.CelebA(image_path, split='train', target_type='attr', download=False) assert isinstance(celeba_dataset, torch.utils.data.Dataset)
example = next(iter(celeba_dataset)) print(example)
(<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=178x218 at 0x1332FD850>, tensor([0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1]))
from itertools import islice fig = plt.figure(figsize=(12, 8)) for i, (image, attributes) in islice(enumerate(celeba_dataset), 18): ax = fig.add_subplot(3, 6, i+1) ax.set_xticks([]); ax.set_yticks([]) ax.imshow(image) ax.set_title(f'{attributes[31]}', size=15) #plt.savefig('figures/12_05.pdf') plt.show()
Image in a Jupyter notebook
mnist_dataset = torchvision.datasets.MNIST(image_path, 'train', download=True) assert isinstance(mnist_dataset, torch.utils.data.Dataset) example = next(iter(mnist_dataset)) print(example) fig = plt.figure(figsize=(15, 6)) for i, (image, label) in islice(enumerate(mnist_dataset), 10): ax = fig.add_subplot(2, 5, i+1) ax.set_xticks([]); ax.set_yticks([]) ax.imshow(image, cmap='gray_r') ax.set_title(f'{label}', size=15) #plt.savefig('figures/12_06.pdf') plt.show()
(<PIL.Image.Image image mode=L size=28x28 at 0x1317A9E80>, 5)
/Users/sebastian/miniforge3/lib/python3.9/site-packages/torchvision/datasets/mnist.py:498: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /Users/runner/miniforge3/conda-bld/pytorch-recipe_1635217266490/work/torch/csrc/utils/tensor_numpy.cpp:189.) return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)
Image in a Jupyter notebook

Readers may ignore the next cell.

! python ../.convert_notebook_to_script.py --input ch12_part1.ipynb --output ch12_part1.py
[NbConvertApp] WARNING | Config option `kernel_spec_manager_class` not recognized by `NbConvertApp`. [NbConvertApp] Converting notebook ch12_part1.ipynb to script [NbConvertApp] Writing 11605 bytes to ch12_part1.py