Source code for finds.recipes.learn
"""Miscellaneous utilities
Copyright 2022, Terence Lim
MIT License
"""
from typing import List
import numpy as np
import random
from sklearn.model_selection import train_test_split
from pandas.api import types
[docs]def form_input(docs: List[List[int]], pad: int | None = 0) -> List[List[int]]:
"""Pad lists of index lists to form batch of equal lengths
Args:
docs: Input documents as lists of int lists
pad: Value to pad with (None to pad with random value from list)
Returns:
List of padded lists of ints
"""
lengths = [len(doc) for doc in docs] # length of each doc
max_length = max(lengths) # to pad so all lengths equal max
if max_length: # pad to max length
out = [[0] * max_length if not not n else
[doc + ([pad] * (max_length-n) if pad is not None else
random.choices(doc, k=max_length-n))]
for doc, n in zip(docs, lengths)]
else: # all lines are blank
out = [[0]] * len(lengths)
return out
[docs]def form_batches(batch_size: int, idx: List) -> List[List[int]]:
"""Shuffles idx list into minibatches each of size batch_size
Args:
batch_size: Size of each minibatch
idx: List of indexes
Returns:
List of batches of shuffled indexes
"""
idxs = [i for i in idx]
random.shuffle(idxs)
return [idxs[i:(i+batch_size)] for i in range(0, len(idxs), batch_size)]
[docs]def form_splits(labels: List[str | int] | int,
test_size: float | int = 0.2,
random_state: int = 42) -> List[List]:
"""Wraps over train_test_split to stratifies labels into split indexes
Args:
labels: Labels of series to stratify, or length of series to shuffle
test_size: Desired size of test set as fraction or number of samples
random_state: Set random seed
Returns:
tuple of stratified train indexes and test indexes
"""
if types.is_list_like(labels):
return train_test_split(np.arange(len(labels)),
stratify=labels,
random_state=random_state,
test_size=test_size)
else: # labels is an int
return train_test_split(labels,
random_state=random_state,
test_size=test_size)
[docs]def torch_trainable(model, total: bool = True) -> List[int] | int:
"""Returns total number of trainable parameters in torch model"""
import torch
p = [p.numel() for p in model.parameters() if p.requires_grad]
return sum(p) if total else p # by components or total sum
[docs]def cuda_summary():
"""Print details of cuda environment
Notes:
- https://pytorch.org/get-started/locally/
- check cuda version (e.g. 11.4?): Nvidia-smi
- install matching torch version
- pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu116
- you can specify $ export TORCH\_CUDA\_ARCH\_LIST="8.6"
in your environment to force it to build with SM 8.6 support
"""
import torch
print('version', torch.__version__)
print('device capability', torch.cuda.get_device_capability())
gpu_stats = torch.cuda.get_device_properties(0)
start_gpu_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
max_memory = round(gpu_stats.total_memory / 1024 / 1024 / 1024, 3)
print(f"GPU = {gpu_stats.name}. Max memory = {max_memory} GB.")
print(f"{start_gpu_memory} GB of memory reserved.")
print(torch.cuda.get_arch_list(), '(sm86 for rtx3080)')
[docs]def torch_summary(model):
"""Print torch network summary
https://stackoverflow.com/questions/42480111/how-do-i-print-the-model-summary-in-pytorch
"""
import torch
modules = [module for module in model.modules()]
params = [p.shape for p in model.parameters()]
trains = [p.shape for p in model.parameters() if p.requires_grad]
print(modules[0])
total_params = 0
total_train = 0
for i in range(1,len(modules)):
j = 2*i
param = (params[j-2][1] * params[j-2][0]) + params[j-1][0]
total_params += param
train = (trains[j-2][1] * trains[j-2][0]) + trains[j-1][0]
total_train += train
print("Layer",i,"->\t",end="")
print("Weights:", params[j-2][0],
"x", params[j-2][1],
"\tBias: ", params[j-1][0],
"\tParameters: ", param,
"\tTrainable: ", train)
print("\nTotal Params: ", total_params,
"\t\tTotal Trainable: ", total_train)