{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "1f23f34a", "metadata": {}, "outputs": [], "source": [ "#| hide\n", "#| eval: false\n", "! [ -e /content ] && pip install -Uqq fastai # upgrade fastai on colab" ] }, { "cell_type": "code", "execution_count": null, "id": "275b39bb", "metadata": {}, "outputs": [], "source": [ "#| default_exp data.transforms" ] }, { "cell_type": "code", "execution_count": null, "id": "d17d629d", "metadata": {}, "outputs": [], "source": [ "#| export\n", "from fastai.torch_basics import *\n", "from fastai.data.core import *\n", "from fastai.data.load import *\n", "from fastai.data.external import *\n", "\n", "from sklearn.model_selection import train_test_split\n", "\n", "import posixpath" ] }, { "cell_type": "code", "execution_count": null, "id": "e42832a3", "metadata": {}, "outputs": [], "source": [ "#| hide\n", "from nbdev.showdoc import *" ] }, { "cell_type": "markdown", "id": "8df0ebe9", "metadata": {}, "source": [ "# Data transformations\n", "\n", "> Functions for getting, splitting, and labeling data, as well as generic transforms" ] }, { "cell_type": "markdown", "id": "e360d100", "metadata": {}, "source": [ "## Get, split, and label" ] }, { "cell_type": "markdown", "id": "408c9ae8", "metadata": {}, "source": [ "For most data source creation we need functions to get a list of items, split them in to train/valid sets, and label them. fastai provides functions to make each of these steps easy (especially when combined with `fastai.data.blocks`)." ] }, { "cell_type": "markdown", "id": "3f5484ed", "metadata": {}, "source": [ "### Get" ] }, { "cell_type": "markdown", "id": "25e6d368", "metadata": {}, "source": [ "First we'll look at functions that *get* a list of items (generally file names).\n", "\n", "We'll use *tiny MNIST* (a subset of MNIST with just two classes, `7`s and `3`s) for our examples/tests throughout this page." ] }, { "cell_type": "code", "execution_count": null, "id": "b67b6707", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", " \n", " \n", " 100.54% [344064/342207 00:00<00:00]\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "(#2) [Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/3')]" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "path = untar_data(URLs.MNIST_TINY)\n", "(path/'train').ls()" ] }, { "cell_type": "code", "execution_count": null, "id": "889ed2fe", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def _get_files(p, fs, extensions=None):\n", " p = Path(p)\n", " res = [p/f for f in fs if not f.startswith('.')\n", " and ((not extensions) or f'.{f.split(\".\")[-1].lower()}' in extensions)]\n", " return res" ] }, { "cell_type": "code", "execution_count": null, "id": "7da88226", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def get_files(path, extensions=None, recurse=True, folders=None, followlinks=True):\n", " \"Get all the files in `path` with optional `extensions`, optionally with `recurse`, only in `folders`, if specified.\"\n", " path = Path(path)\n", " folders=L(folders)\n", " extensions = setify(extensions)\n", " extensions = {e.lower() for e in extensions}\n", " if recurse:\n", " res = []\n", " for i,(p,d,f) in enumerate(os.walk(path, followlinks=followlinks)): # returns (dirpath, dirnames, filenames)\n", " if len(folders) !=0 and i==0: d[:] = [o for o in d if o in folders]\n", " else: d[:] = [o for o in d if not o.startswith('.')]\n", " if len(folders) !=0 and i==0 and '.' not in folders: continue\n", " res += _get_files(p, f, extensions)\n", " else:\n", " f = [o.name for o in os.scandir(path) if o.is_file()]\n", " res = _get_files(path, f, extensions)\n", " return L(res)" ] }, { "cell_type": "markdown", "id": "e23cf75c", "metadata": {}, "source": [ "This is the most general way to grab a bunch of file names from disk. If you pass `extensions` (including the `.`) then returned file names are filtered by that list. Only those files directly in `path` are included, unless you pass `recurse`, in which case all child folders are also searched recursively. `folders` is an optional list of directories to limit the search to." ] }, { "cell_type": "code", "execution_count": null, "id": "e55b1e77", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(#709) [Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/9243.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/9519.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/7534.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/9082.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/8377.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/994.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/8559.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/8217.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/8571.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/8954.png')...]" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t3 = get_files(path/'train'/'3', extensions='.png', recurse=False)\n", "t7 = get_files(path/'train'/'7', extensions='.png', recurse=False)\n", "t = get_files(path/'train', extensions='.png', recurse=True)\n", "test_eq(len(t), len(t3)+len(t7))\n", "test_eq(len(get_files(path/'train'/'3', extensions='.jpg', recurse=False)),0)\n", "test_eq(len(t), len(get_files(path, extensions='.png', recurse=True, folders='train')))\n", "t" ] }, { "cell_type": "code", "execution_count": null, "id": "79e038ed", "metadata": {}, "outputs": [], "source": [ "#| hide\n", "test_eq(len(get_files(path/'train'/'3', recurse=False)),346)\n", "test_eq(len(get_files(path, extensions='.png', recurse=True, folders=['train', 'test'])),729)\n", "test_eq(len(get_files(path, extensions='.png', recurse=True, folders='train')),709)\n", "test_eq(len(get_files(path, extensions='.png', recurse=True, folders='training')),0)" ] }, { "cell_type": "markdown", "id": "45dee6f7", "metadata": {}, "source": [ "It's often useful to be able to create functions with customized behavior. `fastai.data` generally uses functions named as CamelCase verbs ending in `er` to create these functions. `FileGetter` is a simple example of such a function creator." ] }, { "cell_type": "code", "execution_count": null, "id": "7facd818", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def FileGetter(suf='', extensions=None, recurse=True, folders=None):\n", " \"Create `get_files` partial function that searches path suffix `suf`, only in `folders`, if specified, and passes along args\"\n", " def _inner(o, extensions=extensions, recurse=recurse, folders=folders):\n", " return get_files(o/suf, extensions, recurse, folders)\n", " return _inner" ] }, { "cell_type": "code", "execution_count": null, "id": "42a41187", "metadata": {}, "outputs": [], "source": [ "fpng = FileGetter(extensions='.png', recurse=False)\n", "test_eq(len(t7), len(fpng(path/'train'/'7')))\n", "test_eq(len(t), len(fpng(path/'train', recurse=True)))\n", "fpng_r = FileGetter(extensions='.png', recurse=True)\n", "test_eq(len(t), len(fpng_r(path/'train')))" ] }, { "cell_type": "code", "execution_count": null, "id": "2a760615", "metadata": {}, "outputs": [], "source": [ "#| export\n", "image_extensions = set(k for k,v in mimetypes.types_map.items() if v.startswith('image/'))" ] }, { "cell_type": "code", "execution_count": null, "id": "37020562", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def get_image_files(path, recurse=True, folders=None):\n", " \"Get image files in `path` recursively, only in `folders`, if specified.\"\n", " return get_files(path, extensions=image_extensions, recurse=recurse, folders=folders)" ] }, { "cell_type": "markdown", "id": "c74d474e", "metadata": {}, "source": [ "This is simply `get_files` called with a list of standard image extensions." ] }, { "cell_type": "code", "execution_count": null, "id": "fde1d48a", "metadata": {}, "outputs": [], "source": [ "test_eq(len(t), len(get_image_files(path, recurse=True, folders='train')))" ] }, { "cell_type": "code", "execution_count": null, "id": "74e2ba93", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def ImageGetter(suf='', recurse=True, folders=None):\n", " \"Create `get_image_files` partial that searches suffix `suf` and passes along `kwargs`, only in `folders`, if specified\"\n", " def _inner(o, recurse=recurse, folders=folders): return get_image_files(o/suf, recurse, folders)\n", " return _inner" ] }, { "cell_type": "markdown", "id": "85b88ee0", "metadata": {}, "source": [ "Same as `FileGetter`, but for image extensions." ] }, { "cell_type": "code", "execution_count": null, "id": "c2da2bf2", "metadata": {}, "outputs": [], "source": [ "test_eq(len(get_files(path/'train', extensions='.png', recurse=True, folders='3')),\n", " len(ImageGetter( 'train', recurse=True, folders='3')(path)))" ] }, { "cell_type": "code", "execution_count": null, "id": "a73cf240", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def get_text_files(path, recurse=True, folders=None):\n", " \"Get text files in `path` recursively, only in `folders`, if specified.\"\n", " return get_files(path, extensions=['.txt'], recurse=recurse, folders=folders)" ] }, { "cell_type": "code", "execution_count": null, "id": "5ec82947", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class ItemGetter(ItemTransform):\n", " \"Creates a proper transform that applies `itemgetter(i)` (even on a tuple)\"\n", " _retain = False\n", " def __init__(self, i): self.i = i\n", " def encodes(self, x): return x[self.i]" ] }, { "cell_type": "code", "execution_count": null, "id": "93b027bf", "metadata": {}, "outputs": [], "source": [ "test_eq(ItemGetter(1)((1,2,3)), 2)\n", "test_eq(ItemGetter(1)(L(1,2,3)), 2)\n", "test_eq(ItemGetter(1)([1,2,3]), 2)\n", "test_eq(ItemGetter(1)(np.array([1,2,3])), 2)" ] }, { "cell_type": "code", "execution_count": null, "id": "de0e1d17", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class AttrGetter(ItemTransform):\n", " \"Creates a proper transform that applies `attrgetter(nm)` (even on a tuple)\"\n", " _retain = False\n", " def __init__(self, nm, default=None): store_attr()\n", " def encodes(self, x): return getattr(x, self.nm, self.default)" ] }, { "cell_type": "code", "execution_count": null, "id": "2d84b059", "metadata": {}, "outputs": [], "source": [ "test_eq(AttrGetter('shape')(torch.randn([4,5])), [4,5])\n", "test_eq(AttrGetter('shape', [0])([4,5]), [0])" ] }, { "cell_type": "markdown", "id": "ba85dea2", "metadata": {}, "source": [ "### Split" ] }, { "cell_type": "markdown", "id": "1214aa3d", "metadata": {}, "source": [ "The next set of functions are used to *split* data into training and validation sets. The functions return two lists - a list of indices or masks for each of training and validation sets." ] }, { "cell_type": "code", "execution_count": null, "id": "197fe4a6", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def RandomSplitter(valid_pct=0.2, seed=None):\n", " \"Create function that splits `items` between train/val with `valid_pct` randomly.\"\n", " def _inner(o):\n", " if seed is not None: torch.manual_seed(seed)\n", " rand_idx = L(list(torch.randperm(len(o)).numpy()))\n", " cut = int(valid_pct * len(o))\n", " return rand_idx[cut:],rand_idx[:cut]\n", " return _inner" ] }, { "cell_type": "code", "execution_count": null, "id": "4398004c", "metadata": {}, "outputs": [], "source": [ "def _test_splitter(f, items=None):\n", " \"A basic set of condition a splitter must pass\"\n", " items = ifnone(items, range_of(30))\n", " trn,val = f(items)\n", " assert 0 20]) / 10, test_size)" ] }, { "cell_type": "code", "execution_count": null, "id": "479a3a7d", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def IndexSplitter(valid_idx):\n", " \"Split `items` so that `val_idx` are in the validation set and the others in the training set\"\n", " def _inner(o):\n", " train_idx = np.setdiff1d(np.array(range_of(o)), np.array(valid_idx))\n", " return L(train_idx, use_list=True), L(valid_idx, use_list=True)\n", " return _inner" ] }, { "cell_type": "code", "execution_count": null, "id": "9014fdc8", "metadata": {}, "outputs": [], "source": [ "items = 'a,b,c,d,e,f,g,h,i,j'.split(',') #to make obvious that splits indexes and not items.\n", "splitter = IndexSplitter([3,7,9])\n", "\n", "_test_splitter(splitter, items)\n", "test_eq(splitter(items),[[0,1,2,4,5,6,8],[3,7,9]])" ] }, { "cell_type": "code", "execution_count": null, "id": "4881d8de", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def EndSplitter(valid_pct=0.2, valid_last=True):\n", " \"Create function that splits `items` between train/val with `valid_pct` at the end if `valid_last` else at the start. Useful for ordered data.\"\n", " assert 00 else []\n", "\n", " def __call__(self, o, **kwargs):\n", " if len(self.cols) == 1: return self._do_one(o, self.cols[0])\n", " return L(self._do_one(o, c) for c in self.cols)" ] }, { "cell_type": "markdown", "id": "0edfccf5", "metadata": {}, "source": [ "`cols` can be a list of column names or a list of indices (or a mix of both). If `label_delim` is passed, the result is split using it." ] }, { "cell_type": "code", "execution_count": null, "id": "6fb06de1", "metadata": {}, "outputs": [], "source": [ "df = pd.DataFrame({'a': 'a b c d'.split(), 'b': ['1 2', '0', '', '1 2 3']})\n", "f = ColReader('a', pref='0', suff='1')\n", "test_eq([f(o) for o in df.itertuples()], '0a1 0b1 0c1 0d1'.split())\n", "\n", "f = ColReader('b', label_delim=' ')\n", "test_eq([f(o) for o in df.itertuples()], [['1', '2'], ['0'], [], ['1', '2', '3']])\n", "\n", "df['a1'] = df['a']\n", "f = ColReader(['a', 'a1'], pref='0', suff='1')\n", "test_eq([f(o) for o in df.itertuples()], [L('0a1', '0a1'), L('0b1', '0b1'), L('0c1', '0c1'), L('0d1', '0d1')])\n", "\n", "df = pd.DataFrame({'a': [L(0,1), L(2,3,4), L(5,6,7)]})\n", "f = ColReader('a')\n", "test_eq([f(o) for o in df.itertuples()], [L(0,1), L(2,3,4), L(5,6,7)])\n", "\n", "df['name'] = df['a']\n", "f = ColReader('name')\n", "test_eq([f(df.iloc[0,:])], [L(0,1)])\n", "\n", "df['mask'] = df['a']\n", "f = ColReader('mask')\n", "test_eq([f(o) for o in df.itertuples()], [L(0,1), L(2,3,4), L(5,6,7)])\n", "test_eq([f(df.iloc[0,:])], [L(0,1)])" ] }, { "cell_type": "markdown", "id": "87a542b3", "metadata": {}, "source": [ "## Categorize -" ] }, { "cell_type": "code", "execution_count": null, "id": "fd27d2a0", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class CategoryMap(CollBase):\n", " \"Collection of categories with the reverse mapping in `o2i`\"\n", " def __init__(self, col, sort=True, add_na=False, strict=False):\n", " if hasattr(col, 'dtype') and isinstance(col.dtype, CategoricalDtype):\n", " items = L(col.cat.categories, use_list=True)\n", " #Remove non-used categories while keeping order\n", " if strict: items = L(o for o in items if o in col.unique())\n", " else:\n", " if not hasattr(col,'unique'): col = L(col, use_list=True)\n", " # `o==o` is the generalized definition of non-NaN used by Pandas\n", " items = L(o for o in col.unique() if o==o)\n", " if sort: items = items.sorted()\n", " self.items = '#na#' + items if add_na else items\n", " self.o2i = defaultdict(int, self.items.val2idx()) if add_na else dict(self.items.val2idx())\n", "\n", " def map_objs(self,objs):\n", " \"Map `objs` to IDs\"\n", " return L(self.o2i[o] for o in objs)\n", "\n", " def map_ids(self,ids):\n", " \"Map `ids` to objects in vocab\"\n", " return L(self.items[o] for o in ids)\n", "\n", " def __eq__(self,b): return all_equal(b,self)" ] }, { "cell_type": "code", "execution_count": null, "id": "e3ee284c", "metadata": {}, "outputs": [], "source": [ "t = CategoryMap([4,2,3,4])\n", "test_eq(t, [2,3,4])\n", "test_eq(t.o2i, {2:0,3:1,4:2})\n", "test_eq(t.map_objs([2,3]), [0,1])\n", "test_eq(t.map_ids([0,1]), [2,3])\n", "with expect_fail(): t.o2i['unseen label']" ] }, { "cell_type": "code", "execution_count": null, "id": "4383c69b", "metadata": {}, "outputs": [], "source": [ "t = CategoryMap([4,2,3,4], add_na=True)\n", "test_eq(t, ['#na#',2,3,4])\n", "test_eq(t.o2i, {'#na#':0,2:1,3:2,4:3})" ] }, { "cell_type": "code", "execution_count": null, "id": "0f36dc7c", "metadata": {}, "outputs": [], "source": [ "t = CategoryMap(pd.Series([4,2,3,4]), sort=False)\n", "test_eq(t, [4,2,3])\n", "test_eq(t.o2i, {4:0,2:1,3:2})" ] }, { "cell_type": "code", "execution_count": null, "id": "1a2dd76c", "metadata": {}, "outputs": [], "source": [ "col = pd.Series(pd.Categorical(['M','H','L','M'], categories=['H','M','L'], ordered=True))\n", "t = CategoryMap(col)\n", "test_eq(t, ['H','M','L'])\n", "test_eq(t.o2i, {'H':0,'M':1,'L':2})" ] }, { "cell_type": "code", "execution_count": null, "id": "f59e4f7e", "metadata": {}, "outputs": [], "source": [ "col = pd.Series(pd.Categorical(['M','H','M'], categories=['H','M','L'], ordered=True))\n", "t = CategoryMap(col, strict=True)\n", "test_eq(t, ['H','M'])\n", "test_eq(t.o2i, {'H':0,'M':1})" ] }, { "cell_type": "code", "execution_count": null, "id": "3805c226", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class Categorize(DisplayedTransform):\n", " \"Reversible transform of category string to `vocab` id\"\n", " loss_func,order=CrossEntropyLossFlat(),1\n", " def __init__(self, vocab=None, sort=True, add_na=False):\n", " if vocab is not None: vocab = CategoryMap(vocab, sort=sort, add_na=add_na)\n", " store_attr()\n", "\n", " def setups(self, dsets):\n", " if self.vocab is None and dsets is not None: self.vocab = CategoryMap(dsets, sort=self.sort, add_na=self.add_na)\n", " self.c = len(self.vocab)\n", "\n", " def encodes(self, o):\n", " try:\n", " return TensorCategory(self.vocab.o2i[o])\n", " except KeyError as e:\n", " raise KeyError(f\"Label '{o}' was not included in the training dataset\") from e\n", " def decodes(self, o): return Category (self.vocab [o])" ] }, { "cell_type": "code", "execution_count": null, "id": "1c417d2d", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class Category(str, ShowTitle): _show_args = {'label': 'category'}" ] }, { "cell_type": "code", "execution_count": null, "id": "9cb3ad29", "metadata": {}, "outputs": [], "source": [ "cat = Categorize()\n", "tds = Datasets(['cat', 'dog', 'cat'], tfms=[cat])\n", "test_eq(cat.vocab, ['cat', 'dog'])\n", "test_eq(cat('cat'), 0)\n", "test_eq(cat.decode(1), 'dog')\n", "test_stdout(lambda: show_at(tds,2), 'cat')\n", "with expect_fail(): cat('bird')" ] }, { "cell_type": "code", "execution_count": null, "id": "98082733", "metadata": {}, "outputs": [], "source": [ "cat = Categorize(add_na=True)\n", "tds = Datasets(['cat', 'dog', 'cat'], tfms=[cat])\n", "test_eq(cat.vocab, ['#na#', 'cat', 'dog'])\n", "test_eq(cat('cat'), 1)\n", "test_eq(cat.decode(2), 'dog')\n", "test_stdout(lambda: show_at(tds,2), 'cat')" ] }, { "cell_type": "code", "execution_count": null, "id": "f586f42d", "metadata": {}, "outputs": [], "source": [ "cat = Categorize(vocab=['dog', 'cat'], sort=False, add_na=True)\n", "tds = Datasets(['cat', 'dog', 'cat'], tfms=[cat])\n", "test_eq(cat.vocab, ['#na#', 'dog', 'cat'])\n", "test_eq(cat('dog'), 1)\n", "test_eq(cat.decode(2), 'cat')\n", "test_stdout(lambda: show_at(tds,2), 'cat')" ] }, { "cell_type": "markdown", "id": "75d22a20", "metadata": {}, "source": [ "## Multicategorize -" ] }, { "cell_type": "code", "execution_count": null, "id": "06a11d28", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class MultiCategorize(Categorize):\n", " \"Reversible transform of multi-category strings to `vocab` id\"\n", " loss_func,order=BCEWithLogitsLossFlat(),1\n", " def __init__(self, vocab=None, add_na=False): super().__init__(vocab=vocab,add_na=add_na,sort=vocab==None)\n", "\n", " def setups(self, dsets):\n", " if not dsets: return\n", " if self.vocab is None:\n", " vals = set()\n", " for b in dsets: vals = vals.union(set(b))\n", " self.vocab = CategoryMap(list(vals), add_na=self.add_na)\n", "\n", " def encodes(self, o):\n", " if not all(elem in self.vocab.o2i.keys() for elem in o):\n", " diff = [elem for elem in o if elem not in self.vocab.o2i.keys()]\n", " diff_str = \"', '\".join(diff)\n", " raise KeyError(f\"Labels '{diff_str}' were not included in the training dataset\")\n", " return TensorMultiCategory([self.vocab.o2i[o_] for o_ in o])\n", " def decodes(self, o): return MultiCategory ([self.vocab [o_] for o_ in o])" ] }, { "cell_type": "code", "execution_count": null, "id": "1e368de1", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class MultiCategory(L):\n", " def show(self, ctx=None, sep=';', color='black', **kwargs):\n", " return show_title(sep.join(self.map(str)), ctx=ctx, color=color, **kwargs)" ] }, { "cell_type": "code", "execution_count": null, "id": "669391e1", "metadata": {}, "outputs": [], "source": [ "cat = MultiCategorize()\n", "tds = Datasets([['b', 'c'], ['a'], ['a', 'c'], []], tfms=[cat])\n", "test_eq(tds[3][0], TensorMultiCategory([]))\n", "test_eq(cat.vocab, ['a', 'b', 'c'])\n", "test_eq(cat(['a', 'c']), tensor([0,2]))\n", "test_eq(cat([]), tensor([]))\n", "test_eq(cat.decode([1]), ['b'])\n", "test_eq(cat.decode([0,2]), ['a', 'c'])\n", "test_stdout(lambda: show_at(tds,2), 'a;c')\n", "\n", "# if vocab supplied, ensure it maintains its order (i.e., it doesn't sort)\n", "cat = MultiCategorize(vocab=['z', 'y', 'x'])\n", "test_eq(cat.vocab, ['z','y','x'])\n", "\n", "with expect_fail(): cat('bird')" ] }, { "cell_type": "code", "execution_count": null, "id": "02cc0b52", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class OneHotEncode(DisplayedTransform):\n", " \"One-hot encodes targets\"\n", " order=2\n", " def __init__(self, c=None): store_attr()\n", "\n", " def setups(self, dsets):\n", " if self.c is None: self.c = len(L(getattr(dsets, 'vocab', None)))\n", " if not self.c: warn(\"Couldn't infer the number of classes, please pass a value for `c` at init\")\n", "\n", " def encodes(self, o): return TensorMultiCategory(one_hot(o, self.c).float())\n", " def decodes(self, o): return one_hot_decode(o, None)" ] }, { "cell_type": "markdown", "id": "e4de7c4c", "metadata": {}, "source": [ "Works in conjunction with ` MultiCategorize` or on its own if you have one-hot encoded targets (pass a `vocab` for decoding and `do_encode=False` in this case)" ] }, { "cell_type": "code", "execution_count": null, "id": "a192f0c0", "metadata": {}, "outputs": [], "source": [ "_tfm = OneHotEncode(c=3)\n", "test_eq(_tfm([0,2]), tensor([1.,0,1]))\n", "test_eq(_tfm.decode(tensor([0,1,1])), [1,2])" ] }, { "cell_type": "code", "execution_count": null, "id": "c7ea8d86", "metadata": {}, "outputs": [], "source": [ "tds = Datasets([['b', 'c'], ['a'], ['a', 'c'], []], [[MultiCategorize(), OneHotEncode()]])\n", "test_eq(tds[1], [tensor([1.,0,0])])\n", "test_eq(tds[3], [tensor([0.,0,0])])\n", "test_eq(tds.decode([tensor([False, True, True])]), [['b','c']])\n", "test_eq(type(tds[1][0]), TensorMultiCategory)\n", "test_stdout(lambda: show_at(tds,2), 'a;c')" ] }, { "cell_type": "code", "execution_count": null, "id": "30e95ba3", "metadata": {}, "outputs": [], "source": [ "#| hide\n", "#test with passing the vocab\n", "tds = Datasets([['b', 'c'], ['a'], ['a', 'c'], []], [[MultiCategorize(vocab=['a', 'b', 'c']), OneHotEncode()]])\n", "test_eq(tds[1], [tensor([1.,0,0])])\n", "test_eq(tds[3], [tensor([0.,0,0])])\n", "test_eq(tds.decode([tensor([False, True, True])]), [['b','c']])\n", "test_eq(type(tds[1][0]), TensorMultiCategory)\n", "test_stdout(lambda: show_at(tds,2), 'a;c')" ] }, { "cell_type": "code", "execution_count": null, "id": "0bab07b7", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class EncodedMultiCategorize(Categorize):\n", " \"Transform of one-hot encoded multi-category that decodes with `vocab`\"\n", " loss_func,order=BCEWithLogitsLossFlat(),1\n", " def __init__(self, vocab):\n", " super().__init__(vocab, sort=vocab==None)\n", " self.c = len(vocab)\n", " def encodes(self, o): return TensorMultiCategory(tensor(o).float())\n", " def decodes(self, o): return MultiCategory (one_hot_decode(o, self.vocab))" ] }, { "cell_type": "code", "execution_count": null, "id": "305d25c6", "metadata": {}, "outputs": [], "source": [ "_tfm = EncodedMultiCategorize(vocab=['a', 'b', 'c'])\n", "test_eq(_tfm([1,0,1]), tensor([1., 0., 1.]))\n", "test_eq(type(_tfm([1,0,1])), TensorMultiCategory)\n", "test_eq(_tfm.decode(tensor([False, True, True])), ['b','c'])\n", "\n", "_tfm2 = EncodedMultiCategorize(vocab=['c', 'b', 'a'])\n", "test_eq(_tfm2.vocab, ['c', 'b', 'a'])" ] }, { "cell_type": "code", "execution_count": null, "id": "b7893be0", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class RegressionSetup(DisplayedTransform):\n", " \"Transform that floatifies targets\"\n", " loss_func=MSELossFlat()\n", " def __init__(self, c=None): store_attr()\n", "\n", " def encodes(self, o): return tensor(o).float()\n", " def decodes(self, o): return TitledFloat(o) if o.ndim==0 else TitledTuple(o_.item() for o_ in o)\n", " def setups(self, dsets):\n", " if self.c is not None: return\n", " try: self.c = len(dsets[0]) if hasattr(dsets[0], '__len__') else 1\n", " except: self.c = 0" ] }, { "cell_type": "code", "execution_count": null, "id": "c195357f", "metadata": {}, "outputs": [], "source": [ "_tfm = RegressionSetup()\n", "dsets = Datasets([0, 1, 2], RegressionSetup)\n", "test_eq(dsets.c, 1)\n", "test_eq_type(dsets[0], (tensor(0.),))\n", "\n", "dsets = Datasets([[0, 1, 2], [3,4,5]], RegressionSetup)\n", "test_eq(dsets.c, 3)\n", "test_eq_type(dsets[0], (tensor([0.,1.,2.]),))" ] }, { "cell_type": "code", "execution_count": null, "id": "b724db30", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def get_c(dls):\n", " if getattr(dls, 'c', False): return dls.c\n", " if nested_attr(dls, 'train.after_item.c', False): return dls.train.after_item.c\n", " if nested_attr(dls, 'train.after_batch.c', False): return dls.train.after_batch.c\n", " vocab = getattr(dls, 'vocab', [])\n", " if len(vocab) > 0 and is_listy(vocab[-1]): vocab = vocab[-1]\n", " return len(vocab)" ] }, { "cell_type": "markdown", "id": "26014402", "metadata": {}, "source": [ "## End-to-end dataset example with MNIST" ] }, { "cell_type": "markdown", "id": "ec41fd09", "metadata": {}, "source": [ "Let's show how to use those functions to grab the mnist dataset in a `Datasets`. First we grab all the images." ] }, { "cell_type": "code", "execution_count": null, "id": "d02bc371", "metadata": {}, "outputs": [], "source": [ "path = untar_data(URLs.MNIST_TINY)\n", "items = get_image_files(path)" ] }, { "cell_type": "markdown", "id": "934cacf1", "metadata": {}, "source": [ "Then we split between train and validation depending on the folder." ] }, { "cell_type": "code", "execution_count": null, "id": "d979a449", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((#3) [Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/9243.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/9519.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/train/7/7534.png')],\n", " (#3) [Path('/Users/jhoward/.fastai/data/mnist_tiny/valid/7/9294.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/valid/7/9257.png'),Path('/Users/jhoward/.fastai/data/mnist_tiny/valid/7/8175.png')])" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "splitter = GrandparentSplitter()\n", "splits = splitter(items)\n", "train,valid = (items[i] for i in splits)\n", "train[:3],valid[:3]" ] }, { "cell_type": "markdown", "id": "6be33cf3", "metadata": {}, "source": [ "Our inputs are images that we open and convert to tensors, our targets are labeled depending on the parent directory and are categories." ] }, { "cell_type": "code", "execution_count": null, "id": "fe451f60", "metadata": {}, "outputs": [], "source": [ "from PIL import Image" ] }, { "cell_type": "code", "execution_count": null, "id": "c0dfaf25", "metadata": {}, "outputs": [], "source": [ "def open_img(fn:Path): return Image.open(fn).copy()\n", "def img2tensor(im:Image.Image): return TensorImage(array(im)[None])\n", "\n", "tfms = [[open_img, img2tensor],\n", " [parent_label, Categorize()]]\n", "train_ds = Datasets(train, tfms)" ] }, { "cell_type": "code", "execution_count": null, "id": "170ae4c3", "metadata": {}, "outputs": [], "source": [ "x,y = train_ds[3]\n", "xd,yd = decode_at(train_ds,3)\n", "test_eq(parent_label(train[3]),yd)\n", "test_eq(array(Image.open(train[3])),xd[0].numpy())" ] }, { "cell_type": "code", "execution_count": null, "id": "fff0c0d8", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ax = show_at(train_ds, 3, cmap=\"Greys\", figsize=(1,1))" ] }, { "cell_type": "code", "execution_count": null, "id": "aec732da", "metadata": {}, "outputs": [], "source": [ "assert ax.title.get_text() in ('3','7')\n", "test_fig_exists(ax)" ] }, { "cell_type": "markdown", "id": "313f1696", "metadata": {}, "source": [ "## ToTensor -" ] }, { "cell_type": "code", "execution_count": null, "id": "3767ffe5", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class ToTensor(Transform):\n", " \"Convert item to appropriate tensor class\"\n", " order = 5" ] }, { "cell_type": "markdown", "id": "e60a1aeb", "metadata": {}, "source": [ "## IntToFloatTensor -" ] }, { "cell_type": "code", "execution_count": null, "id": "ef22c9f0", "metadata": {}, "outputs": [], "source": [ "#| export\n", "class IntToFloatTensor(DisplayedTransform):\n", " \"Transform image to float tensor, optionally dividing by 255 (e.g. for images).\"\n", " order = 10 #Need to run after PIL transforms on the GPU\n", " def __init__(self, div=255., div_mask=1): store_attr()\n", " def encodes(self, o:TensorImage): return o.float().div_(self.div)\n", " def encodes(self, o:TensorMask ): return (o.long() / self.div_mask).long()\n", " def decodes(self, o:TensorImage): return ((o.clamp(0., 1.) * self.div).long()) if self.div else o" ] }, { "cell_type": "code", "execution_count": null, "id": "148cfb2d", "metadata": {}, "outputs": [], "source": [ "t = (TensorImage(tensor(1)),tensor(2).long(),TensorMask(tensor(3)))\n", "tfm = IntToFloatTensor()\n", "ft = tfm(t)\n", "test_eq(ft, [1./255, 2, 3])\n", "test_eq(type(ft[0]), TensorImage)\n", "test_eq(type(ft[2]), TensorMask)\n", "test_eq(ft[0].type(),'torch.FloatTensor')\n", "test_eq(ft[1].type(),'torch.LongTensor')\n", "test_eq(ft[2].type(),'torch.LongTensor')" ] }, { "cell_type": "markdown", "id": "fd8513cb", "metadata": {}, "source": [ "## Normalization -" ] }, { "cell_type": "code", "execution_count": null, "id": "e50efa08", "metadata": {}, "outputs": [], "source": [ "#| export\n", "def broadcast_vec(dim, ndim, *t, cuda=True):\n", " \"Make a vector broadcastable over `dim` (out of `ndim` total) by prepending and appending unit axes\"\n", " v = [1]*ndim\n", " v[dim] = -1\n", " f = to_device if cuda else noop\n", " return [f(tensor(o).view(*v)) for o in t]" ] }, { "cell_type": "code", "execution_count": null, "id": "d365cc25", "metadata": {}, "outputs": [], "source": [ "#| export\n", "@docs\n", "class Normalize(DisplayedTransform):\n", " \"Normalize/denorm batch of `TensorImage`\"\n", " parameters,order = L('mean', 'std'),99\n", " def __init__(self, mean=None, std=None, axes=(0,2,3)): store_attr()\n", "\n", " @classmethod\n", " def from_stats(cls, mean, std, dim=1, ndim=4, cuda=True): return cls(*broadcast_vec(dim, ndim, mean, std, cuda=cuda))\n", "\n", " def setups(self, dl:DataLoader):\n", " if self.mean is None or self.std is None:\n", " x,*_ = dl.one_batch()\n", " self.mean,self.std = x.mean(self.axes, keepdim=True),x.std(self.axes, keepdim=True)+1e-7\n", " def encodes(self, x:TensorImage): return (x-self.mean) / self.std\n", " def decodes(self, x:TensorImage):\n", " f = to_cpu if x.device.type=='cpu' else noop\n", " return (x*f(self.std) + f(self.mean))\n", "\n", " _docs=dict(encodes=\"Normalize batch\", decodes=\"Denormalize batch\", setups=\"Calculate mean/std statistics from DataLoader if not provided\")" ] }, { "cell_type": "code", "execution_count": null, "id": "4235d415", "metadata": {}, "outputs": [], "source": [ "mean,std = [0.5]*3,[0.5]*3\n", "mean,std = broadcast_vec(1, 4, mean, std)\n", "batch_tfms = [IntToFloatTensor(), Normalize.from_stats(mean,std)]\n", "tdl = TfmdDL(train_ds, after_batch=batch_tfms, bs=4, device=default_device())" ] }, { "cell_type": "code", "execution_count": null, "id": "ede70d80", "metadata": {}, "outputs": [], "source": [ "x,y = tdl.one_batch()\n", "xd,yd = tdl.decode((x,y))\n", "\n", "assert x.type().endswith('.FloatTensor')\n", "test_eq(xd.type(), 'torch.LongTensor')\n", "test_eq(type(x), TensorImage)\n", "test_eq(type(y), TensorCategory)\n", "assert x.mean()<0.0\n", "assert x.std()>0.3\n", "assert 00.9, x.std()" ] }, { "cell_type": "code", "execution_count": null, "id": "197fbe3e", "metadata": {}, "outputs": [], "source": [ "#Just for visuals\n", "from fastai.vision.core import *" ] }, { "cell_type": "code", "execution_count": null, "id": "eeec27cc", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "tdl.show_batch((x,y))" ] }, { "cell_type": "code", "execution_count": null, "id": "1f77bce2", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#| hide\n", "x,y = cast(x,Tensor),cast(y,Tensor) #Lose type of tensors (to emulate predictions)\n", "test_ne(type(x), TensorImage)\n", "tdl.show_batch((x,y), figsize=(1,1)) #Check that types are put back by dl." ] }, { "cell_type": "markdown", "id": "390f5150", "metadata": {}, "source": [ "## Export -" ] }, { "cell_type": "code", "execution_count": null, "id": "d9487e03", "metadata": {}, "outputs": [], "source": [ "#| hide\n", "from nbdev import nbdev_export\n", "nbdev_export()" ] }, { "cell_type": "code", "execution_count": null, "id": "e6a9169d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 5 }