bb = TensorBBox([[-2,-0.5,0.5,1.5], [-0.5,-0.5,0.5,0.5], [1,0.5,0.5,0.75], [-0.5,-0.5,0.5,0.5], [-2, -0.5, -1.5, 0.5]])
bb,lbl = clip_remove_empty(bb, TensorMultiCategory([1,2,3,2,5]))
test_eq(bb, TensorBBox([[-1,-0.5,0.5,1.], [-0.5,-0.5,0.5,0.5], [-0.5,-0.5,0.5,0.5]]))
test_eq(lbl, TensorMultiCategory([1,2,2]))Vision data
DataLoaders in the vision application and higher class ImageDataLoaders
The main classes defined in this module are ImageDataLoaders and SegmentationDataLoaders, so you probably want to jump to their definitions. They provide factory methods that are a great way to quickly get your data ready for training, see the vision tutorial for examples.
Helper functions
get_grid
def get_grid(
n:int, # Number of axes in the returned grid
nrows:int=None, # Number of rows in the returned grid, defaulting to `int(math.sqrt(n))`
ncols:int=None, # Number of columns in the returned grid, defaulting to `ceil(n/rows)`
figsize:tuple=None, # Width, height in inches of the returned figure
double:bool=False, # Whether to double the number of columns and `n`
title:str=None, # If passed, title set to the figure
return_fig:bool=False, # Whether to return the figure created by [`subplots`](https://docs.fast.ai/torch_core.html#subplots)
flatten:bool=True, # Whether to flatten the matplot axes such that they can be iterated over with a single loop
imsize:int=3, # Size (in inches) of images that will be displayed in the returned figure
suptitle:str=None, # Title to be set to returned figure
sharex:bool | Literal['none', 'all', 'row', 'col']=False,
sharey:bool | Literal['none', 'all', 'row', 'col']=False, squeeze:bool=True,
width_ratios:Sequence[float] | None=None, height_ratios:Sequence[float] | None=None,
subplot_kw:dict[str, Any] | None=None, gridspec_kw:dict[str, Any] | None=None
)->(<class 'matplotlib.figure.Figure'>, <class 'matplotlib.axes._axes.Axes'>): # Returns just `axs` by default, and (`fig`, `axs`) if `return_fig` is set to True
Return a grid of n axes, rows by cols
This is used by the type-dispatched versions of show_batch and show_results for the vision application. The default figsize is (cols*imsize, rows*imsize+0.6). imsize is passed down to subplots. suptitle, sharex, sharey, squeeze, subplot_kw and gridspec_kw are all passed down to plt.subplots. If return_fig is True, returns fig,axs, otherwise just axs.
clip_remove_empty
def clip_remove_empty(
bbox:TensorBBox, # Coordinates of bounding boxes
label:TensorMultiCategory, # Labels of the bounding boxes
):
Clip bounding boxes with image border and remove empty boxes along with corresponding labels
This is used in bb_pad
bb_pad
def bb_pad(
samples:list, # List of 3-tuples like (image, bounding_boxes, labels)
pad_idx:int=0, # Label that will be used to pad each list of labels
):
Function that collects samples of labelled bboxes and adds padding with pad_idx.
This is used in BBoxBlock
img1,img2 = TensorImage(torch.randn(16,16,3)),TensorImage(torch.randn(16,16,3))
bb1 = tensor([[-2,-0.5,0.5,1.5], [-0.5,-0.5,0.5,0.5], [1,0.5,0.5,0.75], [-0.5,-0.5,0.5,0.5]])
lbl1 = tensor([1, 2, 3, 2])
bb2 = tensor([[-0.5,-0.5,0.5,0.5], [-0.5,-0.5,0.5,0.5]])
lbl2 = tensor([2, 2])
samples = [(img1, bb1, lbl1), (img2, bb2, lbl2)]
res = bb_pad(samples)
non_empty = tensor([True,True,False,True])
test_eq(res[0][0], img1)
test_eq(res[0][1], tensor([[-1,-0.5,0.5,1.], [-0.5,-0.5,0.5,0.5], [-0.5,-0.5,0.5,0.5]]))
test_eq(res[0][2], tensor([1,2,2]))
test_eq(res[1][0], img2)
test_eq(res[1][1], tensor([[-0.5,-0.5,0.5,0.5], [-0.5,-0.5,0.5,0.5], [0,0,0,0]]))
test_eq(res[1][2], tensor([2,2,0]))TransformBlocks for vision
These are the blocks the vision application provide for the data block API.
ImageBlock
def ImageBlock(
cls:PILBase=PILImage
):
A TransformBlock for images of cls
MaskBlock
def MaskBlock(
codes:list=None, # Vocab labels for segmentation masks
):
A TransformBlock for segmentation masks, potentially with codes
TransformBlock??class TransformBlock():
"A basic wrapper that links defaults transforms for the data block API"
def __init__(self,
type_tfms:list=None, # One or more `Transform`s
item_tfms:list=None, # `ItemTransform`s, applied on an item
batch_tfms:list=None, # `Transform`s or [`RandTransform`](https://docs.fast.ai/vision.augment.html#randtransform)s, applied by batch
dl_type:TfmdDL=None, # Task specific [`TfmdDL`](https://docs.fast.ai/data.core.html#tfmddl), defaults to [`TfmdDL`](https://docs.fast.ai/data.core.html#tfmddl)
dls_kwargs:dict=None, # Additional arguments to be passed to [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
self.type_tfms = L(type_tfms)
self.item_tfms = ToTensor + L(item_tfms)
self.batch_tfms = L(batch_tfms)
self.dl_type,self.dls_kwargs = dl_type,({} if dls_kwargs is None else dls_kwargs)File: ~/aai-ws/fastai/fastai/data/block.py
BBoxLblBlock
def BBoxLblBlock(
vocab:list=None, # Vocab labels for bounding boxes
add_na:bool=True, # Add NaN as a background class
):
A TransformBlock for labeled bounding boxes, potentially with vocab
If add_na is True, a new category is added for NaN (that will represent the background class).
ImageDataLoaders
def ImageDataLoaders(
loaders:VAR_POSITIONAL, # [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader) objects to wrap
path:str | Path='.', # Path to store export objects
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Basic wrapper around several DataLoaders with factory methods for computer vision problems
This class should not be used directly, one of the factory methods should be preferred instead. All those factory methods accept as arguments:
item_tfms: one or several transforms applied to the items before batching thembatch_tfms: one or several transforms applied to the batches once they are formedbs: the batch sizeval_bs: the batch size for the validationDataLoader(defaults tobs)shuffle_train: if we shuffle the trainingDataLoaderor notdevice: the PyTorch device to use (defaults todefault_device())
ImageDataLoaders.from_folder
def from_folder(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
train:str='train', valid:str='valid', valid_pct:NoneType=None, seed:NoneType=None, vocab:NoneType=None,
item_tfms:NoneType=None, batch_tfms:NoneType=None, img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from imagenet style dataset in path with train and valid subfolders (or provide valid_pct)
If valid_pct is provided, a random split is performed (with an optional seed) by setting aside that percentage of the data for the validation set (instead of looking at the grandparents folder). If a vocab is passed, only the folders with names in vocab are kept.
Here is an example loading a subsample of MNIST:
path = untar_data(URLs.MNIST_TINY)
dls = ImageDataLoaders.from_folder(path, img_cls=PILImageBW)x,y = dls.one_batch()
test_eq(x.shape, [64, 1, 28, 28])Passing valid_pct will ignore the valid/train folders and do a new random split:
dls = ImageDataLoaders.from_folder(path, valid_pct=0.2)
dls.valid_ds.items[:3][Path('/Users/jhoward/.fastai/data/mnist_tiny/valid/7/9919.png'),
Path('/Users/jhoward/.fastai/data/mnist_tiny/train/3/9637.png'),
Path('/Users/jhoward/.fastai/data/mnist_tiny/valid/3/7407.png')]
ImageDataLoaders.from_path_func
def from_path_func(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
fnames, label_func, valid_pct:float=0.2, seed:NoneType=None, item_tfms:NoneType=None, batch_tfms:NoneType=None,
img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from list of fnames in paths with label_func
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility.
Here is how to create the same DataLoaders on the MNIST dataset as the previous example with a label_func:
fnames = get_image_files(path)
def label_func(x): return x.parent.name
dls = ImageDataLoaders.from_path_func(path, fnames, label_func)Here is another example on the pets dataset. Here filenames are all in an “images” folder and their names have the form class_name_123.jpg. One way to properly label them is thus to throw away everything after the last _:
ImageDataLoaders.from_path_re
def from_path_re(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
fnames, pat, valid_pct:float=0.2, seed:NoneType=None, item_tfms:NoneType=None, batch_tfms:NoneType=None,
img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from list of fnames in paths with re expression pat
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility.
Here is how to create the same DataLoaders on the MNIST dataset as the previous example (you will need to change the initial two / by a on Windows):
pat = r'/([^/]*)/\d+.png$'
dls = ImageDataLoaders.from_path_re(path, fnames, pat)ImageDataLoaders.from_name_func
def from_name_func(
path:str | pathlib.Path, # Set the default path to a directory that a [`Learner`](https://docs.fast.ai/learner.html#learner) can use to save files like models
fnames:list, # A list of `os.Pathlike`'s to individual image files
label_func:Callable, # A function that receives a string (the file name) and outputs a label
valid_pct:float=0.2, seed:NoneType=None, item_tfms:NoneType=None, batch_tfms:NoneType=None,
img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
)->DataLoaders:
Create from the name attrs of fnames in paths with label_func
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility. This method does the same as ImageDataLoaders.from_path_func except label_func is applied to the name of each filenames, and not the full path.
ImageDataLoaders.from_name_re
def from_name_re(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
fnames, pat, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from the name attrs of fnames in paths with re expression pat
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility. This method does the same as ImageDataLoaders.from_path_re except pat is applied to the name of each filenames, and not the full path.
ImageDataLoaders.from_df
def from_df(
df, path:str='.', # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
valid_pct:float=0.2, seed:NoneType=None, fn_col:int=0, folder:NoneType=None, suff:str='', label_col:int=1,
label_delim:NoneType=None, y_block:NoneType=None, valid_col:NoneType=None, item_tfms:NoneType=None,
batch_tfms:NoneType=None, img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from df using fn_col and label_col
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility. Alternatively, if your df contains a valid_col, give its name or its index to that argument (the column should have True for the elements going to the validation set).
You can add an additional folder to the filenames in df if they should not be concatenated directly to path. If they do not contain the proper extensions, you can add suff. If your label column contains multiple labels on each row, you can use label_delim to warn the library you have a multi-label problem.
y_block should be passed when the task automatically picked by the library is wrong, you should then give CategoryBlock, MultiCategoryBlock or RegressionBlock. For more advanced uses, you should use the data block API.
The tiny mnist example from before also contains a version in a dataframe:
path = untar_data(URLs.MNIST_TINY)
df = pd.read_csv(path/'labels.csv')
df.head()| name | label | |
|---|---|---|
| 0 | train/3/7463.png | 3 |
| 1 | train/3/9829.png | 3 |
| 2 | train/3/7881.png | 3 |
| 3 | train/3/8065.png | 3 |
| 4 | train/3/7046.png | 3 |
Here is how to load it using ImageDataLoaders.from_df:
dls = ImageDataLoaders.from_df(df, path)Here is another example with a multi-label problem:
path = untar_data(URLs.PASCAL_2007)
df = pd.read_csv(path/'train.csv')
df.head()| fname | labels | is_valid | |
|---|---|---|---|
| 0 | 000005.jpg | chair | True |
| 1 | 000007.jpg | car | True |
| 2 | 000009.jpg | horse person | True |
| 3 | 000012.jpg | car | False |
| 4 | 000016.jpg | bicycle | True |
dls = ImageDataLoaders.from_df(df, path, folder='train', valid_col='is_valid')Note that can also pass 2 to valid_col (the index, starting with 0).
ImageDataLoaders.from_csv
def from_csv(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
csv_fname:str='labels.csv', header:str='infer', delimiter:NoneType=None, quoting:int=0, valid_pct:float=0.2,
seed:NoneType=None, fn_col:int=0, folder:NoneType=None, suff:str='', label_col:int=1, label_delim:NoneType=None,
y_block:NoneType=None, valid_col:NoneType=None, item_tfms:NoneType=None, batch_tfms:NoneType=None,
img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from path/csv_fname using fn_col and label_col
Same as ImageDataLoaders.from_df after loading the file with header and delimiter.
Here is how to load the same dataset as before with this method:
dls = ImageDataLoaders.from_csv(path, 'train.csv', folder='train', valid_col='is_valid')ImageDataLoaders.from_lists
def from_lists(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
fnames, labels, valid_pct:float=0.2, seed:int=None, y_block:NoneType=None, item_tfms:NoneType=None,
batch_tfms:NoneType=None, img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from list of fnames and labels in path
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility. y_block can be passed to specify the type of the targets.
path = untar_data(URLs.PETS)
fnames = get_image_files(path/"images")
labels = ['_'.join(x.name.split('_')[:-1]) for x in fnames]
dls = ImageDataLoaders.from_lists(path, fnames, labels)SegmentationDataLoaders
def SegmentationDataLoaders(
loaders:VAR_POSITIONAL, # [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader) objects to wrap
path:str | Path='.', # Path to store export objects
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Basic wrapper around several DataLoaders with factory methods for segmentation problems
SegmentationDataLoaders.from_label_func
def from_label_func(
path, # Path to put in [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
fnames, label_func, valid_pct:float=0.2, seed:NoneType=None, codes:NoneType=None, item_tfms:NoneType=None,
batch_tfms:NoneType=None, img_cls:BypassNewMeta=PILImage, bs:int=64, # Size of batch
val_bs:int=None, # Size of batch for validation [`DataLoader`](https://docs.fast.ai/data.load.html#dataloader)
shuffle:bool=True, # Whether to shuffle data
device:NoneType=None, # Device to put [`DataLoaders`](https://docs.fast.ai/data.core.html#dataloaders)
):
Create from list of fnames in paths with label_func.
The validation set is a random subset of valid_pct, optionally created with seed for reproducibility. codes contain the mapping index to label.
path = untar_data(URLs.CAMVID_TINY)
fnames = get_image_files(path/'images')
def label_func(x): return path/'labels'/f'{x.stem}_P{x.suffix}'
codes = np.loadtxt(path/'codes.txt', dtype=str)
dls = SegmentationDataLoaders.from_label_func(path, fnames, label_func, codes=codes)