diff --git a/nbs/006_data.core.ipynb b/nbs/006_data.core.ipynb index 7d4d82eb9..ced6d17a2 100644 --- a/nbs/006_data.core.ipynb +++ b/nbs/006_data.core.ipynb @@ -88,14 +88,14 @@ " res = cast(o, cls) # if the tensor results in a dtype torch.float64 a copy is made as dtype torch.float32\n", " for k,v in kwargs.items(): setattr(res, k, v)\n", " return res\n", - " \n", + "\n", " @property\n", " def data(self): return cast(self, Tensor)\n", - " \n", + "\n", " def __repr__(self):\n", " if self.ndim > 0: return f'NumpyTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})'\n", " else: return f'NumpyTensor([{self.data}], device={self.device}, dtype={self.dtype})'\n", - " \n", + "\n", "\n", " def show(self, ax=None, ctx=None, title=None, **kwargs):\n", " if self.ndim == 0: return str(self.data)\n", @@ -111,7 +111,7 @@ " ax.set_title(title, weight='bold', color=title_color)\n", " plt.tight_layout()\n", " return ax\n", - " \n", + "\n", "\n", "class ToNumpyTensor(Transform):\n", " \"Transforms an object into NumpyTensor\"\n", @@ -133,10 +133,10 @@ " res = cast(o, cls) # if the tensor results in a dtype torch.float64 a copy is made as dtype torch.float32\n", " for k,v in kwargs.items(): setattr(res, k, v)\n", " return res\n", - " \n", + "\n", " @property\n", " def data(self): return cast(self, Tensor)\n", - " \n", + "\n", " def show(self, ax=None, ctx=None, title=None, **kwargs):\n", " if self.ndim == 0: return str(self.data)\n", " elif self.ndim != 2: self = type(self)(to2d(self))\n", @@ -151,7 +151,7 @@ " ax.set_title(title, weight='bold', color=title_color)\n", " plt.tight_layout()\n", " return ax\n", - " \n", + "\n", " @property\n", " def vars(self):\n", " return self.shape[-2]\n", @@ -506,12 +506,12 @@ "outputs": [], "source": [ "#|export\n", - "class TSLabelTensor(NumpyTensor): \n", + "class TSLabelTensor(NumpyTensor):\n", " def __repr__(self):\n", " if self.ndim == 0: return f'{self.data}'\n", " else: return f'TSLabelTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})'\n", "\n", - "class TSMaskTensor(NumpyTensor): \n", + "class TSMaskTensor(NumpyTensor):\n", " def __repr__(self):\n", " if self.ndim == 0: return f'{self.data}'\n", " else: return f'TSMaskTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})'" @@ -578,22 +578,22 @@ " loss_func=MSELossFlat()\n", " def encodes(self, o:torch.Tensor): return o.float()\n", " def encodes(self, o): return np.asarray(o, dtype=np.float32)\n", - " def decodes(self, o): \n", - " if o.ndim==0: return TitledFloat(o) \n", - " else: \n", + " def decodes(self, o):\n", + " if o.ndim==0: return TitledFloat(o)\n", + " else:\n", " return TitledTuple(o.cpu().numpy().tolist())\n", - " \n", + "\n", "\n", "class ToInt(Transform):\n", " \"Transforms an object dtype to int\"\n", " def encodes(self, o:torch.Tensor): return o.long()\n", " def encodes(self, o): return np.asarray(o).astype(np.float32).astype(np.int64)\n", - " def decodes(self, o): \n", - " if o.ndim==0: return TitledFloat(o) \n", - " else: \n", + " def decodes(self, o):\n", + " if o.ndim==0: return TitledFloat(o)\n", + " else:\n", " return TitledTuple(o.cpu().numpy().tolist())\n", - " \n", - " \n", + "\n", + "\n", "class TSClassification(DisplayedTransform):\n", " \"Vectorized, reversible transform of category string to `vocab` id\"\n", " loss_func,order,vectorized=CrossEntropyLossFlat(),1,True\n", @@ -626,7 +626,7 @@ " else:\n", " return stack(MultiCategory(self.vocab[o.flatten()])).reshape(*o.shape)\n", "\n", - " \n", + "\n", "TSCategorize = TSClassification\n", "TSRegression = ToFloat\n", "TSForecasting = ToFloat" @@ -724,7 +724,7 @@ "class TSMultiLabelClassification(Categorize):\n", " \"Reversible combined transform of multi-category strings to one-hot encoded `vocab` id\"\n", " loss_func,order=BCEWithLogitsLossFlat(),1\n", - " def __init__(self, c=None, vocab=None, add_na=False, sort=True): \n", + " def __init__(self, c=None, vocab=None, add_na=False, sort=True):\n", " super().__init__(vocab=vocab,add_na=add_na,sort=sort)\n", " self.c = c\n", "\n", @@ -744,7 +744,7 @@ " diff_str = \"', '\".join(diff)\n", " raise KeyError(f\"Labels '{diff_str}' were not included in the training dataset\")\n", " return TensorMultiCategory(one_hot([self.vocab.o2i[o_] for o_ in o], self.c).float())\n", - " def decodes(self, o): \n", + " def decodes(self, o):\n", " if o.ndim == 2:\n", " return MultiCategory([self.vocab[o_] for o_ in o])\n", " else:\n", @@ -764,7 +764,7 @@ " self.item_tfms = ToNumpyTensor + L(item_tfms)\n", " self.batch_tfms = L(batch_tfms)\n", " self.dl_type,self.dls_kwargs = dl_type,({} if dls_kwargs is None else dls_kwargs)\n", - " \n", + "\n", "class TSTensorBlock():\n", " def __init__(self, type_tfms=None, item_tfms=None, batch_tfms=None, dl_type=None, dls_kwargs=None):\n", " self.type_tfms = L(type_tfms)\n", @@ -795,7 +795,7 @@ " def __getitem__(self, idx): return (self.X[idx],) if self.y is None else (self.X[idx], self.y[idx])\n", " def __len__(self): return len(self.X)\n", "\n", - " \n", + "\n", "class NumpyDataset():\n", " def __init__(self, X, y=None, types=None): self.X, self.y, self.types = X, y, types\n", " def __getitem__(self, idx):\n", @@ -862,14 +862,14 @@ " \"Flattens a list of lists with splits\"\n", "\n", " def __flatten_list(lst):\n", - " if lst is None: \n", + " if lst is None:\n", " return L([])\n", - " if not hasattr(lst, \"__iter__\"): \n", + " if not hasattr(lst, \"__iter__\"):\n", " lst = [lst]\n", "\n", " # clean_up_list\n", " if len(lst) > 10:\n", - " return lst \n", + " return lst\n", " else:\n", " lst = [l for l in lst if l is not None or (hasattr(l, \"__len__\") and len(l) == 0)]\n", "\n", @@ -892,20 +892,20 @@ "\n", "def _remove_brackets(l):\n", " return [li if (not li or not is_listy(li) or len(li) > 1) else li[0] for li in l]\n", - " \n", + "\n", "class NoTfmLists(TfmdLists):\n", " def __init__(self, items, tfms=None, splits=None, split_idx=None, types=None, do_setup=False, **kwargs):\n", " self.splits = ifnone(splits, L(np.arange(len(items)).tolist(),[]))\n", " self._splits = _flatten_list(self.splits)\n", " store_attr('items,types,split_idx')\n", " self.tfms = Pipeline(split_idx=split_idx)\n", - " def subset(self, i, **kwargs): return type(self)(self.items, splits=self.splits[i], split_idx=i, do_setup=False, types=self.types, \n", + " def subset(self, i, **kwargs): return type(self)(self.items, splits=self.splits[i], split_idx=i, do_setup=False, types=self.types,\n", " **kwargs)\n", " def __getitem__(self, it):\n", " if hasattr(self.items, 'oindex'): return self.items.oindex[self._splits[it]]\n", " else: return self.items[self._splits[it]]\n", " def __len__(self): return len(self._splits)\n", - " def __repr__(self): \n", + " def __repr__(self):\n", " if hasattr(self.items, \"shape\"):\n", " return f\"{self.__class__.__name__}: {self.items.__class__.__name__}{(len(self), *self.items.shape[1:])}\"\n", " else:\n", @@ -921,7 +921,7 @@ "class TSTfmdLists(TfmdLists):\n", " def __getitem__(self, it):\n", " # res = self._get(it)\n", - " if hasattr(self.items, 'oindex'): res = self.items.oindex[it] \n", + " if hasattr(self.items, 'oindex'): res = self.items.oindex[it]\n", " else: res = self.items[it]\n", " if self._after_item is None: return res\n", " else: return self._after_item(res)" @@ -1083,7 +1083,7 @@ " self.n_inp = 1\n", " if kwargs.get('splits', None) is not None:\n", " split_idxs = _flatten_list(kwargs['splits'])\n", - " else: \n", + " else:\n", " split_idxs = _flatten_list(np.arange(len(self)))\n", " self.split_idxs = split_idxs\n", "\n", @@ -1102,16 +1102,16 @@ " return type(self)(*self[i], inplace=True, tfms=None, splits=splits, split_idx=ifnone(self.split_idx, 1))\n", "\n", " def __len__(self): return len(self.tls[0])\n", - " \n", + "\n", " def _new(self, X, y=None, **kwargs):\n", " return type(self)(X, y=y, tfms=self.tfms, inplace=self.inplace, do_setup=False, **kwargs)\n", "\n", " def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], n_inp=self.n_inp, inplace=self.inplace)\n", - " \n", + "\n", " def show_at(self, idx, **kwargs):\n", " self.show(self[idx], **kwargs)\n", " plt.show()\n", - " \n", + "\n", " def __repr__(self): return tscoll_repr(self)\n", "\n", "\n", @@ -1133,37 +1133,37 @@ "class TSDatasets(Datasets):\n", " \"\"\"A dataset that creates tuples from X (and optionally y) and applies `item_tfms`\"\"\"\n", " typs = TSTensor, torch.as_tensor\n", - " def __init__(self, X=None, y=None, items=None, sel_vars=None, sel_steps=None, tfms=None, tls=None, n_inp=None, dl_type=None, \n", + " def __init__(self, X=None, y=None, items=None, sel_vars=None, sel_steps=None, tfms=None, tls=None, n_inp=None, dl_type=None,\n", " inplace=True, **kwargs):\n", "\n", " # Prepare X (and y)\n", " if X is not None:\n", - " if not hasattr(X, '__array__'): \n", + " if not hasattr(X, '__array__'):\n", " X = np.asarray(X)\n", " X = to3d(X)\n", " if y is not None:\n", - " if not hasattr(y, '__array__'): \n", + " if not hasattr(y, '__array__'):\n", " y = np.asarray(y)\n", - " elif hasattr(y, \"iloc\"): \n", + " elif hasattr(y, \"iloc\"):\n", " y = toarray(y)\n", "\n", " # Prepare sel_vars and sel_steps\n", " self.multi_index = False\n", " if sel_vars is None or (type(sel_vars) == slice and sel_vars == slice(None)):\n", " self.sel_vars = slice(None)\n", - " elif type(sel_vars) == slice: \n", + " elif type(sel_vars) == slice:\n", " self.sel_vars = sel_vars\n", " self.multi_index = True\n", " else:\n", " self.sel_vars = np.asarray(sel_vars)\n", " if sel_steps is not None and type(sel_steps) != slice: self.sel_vars = sel_vars[:, None]\n", " self.multi_index = True\n", - " if sel_steps is None or (type(sel_steps) == slice and sel_steps == slice(None)): \n", + " if sel_steps is None or (type(sel_steps) == slice and sel_steps == slice(None)):\n", " self.sel_steps = slice(None)\n", - " elif type(sel_steps) == slice: \n", + " elif type(sel_steps) == slice:\n", " self.sel_steps = sel_steps\n", " self.multi_index = True\n", - " else: \n", + " else:\n", " self.sel_steps = np.asarray(sel_steps)\n", " self.multi_index = True\n", " self.tfms, self.inplace = tfms, inplace\n", @@ -1195,11 +1195,11 @@ " self.ptls = L([typ(stack(tl[:]))[...,self.sel_vars, self.sel_steps] if (i==0 and self.multi_index) else typ(stack(tl[:])) \\\n", " for i,(tl,typ) in enumerate(zip(self.tls,self.typs))]) if inplace and len(tls[0]) != 0 else tls\n", " self.no_tfm = False\n", - " \n", + "\n", " self.n_inp = 1\n", " if kwargs.get('splits', None) is not None:\n", " split_idxs = _flatten_list(kwargs.get('splits'))\n", - " else: \n", + " else:\n", " split_idxs = np.arange(len(self), dtype=smallest_dtype(len(self)))\n", " self.split_idxs = split_idxs\n", "\n", @@ -1209,34 +1209,34 @@ " else:\n", " return tuple([typ(stack(ptl[it]))[...,self.sel_vars, self.sel_steps] if (i==0 and self.multi_index) else typ(stack(ptl[it])) \\\n", " for i,(ptl,typ) in enumerate(zip(self.ptls,self.typs))])\n", - " \n", + "\n", " def subset(self, i):\n", " if is_indexer(i):\n", " return type(self)(tls=L([tl.subset(i) for tl in self.tls]), inplace=self.inplace, tfms=self.tfms,\n", - " sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=None if self.splits is None else self.splits[i], \n", + " sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=None if self.splits is None else self.splits[i],\n", " split_idx=i)\n", " else:\n", " if self.splits is None:\n", - " splits = None \n", + " splits = None\n", " else:\n", " min_dtype = np.min_scalar_type(len(i))\n", " splits = np.arange(len(i), dtype=min_dtype)\n", - " return type(self)(*self[i], inplace=True, tfms=None, \n", + " return type(self)(*self[i], inplace=True, tfms=None,\n", " sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=splits, split_idx=ifnone(self.split_idx, 1))\n", - " \n", + "\n", " def _new(self, X, y=None, **kwargs):\n", - " return type(self)(X, y=y, sel_vars=self.sel_vars, sel_steps=self.sel_steps, tfms=self.tfms, inplace=self.inplace, \n", + " return type(self)(X, y=y, sel_vars=self.sel_vars, sel_steps=self.sel_steps, tfms=self.tfms, inplace=self.inplace,\n", " do_setup=False, **kwargs)\n", - " \n", - " def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], sel_vars=self.sel_vars, sel_steps=self.sel_steps, \n", + "\n", + " def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], sel_vars=self.sel_vars, sel_steps=self.sel_steps,\n", " n_inp=self.n_inp, inplace=self.inplace)\n", "\n", " def __len__(self): return len(self.tls[0])\n", - " \n", + "\n", " def show_at(self, idx, **kwargs):\n", " self.show(self[idx], **kwargs)\n", " plt.show()\n", - " \n", + "\n", " def __repr__(self): return tscoll_repr(self)" ] }, @@ -1294,7 +1294,7 @@ "def add_ds(dsets, X, y=None, inplace=True):\n", " \"Create test datasets from X (and y) using validation transforms of `dsets`\"\n", " items = tuple((X,)) if y is None else tuple((X, y))\n", - " with_labels = False if y is None else True \n", + " with_labels = False if y is None else True\n", " if isinstance(dsets, TSDatasets):\n", " tls = dsets.tls if with_labels else dsets.tls[:dsets.n_inp]\n", " new_tls = L([tl._new(item, split_idx=1) for tl,item in zip(tls, items)])\n", @@ -1310,7 +1310,7 @@ " elif isinstance(dsets, TfmdLists):\n", " new_tl = dsets._new(items, split_idx=1)\n", " return new_tl\n", - " else: \n", + " else:\n", " raise Exception(f\"Expected a `Datasets` or a `TfmdLists` but got {dsets.__class__.__name__}\")\n", "\n", "@patch\n", @@ -1475,9 +1475,9 @@ "outputs": [], "source": [ "dsets = TSDatasets(X_on_disk, splits=splits, inplace=False)\n", - "assert np.shares_memory(X_on_disk, dsets.tls[0].items) \n", + "assert np.shares_memory(X_on_disk, dsets.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.ptls[0].items)\n", - "assert np.shares_memory(X_on_disk, dsets.train.tls[0].items) \n", + "assert np.shares_memory(X_on_disk, dsets.train.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.train.ptls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.valid.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.valid.ptls[0].items)\n", @@ -1520,11 +1520,11 @@ "outputs": [], "source": [ "dsets = TSDatasets(X_on_disk, y_array, tfms=None, splits=splits, inplace=False)\n", - "assert np.shares_memory(X_on_disk, dsets.tls[0].items) \n", + "assert np.shares_memory(X_on_disk, dsets.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.ptls[0].items)\n", - "assert np.shares_memory(X_on_disk, dsets.train.tls[0].items) \n", + "assert np.shares_memory(X_on_disk, dsets.train.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.train.ptls[0].items)\n", - "assert np.shares_memory(X_on_disk, dsets.valid.tls[0].items) \n", + "assert np.shares_memory(X_on_disk, dsets.valid.tls[0].items)\n", "assert np.shares_memory(X_on_disk, dsets.valid.ptls[0].items)\n", "\n", "idxs = random_choice(len(dsets), 10, False)\n", @@ -1702,14 +1702,14 @@ " if num_workers is None: num_workers = min(16, defaults.cpus)\n", " if sampler is not None and shuffle:\n", " raise ValueError('sampler option is mutually exclusive with shuffle')\n", - " \n", + "\n", " for nm in _batch_tfms:\n", " if nm == 'after_batch' and kwargs.get('batch_tfms',None) is not None: kwargs[nm] = Pipeline(listify(kwargs.get('batch_tfms')))\n", " else: kwargs[nm] = Pipeline(kwargs.get(nm,None))\n", " bs = max(1, min(bs, len(dataset))) # bs cannot be 1\n", " if is_listy(partial_n): partial_n = partial_n[0]\n", " if isinstance(partial_n, float): partial_n = int(round(partial_n * len(dataset)))\n", - " if partial_n is not None: \n", + " if partial_n is not None:\n", " partial_n = min(partial_n, len(dataset))\n", " bs = min(bs, partial_n)\n", " if weights is not None: weights = weights / weights.sum()\n", @@ -1717,10 +1717,10 @@ " super().__init__(dataset, bs=bs, shuffle=shuffle, drop_last=drop_last, num_workers=num_workers, verbose=verbose, do_setup=do_setup, **kwargs)\n", " if vocab is not None:\n", " self.vocab = vocab\n", - " \n", + "\n", " def new_dl(self, X, y=None, bs=64):\n", " assert X.ndim == 3, \"You must pass an X iterable with 3 dimensions [batch_size x n_vars x seq_len]\"\n", - " if y is not None: \n", + " if y is not None:\n", " y = np.asarray(y)\n", " assert y.ndim > 0, \"You must pass a y iterable with at least 1 dimension\"\n", " ds = self.dataset.add_dataset(X, y=y)\n", @@ -1730,14 +1730,14 @@ " if self.shuffle or self.sampler is not None:\n", " if self.sort and hasattr(b, 'sort'): b.sort()\n", " self.idxs = L(b)\n", - " else: \n", + " else:\n", " if self.n is not None:\n", " b = slice(b[0], min(self.n, b[0] + self.bs))\n", " else:\n", " b = slice(b[0], b[0] + self.bs)\n", - " \n", + "\n", " self.idxs = b\n", - " if hasattr(self, \"split_idxs\"): \n", + " if hasattr(self, \"split_idxs\"):\n", " self.input_idxs = self.split_idxs[b]\n", " else: self.input_idxs = self.idxs\n", " return self.dataset[b]\n", @@ -1746,7 +1746,7 @@ " if self.indexed: return self.dataset[s or 0]\n", " elif s is None: return next(self.it)\n", " else: raise IndexError(\"Cannot index an iterable dataset numerically - must use `None`.\")\n", - " \n", + "\n", " def get_idxs(self):\n", " if self.n==0: return []\n", " if self.partial_n is not None: n = min(self.partial_n, self.n)\n", @@ -1794,12 +1794,12 @@ " if self.n == 0: return 0\n", " elif self.partial_n is None: return super().__len__()\n", " return self.partial_n//self.bs + (0 if self.drop_last or self.partial_n%self.bs==0 else 1)\n", - " \n", + "\n", " @delegates(plt.subplots)\n", - " def show_batch(self, b=None, ctxs=None, max_n=9, nrows=3, ncols=3, figsize=None, unique=False, sharex=True, sharey=False, decode=False, \n", + " def show_batch(self, b=None, ctxs=None, max_n=9, nrows=3, ncols=3, figsize=None, unique=False, sharex=True, sharey=False, decode=False,\n", " show_title=True, **kwargs):\n", - " \n", - " old_sort = self.sort \n", + "\n", + " old_sort = self.sort\n", " self.sort = False # disable sorting when showing a batch to ensure varied samples\n", "\n", " if unique:\n", @@ -1819,13 +1819,13 @@ " if figsize is None: figsize = (ncols*6, math.ceil(max_n/ncols)*4)\n", " if ctxs is None: ctxs = get_grid(max_n, nrows=nrows, ncols=ncols, figsize=figsize, sharex=sharex, sharey=sharey, **kwargs)\n", " if show_title:\n", - " for i,ctx in enumerate(ctxs): \n", + " for i,ctx in enumerate(ctxs):\n", " show_tuple(db[i], ctx=ctx)\n", " else:\n", " db = [x for x,_ in db]\n", - " for i,ctx in enumerate(ctxs): \n", + " for i,ctx in enumerate(ctxs):\n", " db[i].show(ctx=ctx)\n", - " \n", + "\n", " self.sort = old_sort\n", "\n", " @delegates(plt.subplots)\n", @@ -1874,7 +1874,7 @@ "\n", " @property\n", " def c(self):\n", - " if len(self.dataset) == 0: \n", + " if len(self.dataset) == 0:\n", " return 0\n", " if hasattr(self, \"vocab\"):\n", " return len(self.vocab)\n", @@ -1991,7 +1991,7 @@ " return cls.from_dblock(dblock, source, **kwargs)\n", "\n", " @classmethod\n", - " def from_dsets(cls, *ds, path='.', bs=64, num_workers=0, batch_tfms=None, device=None, shuffle_train=True, drop_last=True, \n", + " def from_dsets(cls, *ds, path='.', bs=64, num_workers=0, batch_tfms=None, device=None, shuffle_train=True, drop_last=True,\n", " weights=None, partial_n=None, sampler=None, sort=False, vocab=None, **kwargs):\n", " device = ifnone(device, default_device())\n", " if batch_tfms is not None and not isinstance(batch_tfms, list): batch_tfms = [batch_tfms]\n", @@ -2026,8 +2026,8 @@ "#|export\n", "class StratifiedSampler:\n", " \"Sampler where batches preserve the percentage of samples for each class\"\n", - " \n", - " def __init__(self, \n", + "\n", + " def __init__(self,\n", " y, # The target variable for supervised learning problems. Stratification is done based on the y labels.\n", " bs : int = 64, # Batch size\n", " shuffle : bool = False, # Flag to shuffle each class’s samples before splitting into batches.\n", @@ -2105,14 +2105,14 @@ "outputs": [], "source": [ "#|export\n", - "def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], return_best=True, \n", - " verbose=True): \n", + "def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], return_best=True,\n", + " verbose=True):\n", "\n", - " if not torch.cuda.is_available(): \n", + " if not torch.cuda.is_available():\n", " num_workers = 0\n", " n_iters = min(n_iters, len(dl))\n", " if not return_best: verbose = True\n", - " \n", + "\n", " nw = dl.fake_l.num_workers\n", " pm = dl.fake_l.pin_memory\n", " pf = dl.fake_l.prefetch_factor\n", @@ -2121,25 +2121,25 @@ " best_nw = nw\n", " best_pm = pm\n", " best_pf = pf\n", - " \n", + "\n", " # num_workers\n", " if not num_workers: best_nw = nw\n", " elif isinstance(num_workers, Integral): best_nw = num_workers\n", - " else: \n", + " else:\n", " best_time = np.inf\n", " for _nw in num_workers:\n", " dl.fake_l.num_workers = _nw\n", " timer.start(False)\n", " for i, _ in enumerate(dl):\n", - " if i == n_iters - 1: \n", + " if i == n_iters - 1:\n", " t = timer.stop() / (i + 1)\n", " pv(f' num_workers: {_nw:2} pin_memory: {pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', verbose)\n", - " if t < best_time: \n", + " if t < best_time:\n", " best_nw = _nw\n", " best_time = t\n", " break\n", " dl.fake_l.num_workers = best_nw\n", - " \n", + "\n", "\n", " # pin_memory\n", " if not pin_memory: best_pm = pm\n", @@ -2151,11 +2151,11 @@ " dl.fake_l.pin_memory = _pm\n", " timer.start(False)\n", " for i, _ in enumerate(dl):\n", - " if i == n_iters - 1: \n", + " if i == n_iters - 1:\n", " t = timer.stop() / (i + 1)\n", - " pv(f' num_workers: {best_nw:2} pin_memory: {_pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', \n", + " pv(f' num_workers: {best_nw:2} pin_memory: {_pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter',\n", " verbose)\n", - " if t < best_time: \n", + " if t < best_time:\n", " best_pm = _pm\n", " best_time = t\n", " break\n", @@ -2172,27 +2172,27 @@ " dl.fake_l.prefetch_factor = _pf\n", " timer.start(False)\n", " for i, _ in enumerate(dl):\n", - " if i == n_iters - 1: \n", + " if i == n_iters - 1:\n", " t = timer.stop() / (i + 1)\n", - " pv(f' num_workers: {best_nw:2} pin_memory: {best_pm!s:^5} prefetch_factor: {_pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', \n", + " pv(f' num_workers: {best_nw:2} pin_memory: {best_pm!s:^5} prefetch_factor: {_pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter',\n", " verbose)\n", - " if t < best_time: \n", + " if t < best_time:\n", " best_pf = _pf\n", " best_time = t\n", " break\n", " dl.fake_l.prefetch_factor = best_pf\n", - " \n", - " except KeyboardInterrupt: \n", + "\n", + " except KeyboardInterrupt:\n", " dl.fake_l.num_workers = best_nw if return_best else nw\n", " dl.fake_l.pin_memory = best_pm if return_best else pm\n", " dl.fake_l.prefetch_factor = best_pf if return_best else pf\n", "\n", - " if not return_best: \n", + " if not return_best:\n", " dl.fake_l.num_workers = nw\n", " dl.fake_l.pin_memory = pm\n", " dl.fake_l.prefetch_factor = pf\n", "\n", - " if verbose: \n", + " if verbose:\n", " print('\\n best dl params:')\n", " print(f' best num_workers : {best_nw}')\n", " print(f' best pin_memory : {best_pm}')\n", @@ -2202,13 +2202,13 @@ "\n", " return dl\n", "\n", - "def get_best_dls_params(dls, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], \n", - " return_best=True, verbose=True): \n", - " \n", + "def get_best_dls_params(dls, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8],\n", + " return_best=True, verbose=True):\n", + "\n", " for i in range(len(dls.loaders)):\n", " try:\n", " pv(f'\\nDataloader {i}\\n', verbose)\n", - " dls.loaders[i] = get_best_dl_params(dls.loaders[i], n_iters=n_iters, num_workers=num_workers, pin_memory=pin_memory, \n", + " dls.loaders[i] = get_best_dl_params(dls.loaders[i], n_iters=n_iters, num_workers=num_workers, pin_memory=pin_memory,\n", " prefetch_factor=prefetch_factor, return_best=return_best, verbose=verbose)\n", " except KeyboardInterrupt: pass\n", " return dls" @@ -2224,9 +2224,9 @@ "def _check_splits(X, splits):\n", " if splits is None:\n", " _dtype = smallest_dtype(len(X))\n", - " if len(X) < 1e6: \n", + " if len(X) < 1e6:\n", " splits = (L(np.arange(len(X), dtype=_dtype).tolist()), L())\n", - " else: \n", + " else:\n", " _dtype = smallest_dtype(len(X))\n", " splits = (np.arange(len(X), dtype=_dtype), L())\n", " elif isinstance(splits, (tuple, list, L, np.ndarray)):\n", @@ -2241,7 +2241,7 @@ " return splits\n", "\n", "def get_ts_dls(X, y=None, splits=None, sel_vars=None, sel_steps=None, tfms=None, inplace=True,\n", - " path='.', bs=64, batch_tfms=None, num_workers=0, device=None, shuffle_train=True, drop_last=True, \n", + " path='.', bs=64, batch_tfms=None, num_workers=0, device=None, shuffle_train=True, drop_last=True,\n", " weights=None, partial_n=None, sampler=None, sort=False, **kwargs):\n", " splits = _check_splits(X, splits)\n", " create_dir(path, verbose=False)\n", @@ -2251,7 +2251,7 @@ " assert len(X) == len(weights), 'len(X) != len(weights)'\n", " weights = [weights[split] if i == 0 else None for i,split in enumerate(splits)] # weights only applied to train set\n", " dls = TSDataLoaders.from_dsets(*dsets, path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers,\n", - " device=device, shuffle_train=shuffle_train, drop_last=drop_last, weights=weights, \n", + " device=device, shuffle_train=shuffle_train, drop_last=drop_last, weights=weights,\n", " partial_n=partial_n, sampler=sampler, sort=sort, **kwargs)\n", " return dls\n", "\n", @@ -2281,9 +2281,9 @@ "def _check_split(X, split):\n", " if split is None:\n", " _dtype = smallest_dtype(len(X))\n", - " if len(X) < 1e6: \n", + " if len(X) < 1e6:\n", " split = L(np.arange(len(X), dtype=_dtype).tolist())\n", - " else: \n", + " else:\n", " _dtype = smallest_dtype(len(X))\n", " split = np.arange(len(X), dtype=_dtype)\n", " return (split, L())\n", @@ -2465,7 +2465,7 @@ "X, y, splits = get_UCR_data('OliveOil', on_disk=False, split_data=False)\n", "train_sampler = torch.utils.data.sampler.RandomSampler(splits[0])\n", "valid_sampler = torch.utils.data.sampler.SequentialSampler(splits[1])\n", - "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=8, inplace=True, \n", + "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=8, inplace=True,\n", " shuffle=False, drop_last=True, sampler=[train_sampler, valid_sampler])\n", "print('train')\n", "for _ in dls.train:\n", @@ -2484,7 +2484,7 @@ "X, y, splits = get_UCR_data('OliveOil', on_disk=False, split_data=False)\n", "train_sampler = torch.utils.data.sampler.SequentialSampler(splits[0])\n", "valid_sampler = torch.utils.data.sampler.SequentialSampler(splits[1])\n", - "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=64, inplace=True, \n", + "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=64, inplace=True,\n", " shuffle=False, sampler=[train_sampler, valid_sampler])\n", "test_eq(dls.get_idxs(), np.arange(len(splits[0])))\n", "test_eq(dls.train.get_idxs(), np.arange(len(splits[0])))\n", @@ -2495,7 +2495,7 @@ "X, y, splits = get_UCR_data('OliveOil', on_disk=False, split_data=False)\n", "train_sampler = torch.utils.data.sampler.RandomSampler(splits[0])\n", "valid_sampler = torch.utils.data.sampler.SequentialSampler(splits[0])\n", - "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=32, inplace=True, \n", + "dls = get_ts_dls(X, y, splits=splits, tfms=[None, TSClassification()], bs=32, inplace=True,\n", " shuffle=False, drop_last=True, sampler=[train_sampler, valid_sampler])\n", "test_ne(dls.train.get_idxs(), np.arange(len(splits[0])))\n", "test_eq(np.sort(dls.train.get_idxs()), np.arange(len(splits[0])))\n", @@ -2580,7 +2580,7 @@ "torch.save(ts_dls, 'export/ts_dls.pth')\n", "del ts_dls\n", "ts_dls = torch.load('export/ts_dls.pth')\n", - "for xb,yb in ts_dls.train: \n", + "for xb,yb in ts_dls.train:\n", " test_eq(tensor(X[ts_dls.train.idxs]), xb.cpu())" ] }, @@ -2856,7 +2856,7 @@ "dls.decoder((xb[0], yb[0]))\n", "dls.decoder(yb)\n", "dls.decoder(yb[0])\n", - "test_eq((dls.cat, dls.c, dls.d),(False, 1, 3)) \n", + "test_eq((dls.cat, dls.c, dls.d),(False, 1, 3))\n", "test_eq(dls.cws, None)" ] }, @@ -2891,10 +2891,10 @@ "dsid = 'OliveOil'\n", "X, y, splits = get_UCR_data(dsid, on_disk=True, split_data=False)\n", "cm = {\n", - " '1':'A', \n", + " '1':'A',\n", " '2':['B', 'C'],\n", - " '3':['B', 'D'] , \n", - " '4':'E', \n", + " '3':['B', 'D'] ,\n", + " '4':'E',\n", " }\n", "keys = cm.keys()\n", "new_cm = {k:v for k,v in zip(keys, [listify(v) for v in cm.values()])}\n", @@ -2922,10 +2922,10 @@ "dsid = 'OliveOil'\n", "X, y, splits = get_UCR_data(dsid, on_disk=True, split_data=False)\n", "cm = {\n", - " '1':'A', \n", + " '1':'A',\n", " '2':['B', 'C'],\n", - " '3':['B', 'D'] , \n", - " '4':'E', \n", + " '3':['B', 'D'] ,\n", + " '4':'E',\n", " }\n", "keys = cm.keys()\n", "new_cm = {k:v for k,v in zip(keys, [listify(v) for v in cm.values()])}\n", @@ -2961,7 +2961,7 @@ "xb,yb = dls.train.one_batch()\n", "test_eq(xb.shape, (min(bs, len(splits[0])), X.shape[1], X.shape[-1]))\n", "it = iter(dls.valid)\n", - "for xb,yb in it: \n", + "for xb,yb in it:\n", " test_close(xb.cpu(), TSTensor(X[splits[1]][dls.valid.idxs]))" ] }, @@ -2992,13 +2992,13 @@ " dl = dls.train if random.random() < .5 else dls.valid\n", " xb,yb = dl.one_batch()\n", " torch.equal(xb.cpu(), TSTensor(X_on_disk[dl.input_idxs]))\n", - " \n", + "\n", "dsets = TSDatasets(X_on_disk, y_array, tfms=[None, TSCategorize()])\n", "dls = TSDataLoaders.from_dsets(dsets, bs=32)\n", "for i in range(10):\n", " xb,yb = dls.one_batch()\n", " torch.equal(xb.cpu(), TSTensor(X_on_disk[dl.input_idxs]))\n", - " \n", + "\n", "dsets = TSDatasets(X_on_disk, tfms=None)\n", "dls = TSDataLoaders.from_dsets(dsets, bs=32)\n", "for i in range(10):\n", @@ -3072,7 +3072,7 @@ } ], "source": [ - "# test passing a list with categories instead of a numpy array \n", + "# test passing a list with categories instead of a numpy array\n", "dsid = 'NATOPS'\n", "bs = 64\n", "X2, y2, splits2 = get_UCR_data(dsid, return_split=False)\n", @@ -3240,22 +3240,22 @@ " try:\n", " timer.start(False)\n", " pbar = progress_bar(dl, leave=False)\n", - " for i, (xb, _) in enumerate(pbar): \n", - " if model is not None: \n", + " for i, (xb, _) in enumerate(pbar):\n", + " if model is not None:\n", " _ = model(xb)\n", - " if n_batches is not None and i >= n_batches - 1: \n", + " if n_batches is not None and i >= n_batches - 1:\n", " t = timer.stop()\n", " pbar.on_interrupt()\n", " break\n", - " if n_batches is None or i < n_batches - 1: \n", + " if n_batches is None or i < n_batches - 1:\n", " t = timer.stop()\n", - " \n", + "\n", " except KeyboardInterrupt:\n", " t = timer.stop()\n", " pbar.on_interrupt()\n", " return t / (i+1)\n", "\n", - "def get_dl_percent_per_epoch(dl, model, n_batches=None): \n", + "def get_dl_percent_per_epoch(dl, model, n_batches=None):\n", " dl_time = get_time_per_batch(dl, model=None, n_batches=n_batches)\n", " model_time = get_time_per_batch(dl, model=model, n_batches=n_batches)\n", " return f'{min(1, dl_time/model_time):.2%}'" diff --git a/nbs/010_data.transforms.ipynb b/nbs/010_data.transforms.ipynb index 68bf2073a..69c4ed806 100644 --- a/nbs/010_data.transforms.ipynb +++ b/nbs/010_data.transforms.ipynb @@ -74,8 +74,8 @@ "class TSIdentity(RandTransform):\n", " \"Applies the identity tfm to a `TSTensor` batch\"\n", " order = 90\n", - " def __init__(self, magnitude=None, **kwargs): \n", - " self.magnitude = magnitude \n", + " def __init__(self, magnitude=None, **kwargs):\n", + " self.magnitude = magnitude\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor): return o" ] @@ -96,11 +96,11 @@ "outputs": [], "source": [ "#|export\n", - "# partial(TSShuffle_HLs, ex=0), \n", + "# partial(TSShuffle_HLs, ex=0),\n", "class TSShuffle_HLs(RandTransform):\n", " \"Randomly shuffles HIs/LOs of an OHLC `TSTensor` batch\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -134,11 +134,11 @@ "outputs": [], "source": [ "#|export\n", - "# partial(TSShuffleSteps, ex=0), \n", + "# partial(TSShuffleSteps, ex=0),\n", "class TSShuffleSteps(RandTransform):\n", " \"Randomly shuffles consecutive sequence datapoints in batch\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -162,7 +162,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -174,7 +174,7 @@ "source": [ "t = TSTensor(torch.arange(11).float())\n", "tt_ = []\n", - "for _ in range(1000): \n", + "for _ in range(1000):\n", " tt = TSShuffleSteps()(t, split_idx=0)\n", " test_eq(len(set(tt.tolist())), len(t))\n", " test_ne(tt, t)\n", @@ -239,10 +239,10 @@ " if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:]\n", " return output\n", "\n", - "class TSMagMulNoise(RandTransform): \n", + "class TSMagMulNoise(RandTransform):\n", " \"Applies multiplicative noise on the y-axis for each step of a `TSTensor` batch\"\n", " order = 90\n", - " def __init__(self, magnitude=1, ex=None, **kwargs): \n", + " def __init__(self, magnitude=1, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -274,7 +274,7 @@ "#|export\n", "def random_curve_generator(o, magnitude=0.1, order=4, noise=None):\n", " seq_len = o.shape[-1]\n", - " f = CubicSpline(np.linspace(-seq_len, 2 * seq_len - 1, 3 * (order - 1) + 1, dtype=int), \n", + " f = CubicSpline(np.linspace(-seq_len, 2 * seq_len - 1, 3 * (order - 1) + 1, dtype=int),\n", " np.random.normal(loc=1.0, scale=magnitude, size=3 * (order - 1) + 1), axis=-1)\n", " return f(np.arange(seq_len))\n", "\n", @@ -319,7 +319,7 @@ "class TSTimeNoise(RandTransform):\n", " \"Applies noise to each step in the x-axis of a `TSTensor` batch based on smooth random curve\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -350,7 +350,7 @@ "class TSMagWarp(RandTransform):\n", " \"Applies warping to the y-axis of a `TSTensor` batch based on a smooth random curve\"\n", " order = 90\n", - " def __init__(self, magnitude=0.02, ord=4, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.02, ord=4, ex=None, **kwargs):\n", " self.magnitude, self.ord, self.ex = magnitude, ord, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -413,7 +413,7 @@ " \"\"\"Applies window slicing to the x-axis of a `TSTensor` batch based on a random linear curve based on\n", " https://halshs.archives-ouvertes.fr/halshs-01357973/document\"\"\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -443,7 +443,7 @@ "class TSMagScale(RandTransform):\n", " \"Applies scaling to the y-axis of a `TSTensor` batch based on a scalar\"\n", " order = 90\n", - " def __init__(self, magnitude=0.5, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.5, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -453,11 +453,11 @@ " output = o * scale\n", " if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:]\n", " return output\n", - " \n", + "\n", "class TSMagScalePerVar(RandTransform):\n", " \"Applies per_var scaling to the y-axis of a `TSTensor` batch based on a scalar\"\n", " order = 90\n", - " def __init__(self, magnitude=0.5, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.5, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -469,7 +469,7 @@ " output = o * scale\n", " if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:]\n", " return output\n", - " \n", + "\n", "TSMagScaleByVar = TSMagScalePerVar" ] }, @@ -485,6 +485,79 @@ "test_ne(TSMagScalePerVar()(xb, split_idx=0), xb)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#|export\n", + "def test_interpolate(mode=\"linear\"):\n", + "\n", + " assert mode in [\"nearest\", \"linear\", \"area\"], \"Mode must be 'nearest', 'linear' or 'area'.\"\n", + "\n", + " # Create a 1D tensor\n", + " tensor = torch.randn(1, 1, 8, device=default_device())\n", + "\n", + " try:\n", + " # Try to interpolate using linear mode\n", + " result = F.interpolate(tensor, scale_factor=2, mode=mode)\n", + " return True\n", + " except NotImplementedError as e:\n", + " print(f\"{mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " print(\"Error:\", e)\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "linear interpolation is not supported by mps. You can try a different mode\n", + "Error: The operator 'aten::upsample_linear1d.out' is not currently implemented for the MPS device. If you want this op to be added in priority during the prototype phase of this feature, please comment on https://github.com/pytorch/pytorch/issues/77764. As a temporary fix, you can set the environment variable `PYTORCH_ENABLE_MPS_FALLBACK=1` to use the CPU as a fallback for this op. WARNING: this will be slower than running natively on MPS.\n" + ] + }, + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Run the test\n", + "test_interpolate('linear')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_interpolate('nearest')" + ] + }, { "cell_type": "code", "execution_count": null, @@ -495,40 +568,45 @@ "class TSRandomResizedCrop(RandTransform):\n", " \"Randomly amplifies a sequence focusing on a random section of the steps\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, size=None, scale=None, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.1, size=None, scale=None, ex=None, mode='nearest', **kwargs):\n", " \"\"\"\n", " Args:\n", " size: None, int or float\n", " scale: None or tuple of 2 floats 0 < float <= 1\n", " mode: 'nearest' | 'linear' | 'area'\n", - " \n", + "\n", " \"\"\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", - " if scale is not None: \n", + " if scale is not None:\n", " assert is_listy(scale) and len(scale) == 2 and min(scale) > 0 and min(scale) <= 1, \"scale must be a tuple with 2 floats 0 < float <= 1\"\n", " self.size,self.scale = size,scale\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", " seq_len = o.shape[-1]\n", - " if self.size is not None: \n", + " if self.size is not None:\n", " size = self.size if isinstance(self.size, Integral) else int(round(self.size * seq_len))\n", " else:\n", " size = seq_len\n", - " if self.scale is not None: \n", + " if self.scale is not None:\n", " lambd = np.random.uniform(self.scale[0], self.scale[1])\n", - " else: \n", + " else:\n", " lambd = np.random.beta(self.magnitude, self.magnitude)\n", " lambd = max(lambd, 1 - lambd)\n", " win_len = int(round(seq_len * lambd))\n", - " if win_len == seq_len: \n", + " if win_len == seq_len:\n", " if size == seq_len: return o\n", - " _slice = slice(None) \n", + " _slice = slice(None)\n", " else:\n", " start = np.random.randint(0, seq_len - win_len)\n", " _slice = slice(start, start + win_len)\n", " return F.interpolate(o[..., _slice], size=size, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", - " \n", + "\n", "TSRandomZoomIn = TSRandomResizedCrop" ] }, @@ -538,9 +616,10 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSRandomResizedCrop(.5)(xb, split_idx=0).shape, xb.shape)\n", - "test_ne(TSRandomResizedCrop(size=.8, scale=(.5, 1))(xb, split_idx=0).shape, xb.shape)\n", - "test_ne(TSRandomResizedCrop(size=20, scale=(.5, 1))(xb, split_idx=0).shape, xb.shape)" + "if test_interpolate('nearest'):\n", + " test_eq(TSRandomResizedCrop(.5)(xb, split_idx=0).shape, xb.shape)\n", + " test_ne(TSRandomResizedCrop(size=.8, scale=(.5, 1))(xb, split_idx=0).shape, xb.shape)\n", + " test_ne(TSRandomResizedCrop(size=20, scale=(.5, 1))(xb, split_idx=0).shape, xb.shape)" ] }, { @@ -553,8 +632,13 @@ "class TSWindowSlicing(RandTransform):\n", " \"Randomly extracts an resize a ts slice based on https://halshs.archives-ouvertes.fr/halshs-01357973/document\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -572,8 +656,9 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSWindowSlicing()(xb, split_idx=0).shape, xb.shape)\n", - "test_ne(TSWindowSlicing()(xb, split_idx=0), xb)" + "if test_interpolate('nearest'):\n", + " test_eq(TSWindowSlicing()(xb, split_idx=0).shape, xb.shape)\n", + " test_ne(TSWindowSlicing()(xb, split_idx=0), xb)" ] }, { @@ -586,8 +671,13 @@ "class TSRandomZoomOut(RandTransform):\n", " \"Randomly compresses a sequence on the x-axis\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -610,7 +700,8 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSRandomZoomOut(.5)(xb, split_idx=0).shape, xb.shape)" + "if test_interpolate('nearest'):\n", + " test_eq(TSRandomZoomOut(.5)(xb, split_idx=0).shape, xb.shape)#" ] }, { @@ -623,8 +714,13 @@ "class TSRandomTimeScale(RandTransform):\n", " \"Randomly amplifies/ compresses a sequence on the x-axis keeping the same length\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -639,7 +735,8 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSRandomTimeScale(.5)(xb, split_idx=0).shape, xb.shape)" + "if test_interpolate('nearest'):\n", + " test_eq(TSRandomTimeScale(.5)(xb, split_idx=0).shape, xb.shape)" ] }, { @@ -652,8 +749,13 @@ "class TSRandomTimeStep(RandTransform):\n", " \"Compresses a sequence on the x-axis by randomly selecting sequence steps and interpolating to previous size\"\n", " order = 90\n", - " def __init__(self, magnitude=0.02, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.02, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -673,7 +775,8 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSRandomTimeStep()(xb, split_idx=0).shape, xb.shape)" + "if test_interpolate('nearest'):\n", + " test_eq(TSRandomTimeStep()(xb, split_idx=0).shape, xb.shape)" ] }, { @@ -697,14 +800,14 @@ " S = o.shape[-1]\n", " if isinstance(self.step_pct, tuple):\n", " step_pct = np.random.rand() * (self.step_pct[1] - self.step_pct[0]) + self.step_pct[0]\n", - " else: \n", + " else:\n", " step_pct = self.step_pct\n", " if step_pct != 1 and self.same_seq_len:\n", " idxs = np.sort(np.tile(random_choice(S, round(S * step_pct), True), math.ceil(1 / step_pct))[:S])\n", " else:\n", " idxs = np.sort(random_choice(S, round(S * step_pct), True))\n", " return o[..., idxs]\n", - " \n", + "\n", "TSSubsampleSteps = TSResampleSteps" ] }, @@ -728,13 +831,13 @@ "class TSBlur(RandTransform):\n", " \"Blurs a sequence applying a filter of type [1, 0, 1]\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", - " if filt_len is None: \n", - " filterargs = [1, 0, 1] \n", - " else: \n", + " if filt_len is None:\n", + " filterargs = [1, 0, 1]\n", + " else:\n", " filterargs = ([1] * max(1, filt_len // 2) + [0] + [1] * max(1, filt_len // 2))\n", - " self.filterargs = np.array(filterargs) \n", + " self.filterargs = np.array(filterargs)\n", " self.filterargs = self.filterargs/self.filterargs.sum()\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -764,14 +867,14 @@ "class TSSmooth(RandTransform):\n", " \"Smoothens a sequence applying a filter of type [1, 5, 1]\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " self.filterargs = np.array([1, 5, 1])\n", - " if filt_len is None: \n", - " filterargs = [1, 5, 1] \n", - " else: \n", + " if filt_len is None:\n", + " filterargs = [1, 5, 1]\n", + " else:\n", " filterargs = ([1] * max(1, filt_len // 2) + [5] + [1] * max(1, filt_len // 2))\n", - " self.filterargs = np.array(filterargs) \n", + " self.filterargs = np.array(filterargs)\n", " self.filterargs = self.filterargs/self.filterargs.sum()\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -798,20 +901,20 @@ "outputs": [], "source": [ "#|export\n", - "def maddest(d, axis=None): \n", + "def maddest(d, axis=None):\n", " #Mean Absolute Deviation\n", " return np.mean(np.absolute(d - np.mean(d, axis=axis)), axis=axis)\n", "\n", "class TSFreqDenoise(RandTransform):\n", " \"Denoises a sequence applying a wavelet decomposition method\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, thr=None, thr_mode='hard', pad_mode='per', **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, thr=None, thr_mode='hard', pad_mode='per', **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " self.wavelet, self.level, self.thr, self.thr_mode, self.pad_mode = wavelet, level, thr, thr_mode, pad_mode\n", " super().__init__(**kwargs)\n", - " try: \n", + " try:\n", " import pywt\n", - " except ImportError: \n", + " except ImportError:\n", " raise ImportError('You need to install pywt to run TSFreqDenoise')\n", " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", @@ -843,7 +946,7 @@ "metadata": {}, "outputs": [], "source": [ - "try: import pywt \n", + "try: import pywt\n", "except ImportError: pass" ] }, @@ -868,13 +971,13 @@ "class TSRandomFreqNoise(RandTransform):\n", " \"Applys random noise using a wavelet decomposition method\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, mode='constant', **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, mode='constant', **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " self.wavelet, self.level, self.mode = wavelet, level, mode\n", " super().__init__(**kwargs)\n", - " try: \n", + " try:\n", " import pywt\n", - " except ImportError: \n", + " except ImportError:\n", " raise ImportError('You need to install pywt to run TSRandomFreqNoise')\n", " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", @@ -906,8 +1009,13 @@ "class TSRandomResizedLookBack(RandTransform):\n", " \"Selects a random number of sequence steps starting from the end and return an output of the same shape\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.1, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.mode = magnitude, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -925,9 +1033,10 @@ "metadata": {}, "outputs": [], "source": [ - "for i in range(100): \n", - " o = TSRandomResizedLookBack()(xb, split_idx=0)\n", - " test_eq(o.shape[-1], xb.shape[-1])" + "if test_interpolate('nearest'):\n", + " for i in range(100):\n", + " o = TSRandomResizedLookBack()(xb, split_idx=0)\n", + " test_eq(o.shape[-1], xb.shape[-1])" ] }, { @@ -940,7 +1049,7 @@ "class TSRandomLookBackOut(RandTransform):\n", " \"Selects a random number of sequence steps starting from the end and set them to zero\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, **kwargs): \n", + " def __init__(self, magnitude=0.1, **kwargs):\n", " self.magnitude = magnitude\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -949,7 +1058,7 @@ " lambd = np.random.beta(self.magnitude, self.magnitude)\n", " lambd = min(lambd, 1 - lambd)\n", " output = o.clone()\n", - " output[..., :int(round(lambd * seq_len))] = 0 \n", + " output[..., :int(round(lambd * seq_len))] = 0\n", " return output" ] }, @@ -959,7 +1068,7 @@ "metadata": {}, "outputs": [], "source": [ - "for i in range(100): \n", + "for i in range(100):\n", " o = TSRandomLookBackOut()(xb, split_idx=0)\n", " test_eq(o.shape[-1], xb.shape[-1])" ] @@ -974,7 +1083,7 @@ "class TSVarOut(RandTransform):\n", " \"Set the value of a random number of variables to zero\"\n", " order = 90\n", - " def __init__(self, magnitude=0.05, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.05, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1014,7 +1123,7 @@ "class TSCutOut(RandTransform):\n", " \"Sets a random section of the sequence to zero\"\n", " order = 90\n", - " def __init__(self, magnitude=0.05, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.05, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1052,7 +1161,7 @@ "class TSTimeStepOut(RandTransform):\n", " \"Sets random sequence steps to zero\"\n", " order = 90\n", - " def __init__(self, magnitude=0.05, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.05, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1085,7 +1194,7 @@ "class TSRandomCropPad(RandTransform):\n", " \"Crops a section of the sequence of a random length\"\n", " order = 90\n", - " def __init__(self, magnitude=0.05, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.05, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1160,7 +1269,7 @@ " self.magnitude, self.ex = magnitude, ex\n", " self.dropout = nn.Dropout(magnitude)\n", " super().__init__(**kwargs)\n", - " \n", + "\n", " @torch.no_grad()\n", " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", @@ -1189,7 +1298,7 @@ "class TSTranslateX(RandTransform):\n", " \"Moves a selected sequence window a random number of steps\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1229,7 +1338,7 @@ "class TSRandomShift(RandTransform):\n", " \"Shifts and splits a sequence\"\n", " order = 90\n", - " def __init__(self, magnitude=0.02, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.02, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1259,7 +1368,7 @@ "class TSHorizontalFlip(RandTransform):\n", " \"Flips the sequence along the x-axis\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1289,7 +1398,7 @@ "class TSRandomTrend(RandTransform):\n", " \"Randomly rotates the sequence along the z-axis\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, **kwargs): \n", + " def __init__(self, magnitude=0.1, ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1303,7 +1412,7 @@ " output = o + t\n", " if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:]\n", " return output\n", - " \n", + "\n", "TSRandomRotate = TSRandomTrend" ] }, @@ -1326,10 +1435,10 @@ "class TSVerticalFlip(RandTransform):\n", " \"Applies a negative value to the time sequence\"\n", " order = 90\n", - " def __init__(self, magnitude=1., ex=None, **kwargs): \n", + " def __init__(self, magnitude=1., ex=None, **kwargs):\n", " self.magnitude, self.ex = magnitude, ex\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", " return - o" ] @@ -1354,11 +1463,16 @@ "class TSResize(RandTransform):\n", " \"Resizes the sequence length of a time series\"\n", " order = 90\n", - " def __init__(self, magnitude=-0.5, size=None, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=-0.5, size=None, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.size, self.ex, self.mode = magnitude, size, ex, mode\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if self.magnitude == 0: return o\n", " size = ifnone(self.size, int(round((1 + self.magnitude) * o.shape[-1])))\n", " output = F.interpolate(o, size=size, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", @@ -1371,8 +1485,9 @@ "metadata": {}, "outputs": [], "source": [ - "for sz in np.linspace(.2, 2, 10): test_eq(TSResize(sz)(xb, split_idx=0).shape[-1], int(round(xb.shape[-1]*(1+sz))))\n", - "test_ne(TSResize(1)(xb, split_idx=0), xb)" + "if test_interpolate('nearest'):\n", + " for sz in np.linspace(.2, 2, 10): test_eq(TSResize(sz)(xb, split_idx=0).shape[-1], int(round(xb.shape[-1]*(1+sz))))\n", + " test_ne(TSResize(1)(xb, split_idx=0), xb)" ] }, { @@ -1385,8 +1500,13 @@ "class TSRandomSize(RandTransform):\n", " \"Randomly resizes the sequence length of a time series\"\n", " order = 90\n", - " def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs):\n", + " def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", " def encodes(self, o: TSTensor):\n", @@ -1401,12 +1521,13 @@ "metadata": {}, "outputs": [], "source": [ - "seq_len_ = []\n", - "for i in range(100): \n", - " o = TSRandomSize(.5)(xb, split_idx=0)\n", - " seq_len_.append(o.shape[-1])\n", - "test_lt(min(seq_len_), xb.shape[-1])\n", - "test_gt(max(seq_len_), xb.shape[-1])" + "if test_interpolate('nearest'):\n", + " seq_len_ = []\n", + " for i in range(100):\n", + " o = TSRandomSize(.5)(xb, split_idx=0)\n", + " seq_len_.append(o.shape[-1])\n", + " test_lt(min(seq_len_), xb.shape[-1])\n", + " test_gt(max(seq_len_), xb.shape[-1])" ] }, { @@ -1419,11 +1540,16 @@ "class TSRandomLowRes(RandTransform):\n", " \"Randomly resizes the sequence length of a time series to a lower resolution\"\n", " order = 90\n", - " def __init__(self, magnitude=.5, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=.5, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", " size_perc = 1 - (np.random.rand() * (1 - self.magnitude))\n", " return F.interpolate(o, size=int(size_perc * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)" @@ -1439,11 +1565,16 @@ "class TSDownUpScale(RandTransform):\n", " \"Downscales a time series and upscales it again to previous sequence length\"\n", " order = 90\n", - " def __init__(self, magnitude=0.5, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=0.5, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0 or self.magnitude >= 1: return o\n", " output = F.interpolate(o, size=int((1 - self.magnitude) * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", " output = F.interpolate(output, size=o.shape[-1], mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", @@ -1457,7 +1588,8 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSDownUpScale()(xb, split_idx=0).shape, xb.shape)" + "if test_interpolate('nearest'):\n", + " test_eq(TSDownUpScale()(xb, split_idx=0).shape, xb.shape)" ] }, { @@ -1470,13 +1602,18 @@ "class TSRandomDownUpScale(RandTransform):\n", " \"Randomly downscales a time series and upscales it again to previous sequence length\"\n", " order = 90\n", - " def __init__(self, magnitude=.5, ex=None, mode='linear', **kwargs): \n", + " def __init__(self, magnitude=.5, ex=None, mode='nearest', **kwargs):\n", " \"mode: 'nearest' | 'linear' | 'area'\"\n", + "\n", + " if not test_interpolate(mode):\n", + " print(f\"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode\")\n", + " magnitude = 0\n", + "\n", " self.magnitude, self.ex, self.mode = magnitude, ex, mode\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0 or self.magnitude >= 1: return o\n", - " scale_factor = 0.5 + 0.5 * np.random.rand() \n", + " scale_factor = 0.5 + 0.5 * np.random.rand()\n", " output = F.interpolate(o, size=int(scale_factor * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", " output = F.interpolate(output, size=o.shape[-1], mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False)\n", " if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:]\n", @@ -1489,9 +1626,10 @@ "metadata": {}, "outputs": [], "source": [ - "test_eq(TSRandomDownUpScale()(xb, split_idx=0).shape, xb.shape)\n", - "test_ne(TSDownUpScale()(xb, split_idx=0), xb)\n", - "test_eq(TSDownUpScale()(xb, split_idx=1), xb)" + "if test_interpolate('nearest'):\n", + " test_eq(TSRandomDownUpScale()(xb, split_idx=0).shape, xb.shape)\n", + " test_ne(TSDownUpScale()(xb, split_idx=0), xb)\n", + " test_eq(TSDownUpScale()(xb, split_idx=1), xb)" ] }, { @@ -1527,7 +1665,7 @@ "metadata": {}, "outputs": [], "source": [ - "for i in range(5): \n", + "for i in range(5):\n", " o = TSRandomConv(magnitude=0.05, ex=None, ks=[1, 3, 5, 7])(xb, split_idx=0)\n", " test_eq(o.shape, xb.shape)" ] @@ -1570,7 +1708,7 @@ " vals[:, self._sel_vars] = torch.rand(*vals[:, self._sel_vars, 0].shape, device=o.device).unsqueeze(-1)\n", " else:\n", " if self.magnitude == 1:\n", - " return o.fill_(self.value) \n", + " return o.fill_(self.value)\n", " else:\n", " vals = torch.rand(*o.shape[:-1], device=o.device).unsqueeze(-1)\n", " elif self.sel_vars is not None or self.sel_steps is not None:\n", @@ -1582,7 +1720,7 @@ " vals[:, self._sel_vars, self._sel_steps] = torch.rand(*vals[:, self._sel_vars, self._sel_steps].shape, device=o.device)\n", " else:\n", " if self.magnitude == 1:\n", - " return o.fill_(self.value) \n", + " return o.fill_(self.value)\n", " else:\n", " vals = torch.rand_like(o)\n", " mask = vals > (1 - self.magnitude)\n", @@ -1597,13 +1735,13 @@ { "data": { "text/plain": [ - "tensor([[[0., 1., 0., 1., 0., 1., 0., 0., 1., 0.],\n", - " [1., 0., 0., 0., 1., 0., 0., 1., 0., 1.],\n", - " [0., 0., 1., 0., 0., 0., 1., 0., 0., 0.]],\n", + "tensor([[[0., 0., 1., 0., 1., 1., 0., 1., 1., 0.],\n", + " [1., 1., 0., 1., 1., 1., 1., 1., 1., 0.],\n", + " [1., 1., 1., 1., 1., 0., 0., 1., 1., 1.]],\n", "\n", - " [[0., 0., 1., 0., 1., 1., 0., 1., 0., 1.],\n", - " [1., 0., 1., 1., 0., 1., 1., 1., 1., 0.],\n", - " [0., 1., 1., 1., 1., 1., 0., 1., 0., 1.]]])" + " [[1., 1., 1., 1., 1., 0., 1., 1., 0., 1.],\n", + " [0., 0., 0., 0., 0., 1., 0., 1., 0., 1.],\n", + " [0., 1., 0., 1., 0., 0., 0., 1., 0., 0.]]])" ] }, "execution_count": null, @@ -1625,11 +1763,11 @@ "data": { "text/plain": [ "tensor([[[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [1., 1., 1., 1., 1., 0., 0., 0., 0., 1.],\n", + " [1., 1., 1., 1., 1., 0., 1., 0., 0., 0.],\n", " [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]],\n", "\n", " [[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [1., 1., 1., 1., 1., 1., 0., 1., 1., 1.],\n", + " [1., 1., 1., 1., 1., 0., 1., 0., 0., 0.],\n", " [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]])" ] }, @@ -1656,7 +1794,7 @@ " [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]],\n", "\n", " [[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", - " [0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],\n", + " [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],\n", " [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]])" ] }, @@ -1786,13 +1924,13 @@ { "data": { "text/plain": [ - "tensor([[[1., nan, 1., nan],\n", + "tensor([[[1., nan, nan, 1.],\n", " [1., 1., 1., 1.],\n", - " [1., nan, nan, nan]],\n", + " [1., nan, 1., 1.]],\n", "\n", - " [[1., 1., nan, nan],\n", + " [[nan, 1., 1., nan],\n", " [1., 1., 1., 1.],\n", - " [nan, 1., 1., nan]]])" + " [nan, nan, 1., 1.]]])" ] }, "execution_count": null, @@ -1813,13 +1951,13 @@ { "data": { "text/plain": [ - "tensor([[[1., 1., nan, nan],\n", + "tensor([[[1., 1., 1., nan],\n", " [1., 1., nan, 1.],\n", - " [1., 1., nan, 1.]],\n", + " [1., 1., nan, nan]],\n", "\n", " [[1., 1., nan, 1.],\n", - " [1., 1., nan, 1.],\n", - " [1., 1., 1., nan]]])" + " [1., 1., nan, nan],\n", + " [1., 1., nan, 1.]]])" ] }, "execution_count": null, @@ -1888,7 +2026,7 @@ "outputs": [], "source": [ "#| export\n", - "def self_mask(o): \n", + "def self_mask(o):\n", " mask1 = torch.isnan(o)\n", " mask2 = rotate_axis0(mask1)\n", " return torch.logical_and(mask2, ~mask1)\n", @@ -1911,7 +2049,7 @@ { "data": { "text/plain": [ - "(0.3083333373069763, 0.5133333206176758)" + "(0.30000001192092896, 0.49000000953674316)" ] }, "execution_count": null, @@ -1937,9 +2075,9 @@ "source": [ "#|export\n", "all_TS_randaugs = [\n", - " \n", - " TSIdentity, \n", - " \n", + "\n", + " TSIdentity,\n", + "\n", " # Noise\n", " (TSMagAddNoise, 0.1, 1.),\n", " (TSGaussianNoise, .01, 1.),\n", @@ -1947,12 +2085,12 @@ " (partial(TSTimeNoise, ex=0), 0.1, 1.),\n", " (partial(TSRandomFreqNoise, ex=0), 0.1, 1.),\n", " partial(TSShuffleSteps, ex=0),\n", - " (TSRandomTimeScale, 0.05, 0.5), \n", - " (TSRandomTimeStep, 0.05, 0.5), \n", + " (TSRandomTimeScale, 0.05, 0.5),\n", + " (TSRandomTimeStep, 0.05, 0.5),\n", " (partial(TSFreqDenoise, ex=0), 0.1, 1.),\n", " (TSRandomLowRes, 0.05, 0.5),\n", " (TSInputDropout, 0.05, .5),\n", - " \n", + "\n", " # Magnitude\n", " (partial(TSMagWarp, ex=0), 0.02, 0.2),\n", " (TSMagScale, 0.2, 1.),\n", @@ -1961,26 +2099,26 @@ " partial(TSBlur, ex=0),\n", " partial(TSSmooth, ex=0),\n", " partial(TSDownUpScale, ex=0),\n", - " partial(TSRandomDownUpScale, ex=0), \n", - " (TSRandomTrend, 0.1, 0.5), \n", - " TSVerticalFlip, \n", - " (TSVarOut, 0.05, 0.5), \n", - " (TSCutOut, 0.05, 0.5), \n", - " \n", + " partial(TSRandomDownUpScale, ex=0),\n", + " (TSRandomTrend, 0.1, 0.5),\n", + " TSVerticalFlip,\n", + " (TSVarOut, 0.05, 0.5),\n", + " (TSCutOut, 0.05, 0.5),\n", + "\n", " # Time\n", " (partial(TSTimeWarp, ex=0), 0.02, 0.2),\n", " (TSWindowWarp, 0.05, 0.5),\n", " (TSRandomSize, 0.05, 1.),\n", - " TSHorizontalFlip, \n", + " TSHorizontalFlip,\n", " (TSTranslateX, 0.1, 0.5),\n", - " (TSRandomShift, 0.02, 0.2), \n", - " (TSRandomZoomIn, 0.05, 0.5), \n", + " (TSRandomShift, 0.02, 0.2),\n", + " (TSRandomZoomIn, 0.05, 0.5),\n", " (TSWindowSlicing, 0.05, 0.2),\n", " (TSRandomZoomOut, 0.05, 0.5),\n", " (TSRandomLookBackOut, 0.1, 1.),\n", " (TSRandomResizedLookBack, 0.1, 1.),\n", " (TSTimeStepOut, 0.01, 0.2),\n", - " (TSRandomCropPad, 0.05, 0.5), \n", + " (TSRandomCropPad, 0.05, 0.5),\n", " (TSRandomResizedCrop, 0.05, 0.5),\n", " (TSMaskOut, 0.01, 0.2),\n", "]" @@ -2038,11 +2176,11 @@ "#|export\n", "class TestTfm(RandTransform):\n", " \"Utility class to test the output of selected tfms during training\"\n", - " def __init__(self, tfm, magnitude=1., ex=None, **kwargs): \n", + " def __init__(self, tfm, magnitude=1., ex=None, **kwargs):\n", " self.tfm, self.magnitude, self.ex = tfm, magnitude, ex\n", " self.tfmd, self.shape = [], []\n", " super().__init__(**kwargs)\n", - " def encodes(self, o: TSTensor): \n", + " def encodes(self, o: TSTensor):\n", " if not self.magnitude or self.magnitude <= 0: return o\n", " output = self.tfm(o, split_idx=self.split_idx)\n", " self.tfmd.append(torch.equal(o, output))\n", @@ -2102,9 +2240,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/010_data.transforms.ipynb couldn't be saved automatically. You should save it manually 👋\n", + "/Users/nacho/notebooks/tsai/nbs/010_data.transforms.ipynb saved at 2024-02-10 21:46:00\n", "Correct notebook to script conversion! 😃\n", - "Sunday 18/06/23 12:25:55 CEST\n" + "Saturday 10/02/24 21:46:03 CET\n" ] }, { diff --git a/nbs/012_data.image.ipynb b/nbs/012_data.image.ipynb index 28579951e..24f781805 100644 --- a/nbs/012_data.image.ipynb +++ b/nbs/012_data.image.ipynb @@ -117,7 +117,7 @@ "\n", " def encodes(self, o: TSTensor):\n", " device = o.device\n", - " if o.data.device.type == 'cuda': o = o.cpu()\n", + " if o.data.device.type != 'cpu': o = o.cpu()\n", " if o.ndim == 2: o = o[None]\n", " seq_len = o.shape[-1]\n", " fig = self.fig\n", @@ -182,7 +182,7 @@ "\n", " def encodes(self, o: TSTensor):\n", " device = o.device\n", - " if o.data.device.type == 'cuda': o = o.cpu()\n", + " if o.data.device.type != 'cpu': o = o.cpu()\n", " if o.ndim == 2: o = o[None]\n", " nvars, seq_len = o.shape[-2:]\n", " aspect = seq_len / nvars\n", @@ -283,7 +283,7 @@ " bs, *_, seq_len = o.shape\n", " size = ifnone(self.size, seq_len)\n", " if size != seq_len:\n", - " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0]\n", + " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0]\n", " else:\n", " o = o.reshape(-1, seq_len)\n", " output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) / 2 + .5\n", @@ -307,7 +307,7 @@ " bs, *_, seq_len = o.shape\n", " size = ifnone(self.size, seq_len)\n", " if size != seq_len:\n", - " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0]\n", + " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0]\n", " else:\n", " o = o.reshape(-1, seq_len)\n", " output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) / 2 + .5\n", @@ -331,7 +331,7 @@ " bs, *_, seq_len = o.shape\n", " size = ifnone(self.size, seq_len)\n", " if size != seq_len:\n", - " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0]\n", + " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0]\n", " else:\n", " o = o.reshape(-1, seq_len)\n", " output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size)\n", @@ -355,7 +355,7 @@ " bs, *_, seq_len = o.shape\n", " size = ifnone(self.size, seq_len)\n", " if size != seq_len:\n", - " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0]\n", + " o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0]\n", " else:\n", " o = o.reshape(-1, seq_len)\n", " output = self.encoder.fit_transform(o.cpu().numpy()) / 2\n", @@ -379,7 +379,7 @@ " o = to3d(o)\n", " bs, *_, seq_len = o.shape\n", " size = ifnone(self.size, seq_len)\n", - " if size != seq_len: o = F.interpolate(o, size=size, mode='linear', align_corners=False)\n", + " if size != seq_len: o = F.interpolate(o, size=size, mode='nearest', align_corners=None)\n", " output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size)\n", " if self.cmap and output.shape[1] == 1:\n", " output = TSImage(plt.get_cmap(self.cmap)(output)[..., :3]).squeeze(1).permute(0,3,1,2)\n", @@ -401,8 +401,8 @@ }, { "data": { - "image/jpeg": "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", - "image/png": "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RFwE9uqlyorOxA8td/12xTHGYh3n6XY+/cWKpGcGuMfVxZ/axT+9B6MP/fvq4mNE7eJfdu+6G/4zK5+ZpR9feVgs8vF8faej71p619WDVAbT6eLb0ad/z4sfGsDH9SLc7z108VoKnEZUw+k8qL7awgdVP268vnv5pgWljljQ27KgZy3oxWdI3L//CExf9kjMAPTexT886tR2ClNgJigzGKa8/3zUKUZzBJGqOwGzCZso3VDAI3IDJvM4VZ73PbCjUGo7taD08hihkkE7gdPrj//TcvSnNcN9UaakkGiSts69g9HHMagAdbeFvDGc14l46403M3kE6MrOru8kkA7eR3w47Lv3dO2abT8GnXTr+D/ffv5/FCjHgXucy7erj0q+Mdjr7dGPj9vrjfcqbvTTT8DEVRhqAykLUP1ilNuR59vu2+327br7dsWIn65PLHdnOdzp72es6WMX//wpOl/wAeXlg1dI678e377tda+4HY474JfX3Y/X28u38+n184j/x+fx9XJ7vX58u36wxBn/cPk8nn8eL39pR+nQH40ocwYuZXLR3YxBA1OeKgWgjnweLOgDQInn3pLxYrYC8uVyAPrKMqUxoocf19uPS93ux+WUMWju5enK97zj885EPQ/BnKU/HHnZI663R66GYBTmjXVQyiRHZl17h6RIveIFUI6lYaOLmYUczVmgih84TwKWBIC2l4dFAQo6gansLYHoIT69fg9Ai4TNl2IZUYNIHLQUoN6C3vZcuHbx95skb6d9jZ3dFl58YzhrgPB5c2PQmUV0G0CdaFIPGYGKVO4evmXc6b0R5b39nIvneOQND9T/ix76EoB+AwfPOF5L48Eq6Jy3e5Q0suqN7qzVkVb8DkYDUHDhmmJeydDnloUXhX1X+PZxOn8Emt4kAdBBJwPQywcAFZr792/719fd/wSdAPQFgL4C0GAUmALQohOY4li+hwtM4c+NEZcfN+8dhnatHcNQTNa6SZplTR3zoO6Hg0l9kEx+Jt24oWISmkrxxDIAvToAnWGoAP2+AfT6+f0AOk928dy2+xjplfs750GZ/rwD1G0tddhjlFib5yLETPHNLTwADXTwVG6Q5K/giNUfXAVhJliDgGklcJKFdvPWByT0BZhP3b2LT3S4n74tC2qBP0iwLJLkzin80lvO94oor+jsfZLo5IkQG0UwZ/KdbWTYqcbtOn688D47bwwXprxXxJsbrI13ebwrIMd8akEptRbUSQcAyn0mPbswjSi7YvRwjAU9/7xdvvNe/PPT7fW7AP32zFs/OxwNjt897DX00U1qYgjdxYKCTjGKBdV21oICUDDkPbUYHYB+xIIGl5sR/Xa6fdu9vu7/wAaB0W8Yzl3d6+v5+O1T8/mNwBm7LjSF6QJoMOpbyNmywm2Q2IPmuP/JAzKvLLfJRKGgQx8VqwwUo78OK4XCui5P342MAk16+T37WgSggelts6C77xdumI7fD0EnGA1AsyLr9WX/8QhQZprYyavzoEyX0spCMKtkHfRu00xBm/BIQMCMhg0QF0eG4lL/K0Ah0IJyifatTq1TAMo4x813emGEubx4kvR1PagwpYVrkgmWspEmcJPkVoSzXWFWGjPD63pjx3Vs18FuSvosluB99subdtQufnp5Vx//BtD07xp6LOgyn9we3eebwChdPIPH3ZHh7K/jy0ugKToJaEEfABps6vk37g7Q2wLoZkHzXpu4KUCf6NDp3DGfYPTNMSizBLw8/3L5/noEna/BqIGxnfbyr+Dyj8/TN8zn+aGLD0aFJm/HZ1+Hw6m3YkXnGZjyymAGGN25holALqX/Aqjo9AhABfUG0PTvIpWbP96Jzl387fC9XTz+kbeOTt9vnz+u+t9vzNKvB/H09fvP1wMuHX12TPpRI1qAdji5LGhvz4LGIMeOOGeCZVRNAJdxgCHaQABlGJpBJUEoiXu4i6flM83kMJTB9bSaF2iO0+Hwp4GePvoOlEsDy1DgF6A+CsJlBZ29ggviuSbcg46ZbPdRYq2P6yd9xPuWZT289YY7so3H6ZglzCxXym/X0vusKNP4vObBi0pIhfugZ8d2Bp1/MYcKAdNV9EmsMHZFEIvV9J0VcFl+gG/9I60/U0nldlXwkcVFs5To6Fsl3L8zCcoAwS7evXiAKRsxXD5Y0nTkXXEnt3jZMa8Os/kCi86dlXHRCI/lOcXP+2YvLpt3VSlrl1ihfeW9eBni61jBp2PjjkwUBJ2cik58hr/OiTJHnW1HfUuWdT1I7Lx8jJjDQcPqHqu5FjcbyFx/jQUdpwEi8ZVcoxBdKhej8ytjyShqLZZ2yO7Gfi6IZU32K35vXF0vYfOqWgy79wx3hGyIKDYGIaJQaPYX6RNfkdMeNklAZltgibxP2v9DyYnl2c3pyud/GIsLxDZcszD6YeTSo0nJUWjmyrCRcy2YMW3P9Uu6GrtvA+MQittinrOIUfeoyTvs+m/Mt/g2pv68VxTFzPpOV4F4W6rjFXdnOjujhGAZd3rjDTodgPpIlcKvzNj7RnCWUOZm09tZxmQ88RCWeAraGjbAykMeIF2vZzZ4gJZSkHCeTqEv31ZxjygGEuwG4a46zrUjfHZ+5KY8S+d4qPmN55pdBOKD1d3Lrc65IV4cYR6LqVjuedWGPg7DwHu+2SSMS5SWIPLK2w42CXu/2K/xnMGdlopR6ubre5qH3qcEnQmidauZ7i0ti+psFAZKDOZVoKu9EmB1onsM+Y6Vi2iZAOFOh7obUL0MYefBhwq5kvTim3EphtsilEwpLm5xzisT1SpN3QYfQSMarkQCxIT4BOr8tSEAEH+EtxbxZoPRNOpy6QbDASZWGKyoENmLOB3/HODmC0CNQ44KkpLwprlFdtRFL9/yfJPG5x/uZmA3Ewuapm14/DNJuO29IrUWxeGr0DgC5+gRRTujlHv2X7xcY8/OjkdIHoyiRpQmOqt0FIcUmbrGiCgh6tBPTZTTOm/0YFRWZ9BZjOq7ziU7kvmyvQ3JDRkP9ovL5Z9cQ9eFSsD0dhOdsywkSgCdPg1CFiwvYdc4ohb3r7vxdpMrEUUtTxIHnd4WiFEW/dV8OgjjoV8m6YOV9GI2blqCwZAYCEAT5Xow0EkmmmU02QCgZCOUYhQlL2gSCDqjXjCKDnkU56sI0gSXC6MRgq5YmFq8SkP1o09+VGxNWDS8sGL9Q61QaQ5hzAF9nITYCV/szE0fNFy0PKvOEBiaAag1JRu64345h6eTGoVM6UQni8k2e+5EyIyIsaCi09F9AOr+nd1E6ZyJas0nCMD5xrCbL+Bz/WRtfDBa8xlf0BSsYBHHvBJAYQz1y569OmKmCUMZzY49QLxMC6oWZUL2whNZlVkfoxQ0t6lUNBfDwijro5YFzWy+5SK2W5OuZcfPvgbH0AVcBqMaUdDJ7dBmQUEk5hMIIt5Cp7c+mIBglOf8GAwfGOSOlYDxblH3xA0suNwwGguKyD59x6dCaWgDASgIaJPTywvQWFBqlMlvFNgp8KKz3dRZIKKu0ZiBWgECxS4+Zn1ZUMqjiMx2ZQHWuk0oEtBoBQiCBJ9I8VcPJ5b5iZmAlc1Rga2HIHLEXwvKrASFogHnzLx6Q9Ama+PxmjnztmH+0KBytbyUKrls/cGLxjpvPLfwDkAzk8fOnTw+jO8edLwjPj47fvk+O28Ms9SDt954r4g3N5i65ok46zvdsovAhe05QM5FS3q+uO4ie9lxV8S4k2bTdtIQl3dWHF8Yu7G4gxc27BodPOFHwtFBr+KlM/lTqI6XRiA8s6aaTZrsYFnAzP5K2RL3mdeJWS6i5N11h8myOJ4TGePSZHwWeXLv5NLkuvPt9OeNUQhLl9hdkuvOYT+WEJ9bcsaEuenArmqQ9LFMxtNP8yzIlV5BJ0M+akN4oBmAovje0wegGDlQitWkslTUFilGqd3+ghGlmqzpznsHPsPCUV+GTi6zQavpxqCx889+fV6nMR34PAThyS83Q2x1jvxsT8wkolbdVUeXXP/4Hsjij0D2F7g0oFRzVgLp8i+xhxjFrjEiYgDq/jp28ULzXxa09LvTPzwr6yGvhPCNW9dp45qKTjI2T/fFTVJVnYkRHji4crg7bbsxoktoHdS5E53z98sRXi9sXLNkjtXHXd85q0CamlXJN2eU6GPpM7nu063TEj9p1nUwrGVTTuZBmSuiN/UCIkk/qhoyDNft1/H2drz9OnHbsjt97p4+9qePPb5LsqiB05NXtp5wFIox4ikQe+246GMcyFGjmWU2gMF03KsDMP8cWN1mqr2iD1/0WWrhXmI2dQIzNnFAABUcwFuGBZAmC+2s1WSeHrvSMO0bk5CGzT2Qt0cdW00tqSMXLpcomIvP7ry/Pm4/P/RR46cPza74OG7f2HmELaLZWIQxB/cpM4XhW1sssd29n7K/0549yHyHns0q2QryXwBVrWp42uEO0Fw5yENCQAxgbA8OY/qT5xC+4kF7ppG8IDN2T9sNz2Sii6caBsslrUo4V6g8h7kEqMlLlsveVYHe4NGw3uxN8yJTzVA2PmYnTodzA9BssiBACbhzKBgtTLc3N7oAeWFXpAJTZ+O/M52E2Vl3Ray5o1/b7TaMsk6LSVDujTsPms7EC7xV2SpGLYvOtw9uqndA8/RxCEYxaa0B97isO8lD4oDSzaAWOgkAUF/kDgqFKUNv94mx7+CdESYlfuZeBUu+AZTAHZ3A1DspoRl0xg9AwRst+nh4z1fQBpcbRtc0E+j2jt4GsvWgpjNxu0SUA0wBaNEJQHFew2IUn70W2VxMgCItGA06nXTgPR32HePtbTH6BHwLUH32fdJ80uyOQXMEf4Qo3T8OY+Lzi2N5eM7ddDdt8QVKbDzTyzC5Ck1r3IFAOG3AA6ApdEFTtnDnDR4CIeXXMP/sLU3LA80xou24aN6YUhQcgNJr5W646HSHRJD6aD43dBLomxtgsaa0Sfhw8Emmz4qc7wSgtGfGkczmj/DFKHdPPkZiwiYT9QJUwxKB/S2xyyoCUI0oi0U28wlSsaC+xcaFBtp4Xs6dXh2zDhk/d+VcAartDEwD0MGot9GHG6uEMaJ0jRtANwsamDJE1WZoOPMGp7YTaxhLXHRuMI09ZUDjMZaUAPBguQ/mPRa0AG0bUenaztrR91hQ0fkpQMHlhtEClE1G3mJBO/3rVC1bibFDHgDlbo7XaTCxLpA6+FQ5oyWK5a0EFqig2oEHARFSlACwYJWzBEfvWwuYrUd6iFylPi6TeXfNaP7FT7byWF388AsLwim0gC5XDXWcFhT4akEFaEZTMaI0S6BpV7Fs57Kg2Mu1U422825E19p4F8mnZ5fMNUp5zs6TzM7GM9/pReeECEYi03IRC4z6BNdHnbxSyjMA5VZUPGuxhM5Y79fx8EZTZYnb+YN3l9PF+yyMw84AQ8ij8aJT2/nVgjrtutC5de4J+L6/L2u6N4KPGP8N0AOTowxRv5hPkBqkBaZbHpp5DRAGrg8AJS3T5d7i2MungdKQdvHctWtHGV+y+/6vj/3Pjz0+V/4yn9pRtsABmlsXn7lf7SjdPWahABWpWtCdgwEiB6CaT4otbvhVzerbf/0ATJtYp/bzp5TS9uBklhpQfaqanHbx6eUfeE6WEyvS5yBm2dGBplftOmhw/rAQSJZJODr6dI2oKaNVJGSADUbnDtFdER13u5VhNvfi3Qzetbjs2AvEVzHZ+LcB3nqbGFN9cpNVlawCYSrc+XEnCdCOlVFHDNuZe/ABmY68agZHq2UeFIkr7BLdCLZgt1Dezbi4AIhntJHKGQgfvHqnoeNUy+SDRPr0hsdnK2XWqdGQNJ4BLsPpbOwZPWWnWAK72zdwbCccNyNGuXKvAeNc1BMQ38QgoFXgGN8ufpBa9dIQUbINhLqZ9MBmIjG6wIc1qnbCzqnkfHwmut1R3/elf6of5asEH0ukIYjBETYp31xxvk282l9SQQCKOUoXb4HpbREBXAg7mp6fSt9fo+s8l4L/UichcY9TAxnggk6YPnTxZin9qT28pwVjfVODzpQvea8DUZrmTzdqWJiG2BJ6iet3X9nsfSxSVYRrqkYXKsVT3xh2ity33tDRWjiX9Z2uUcI05kmmw0OMBO3p9AiUrOK8eWNEZ+dUuOJz8NDDq6gqMSKVSRUYd1Kis22UAgVi+6acHBi0AU1fVkVN9gz0104LrF7CChJGEpuNeUteHqjvWwSBKc+CqFp8pp79GhFzSHeoO/uA2GAUP3djPbUuuRwKTVvEhhKaZmm4urehU5G0PincaUMUyHDJMvRU5+67C0wFnPqMkgM+dGtMIqN2ktzrTT+tY3NAD0YboAqxNkyAYVmZR9gwKv5qHZGix/o1SftvRYTJQmfagfqkOUgAWlmvRatC2UrgD+y/8jwhnzHN2wal/RJH5mEZgilPBNzJNaLYLTFKhdL1pCdY+soGsw+qWdqJOqo7U8Vo0OP7G119nBV03gDhePjWBsMHOoEmGLVnr5ZQPQeesin0dtlODWizTrjxZggr8JXZYT/LLJyxogFAFRkZEg40AWXv/zClCdB44jIYvdvOYNQushhFWi6Y3e5byLiTiTIGhQzj2sszCsBwFp00qH0Y9RhE/o7RQhM/F6NtMo0j3tObUUbQyZAX84nm0Qb1FWrjRGd6DBB5R20Np8QDVq98K9iaxnbSM1AdeikAFIyOPm1utKxfcayBwc2ZnrYQMMSO2FCgea5Szglw2DeiqDHPckgZZiGVbYEl4hh8E4m7qwG6tHYykdR02lIXWs2zTZ7OHQRZm3Tu65pWNapgA2Wv3egxqiSJ4QhvvYkejZyfXgN87I+N3cIBGmxbe3naFXNIpM+w6UetvAdMKHwkrLRNSMWgzLKPvL2E5L6rEozmVX07rzhwpr10YUAeRSdcU0qJNl4MpEjVwMT3CakVtF2hod+H7OonHGMd7c3VDWMJFOLYweYRo7SN2jKm6LSREyaeUPw0JNWiEVNRPJ10gQwcnUvBdqaXV+cOn6JwA2+xAo7UfWBEE7Q3E6m2yANeA83Ex5T6RCEVpMq9zPQVQrz5P4hRmmo6khVxJYqZkHq1h5QxdEiNgbAmo/nCVA75D3NP2LE6zOFg3gc/lAGhkRaRUmCq7QlAITEaBaUkyBxHEHaa977ZO30RE78URMD4nHKhE6Oh9ZTHMnStNiHOZy/sRHLIwic7X4eJ7t8TDFEk851GEmDsJbEatLEjhqJWYE7XwQUAW4rgkYXPyz1ULPcprYsWAq3ju4KDErNmi4avo0eNgwZnGLHx8+6yMT41eKAhrOGJPi3I2iFOsdheXnVRi/iGv7r0gQqpwnGIGdUSI1fgSgDh8eO4E1a36pPAPCZIeDScBwcMKnh4BVIhmHH81gS2ji3i0636VoFwKjIWNKVbYhCRgGGFiPzG1EFAIHIbk8N6EBcLSnuNBSWjLdt7emokTQ4DXT8S/imlZZEgd6Kjj4wmUrBR0MXNbGPsN5GqLJniNxw/zS63RSMxfzIhGppWAMmszvA32SyULeL0nOWShKzeJ0QBJIQqtOWDzBLLp3UwjTGIolMdE01JC0emMAxP+Sddksgi95YXec0dyU3ln3MJyhJfF5rGm7dCWGBZmWvjWXHUWNmGZ3KRL5Ehn4qQ6qnxBv2P9hR6NJlka2mazjDUxnBOpfkl42JujK58kyO5yC6rxZagHJvVpLBQAA/TtnCyp7aoxdYycfiH2jAlpg7hSzAFSRYp5ZYaQs90XljjtZTIj1z9U98VgNwhtAwoy2gr21i5t0rh3jKUr9o3EEX0VA6hNyvMCXOkqW1wq5ZDATwjl7XVj0zh6omnIZcOnjIqRiNG+U47hFjhR1ZLqhBItinCUBIszkDKNJySJ7X1Mr8ShSYy4aUY2ekWh9/5RDNKDMFdLqVJ/gRamUkNralTVpj7AFjBlm4jlTE2uX6EIBd/bQuVY7w+nsxLaVBGeovDnW1V1jRZSZOCqxOzwTOxejC2agZpnASqKM6JJ0Fa/yOkhIrXVPwCj3N6vBz8NFN8I8slyfJLmVt+WViqMqW2nlrPFG/Aem5Fyi0FRCNqKpShtypmawNOrTxVoCDP0glQQk/NsGrQmBJYYeJVvNJGdJk0EAkIpl4KbaEmteApLX1NRN3qB0nFt9TkTl2ilKlmJByZQqNOWrvwTTh8NmmIhxIpmjfiKNHkUitm4Fi/U6OWS15TphKVtcIga0s3AIGnoseq+ye7hOUdgkR7AqVJUsnZGOUhpFY5J6I6s+iQlboiliKUyRha1eFZYrbKKGH1NcxTETNY4hRqwNe1/DG8yZF6W7IlmpwKS+MfzppMQOQkP7QpNXVrDVWKlK2tgeSSK0dPW7qn/Kt1irBCYR/WeAEmvtnwMBpQlFT65EwasVRbv4XUDwFBi5dbsm4chpLYsIq0EYGyljhwINzSkS4u9RqhSJ1CJLvnKmVYQ2mLKG3Yjjj8tJQyT94pizqk0Apoysge0WEThilMSsksqeScGkhDpMToxFR0Axm/yaLcESAZVxZyjmDTZCSQaTGUixSNaqz1b6yBHLYFzPOvmDoOhcQ32oDySLhEXUxKDEBJezxyFqbERq7wXNwlNfWxvAkTR+ZHl5wybGSkWgTWcIqWwmj+G4OfurUmxluTEjUQ/RC5xScidVP1Ib5HJWtU1NJN57YKgt8ct2GkJbtMlruHw5h4ef9nKpEpN16pR/4wUQgCd4YBx7AKz5EIPhycLIZmHN5TQfmQXjGSV+IVaHz1eY+/pw+hSXFDmbOmEaOcHPUTrGdS4oVqUrfAA9VD+6YIkxIYzo+RpISPJC13TtdNUvJa6P1AmZUjUdI3D37a0eiE7/GLpoXp1yX+floO+NROf3FuYMU8tOKiaVLFJFyXxJGhYdstoVJu/iP9itTy1D3weSz6MVxjI2H5WwHC8hqyJqWgxuBPUgIrHONxz/Uv4G5CwXuVZbnb0cgUZJzXtmJEybkWm7QRhE8zBdeVmnzmsohJ88xjxcBwRAgBXjIsbAQJE9OknpTD8LHSRpdn+HDWCNJ+AwZkFjpkAPRfx53dv5LuZYQLjOTD/yrm98K+pm78vpCFwXAmHG6rIVeORHpCYFNBT1dEqzSJ/EDJ0fMvWZpgUvrFkJUyKY9FP+arhE29C9ncZJwBTM491d1ZhfMqaf2WDEEKk9I0csnP712GhOSZLP4sDr8HEn9XcmyN+RZb8/Zow60yzOLRPrf8a0Q2CovyZCgfeOa6IN7Omp8QjAycc7rBLoWOclJeU/HvGpsi7hb0S6FNNWqV2hgvU9iksM1Xkkjz6G9FDtnkl51Jc0pGC8mR0ezGecXaeCtywiStGKnKbdH/fkr8vYSVMcRTMqkbUje25flwqgwQVvjEb1KNMCQ3fgUmPhnNnNRHvzwfY+5h6BFs5bUG2+mKHOJwrkpH5/d8pKW5miUcrDWnXJqNxF+VaoR5eiR+qpkYscex6Cgu57bh1GXIlrBl3iwr/JveRp42RksskymFr1W2kMW6rcAZ0asSRdFUn2ctfcLmQ5c+BjRglbuaKc+nu46pa+18IuFiCgmGJi+o8QSGFVzXT3eXZWM8dg8hlUe/0PNuhZu850VRA12ghs9iCFacuByvzPJcjqfkPC9h5brv1WjKrASe/ziPTz6GfrrVEcfOi58ffjGOrb77qJM7Lx4ysNbphZf7/UpX3BYmwKoAnm/5lUl3bLk7djdJ5CSxSIDnYSwt9alY14OywaNV4LnsLGgi3qeqPkzqmiZvFXr4LJsKuK6BH3wtcxenEcEjBnL69Ck+VfSJlhXkWUYXLLOwhuJZ4oijcWkC36fwXT3ehspSv9Q0d5p5qEXbxfngCv55IOe0ucsedGjQAvPcCoHn2LARbRMpYfW9tN6rRvwnz7QEMmfhtvWiSO8GrCHKJxBCrOAEOD19++mjpPvFzAn8QlBUN8JInYvSujRtAj5n8yEPTPMEE+C4BsFXI/k+e3w+4cp3MvnEWz9GyPeKti/CZMtj9z5md1n272SHRPag4+0dd8DCfZ+9QFhUzNOPrAflvYVD18a7vpOPcrhHvXf2PMnkWZFVob7+VoUGkRtovvE6k/dGNuQnH2LjjY8fh082MfFZfN+h5mtd1xd2K8E93Z7xX6/Pr/Ff3Ezilc9x7/0O1je2mdnc7fZ6vn47H15P12+nvYusr+yfcP2Oz9tJLLTT3XideK0EbQCwsnrTsAsNPGwpH3C6Ep9jYq1OHcLnobiEPtECdnnk70NJdv7GbvigiMd8rq3JQ7NXas0L0fnwIEuSXVjtM0YeNAUlPF3L+lRkELrdOIvXyH0LjzJikaDPEx8KRHfkKzi8OQcl4qRgIjwAFV3qPgROwDQLfh0iikYc70KTP+tBjaLG0oyJhQv0bNxgszU8PgQSc2xXSQgsCbkWQLmmRKot69J6L70uOghAWVEPQP0+e74xnK+8+SVCvvXWr2n1izB+1eBnP29wY3dZ9u/0+NMtvrqPUjZUyisfeWOYl78AaNfG/0L7Jz6qmTVKvII5G9gqOZdWFFSNGAFAUUUxCkDPvw6ffxzOvC7KXhAuB6UG+HxYM7jcMOq+Nrdn/Jcb2BWawahIdZ8EPx/vnkh+QUF0vuLc+sZ9ykAnAdDpYtBi9MuKepctA81YUNAgLjenMcsJ/gNAbUFt2gCU1uP90KwP4CPMfFub/UGDvSxdmNX/vMCft9DzXTfWOsMwRPY2ypMrBDyD2qfb7H6T10R9P8DyBCgW1KU1PQ8wipWaMIE5gBmMEjEEYkaETpsEo33ZozAlgTLErMuW7wBN88kFgIpij3tr9qpANQmENkOZNDuNCTR1hWbMp0J08RYw1ZReAs2xoMt85muZ8zWtAHT25Gbf+Gwgz/d63b/TTTK++bb05lxRz2plMcqSiAPvFfHmBjClR3Z9p+v0XKMkCGdIr2Kqo1YsAKWSYlQLKjT3L98OT3yihQ0kWBwiRm+nk7azRlQL+vJgQU9BZC0oPjIGncL06fDt8wo6vxEAqQudDxY0MM2KenGZnrbQDEbv0ASpeddjzCftHmOD0RCpASgkrgfFiKbvdmkC4yJXv2BE+ZCXFpSRgPHxWePCElXWzPteBwDlXTj6VsCAAUOGuKz25+24bn3DGjstDhpEJZj5vjRHsfb1HuseKkD0fAF0BUWahk5ffOJomwSI6FWXjp74saDU+AGgIbYoPpruj3mhjd/woLMpK95mZxii1uK4uJZTSMTntWt6Gqr64LwAZ1WFnYSvZo/zizC+o33OZg2sYmD8dHJhJQMmdlBilZ0+nQ4a91JTQji5aIhxZ5aKsvqY9Z3uYcvCCxrHaow/FbFmRjpEi2Pho3tEsd6Ube7gTwtktTI+8ezLSDwjTpYvEXBZKuH6FFTnRj86tu5i27zZIimBH8T3LZSsG4Rn17WgNq+DrmYCHI4+Xe5kDNLFFuBrHdPV6afdR9VRODUSquiQepLgwDkdMCqKO/K17Sgzr8u6LTqnvm0f/dPW76RyfeTteIfAbRf8PLFRwzi4diSqvRY1OCqCr6iFBD89HgNmXi6pA85F2184IjsVl3WYZ0As/zk2nsj1+Sd6zmGdVyAUcNmOKYnL4W5BCbvNCroxwHiGbcM+n3xli09aPz9dnsY/P813hfnGsJ8Z9gOE2a0+G9Z3lK/P2+/szP2XK+ncv9P9vfyuNT471fByfd+c5Y1h3snsC5m8ucHa+Iyo7IEcuIlOG1bfKk8dvCti3EnPTp9OAX/nziLV420MF8q5ge0Tu+Adn59xh+enw9PT4fPu3KHWDyeN47UU3gytO3/ywvSx/g9e8HUcLkzx2Zoe4+ZFuL7yAeyAJs1jx+b1XoPC1Yl1Azh0vA5B/ZdmdfHewtm5u+LNLh6XRazUw0XU+UgSY5Q/HSAztj7/cTz/efysz5bP32+4z+/uCvn5vGMHrU+218d/vZ7j2E0LpfO5i0/ck23hyBY7w+C5Y1C0ORZU1QYp0bEaVu31kbkRnMeCtoMvtpJJC4qTqUqQ3D1FWJTmtnppvQCxWVhu9ydWIMdkD2PzWeZgVGIhapnp3x2A2ikCUDqYwBSDEmjyRgwwZdMYcClGQafbu/Jxdr/P7hew3YZBx3cy2ZXHa3h8941nZ273PvZFWfbvZIdEffZRykvdbKvN69/Xvo0JRnmviMWmXRsPTBGZVkR067/piQC9G5RXx5307FhNjg2j3QIcHQWgz+ISdBamn8+H5fzE/Pqocb9ufL75oXgdn7BnG9DP4yeBi1u6cP/OUJwASBKawRODrK5+pjMjIDojKae5px+MAsPfx6DWSMcVJzTt4u2LwJELjHG86p7RsTswfuObHodP0PnnEZg61AaaP8Qom4cBTfctKDoJiE73eiMANItRYOqWUUCzGHUMqrHrfZK604CLLH5ESXTeGM+VnjOwMqDhxwjbJEhy7keOxtoN/MfGDQ4QcgBQLWgZGjPxC5qWHXA2nqIKTdE5FnSMKBb0sxZUH1xenkUn/vkkLgedsaCbEVXDmScBpv3mhvvG/529jx8sKLt8MfYsRlFbzWffzGQRuFWNCiMs0trgqUgUkFhnlLAr3w6OO9fTiWIUC+r7dgKU3c4CzSeMaGD6Lws6RrS4xBejT+Cy6MTn/RYGz2NB0T5784vOsaC0HW2DBdWOejW5bNdA9ppi6BM72rt4jGgs6KBzbnOLTk0py1GBJmOFp/3+2z6bgzpAZidbvumB+RSd9WNBi9EHdGaHDXAZdIrUZT4N2C41n5rS2s5itOgUDoMhpRQ56JzfDFFG/el26xWaIYsFZR4rU5RQdtcGNxfBgg7PQllyuvhlQTmj2AFoCmsrN37BdACajt5bi/bvmXyjb1i9fKE5vfwnk61HHP17kFrbWX9GRxqCfnPDy3jvztzsfVwL6g6Jh2VBGbSe7xb0id6T8Sjj4Geulqw+poq5XOPfdcd8Z26MvCuqBbX2saPspMccQABKF7+g+UQv/3yM+aw/FjQfhN86d7+jxEt+5+NnennsKEvWuZfDMVm7WdDA1DsTLWj2XqoFrRHFHwvqq6tgFMObhk7I++7l7NyBCb43dGzJuncDMizMk5MLNZ98LMdLcfXv51rQYhQLqr1M/44ZWbZTI1oLGiOqKbVP23p5Ln9gFL9aw0fNDQvOGoJa0kFO8RK/hGIrgAo0qXOMKJmxoFsvL73akLjs2RVxRmP3SJI2AxQqaZNFk63hXHZ0JupjslEja8p5QZiXAtmHMN+fju8eJ3Hd/YKbaPcq9BvDfmnYhehOt3g3wadc880N91jkhQ4/1+Lusmyxica4h3d7F3ZvIT67Rjh7yS14J6j33FFZuXQbxegoziq4owFFOKPkroSUaEGOPkEntwxUz8zZ7MWNzbJTIxvIOHx0dbqbnHEPxoAizvcD/OgNLuNM9opijlI/jxKcs9Vd3IlGh/DcRvtMwo+d1Xmf2Fu+GE5OOy8uQDsAje9QVIDSaGBTgPa9+NhOlGZbOI2uJqNGVB21z2QBYba448aI15G9V5fGO3NPnVDoNnjML5jkZ0vTHHZLDkKcjJr+XSR1HlRsDYAGnSh4MDpYFT9BTZrEFiiA8EniImTjInTi+I46yVnEFmdfgMheQvaxOQJBQ9ItEfidoggYAqMPR/t7iiBQLUrD1WWR+nHRqnudzHSXe3ksl+4j9Nltab5XNF81yLto7hvCk6Nuj2gMV4DPsHz7kpku28iyGCEhYKrZqzsqS0VQXyTJfCc30zYut0RsJ6vtJA84KyFqsmHibBgnDe2O9d2oyGcS42w/mzDf4GQaEVS55RCoYr6NT4lk1o23lDu9s+GSAI/R8J2dxILbVWttQWcxOgBt//5wkyRMETJQVcM202p+WiQVZJjYQC9hP2OLnr2tyqwjV1nahfsrNCbUp1GSmqQZaKpPaxqM6gugwChQoWSL7yFUHmxBFClsbI3CJQSKW5ehifdgtAJJvejw1eiiScB8tBAvReVodoIy5gigG5y2V6pBJ4D0wGpxk0R1mEv5DaDVVGoVdcQYVSkYpi8AVR1O2zE0F6D9IoxhrbEOs0x7+y6aSAWvjOSyF4jW3IuDEUL1W4Aqp4radGdqpuIZlDQL+/l6V+SNEZoUf2I00NR3ekUnOg3QPI/ozK5aIHha0c68AG1g0KnMAWitpoiMa4B2qhHdAOotlaODdPGaTo/p32kOz3wPCXQWpjSAwgcJAWi1jS9Ag05sPOEBqAEMtacD0EBWy7ywq6ICX6EZ21mYBqPkKh4CkYFJoLJUXY23/xUfBcyClAgjDVyK0dx9eNFVPK0YhReF8dN6XwFKYSWYUiPIRFqcwfvhI4bYPhqdARFFozgdgbngkkyFU38u32hKlemiQTSiXGjc187W52AGqQugGFHfnYztyYc9HKxlNtqhAeMxyqxmla5SKnveREqVKDqdPEX4hKTQ5K4oAA1ZMBpQbujcACpMhSxiB6YLl7WmkPEUVvPptpAiVYD6CPYBoBs6Vxcf8+kb9hhOaqcFrR3NyJMSPSiXflj1BKleczZQAbqaX4VHjTFyuWkUoMsJ0AGigQ2dZFktYoDJBnW4nACNK1KFpsAVAhzRMdL4y6Fc/ZmzxNsU81c6K6HwvpUoQJmOIyPiodrYUbw2IPTDmpvrLxbUckiS05SbBk9k8nYA+jDNhDXEiFo7J34pgsl2vm16yugrE+N+AJA9j8ZdPvkgZrbFzpAzu7QzbU536zeF/BghX9Pie0UGmPI8f7BvPDteueuc25HxUO+ZPeh4esQ+SuxUw8jJEjWzNl7wGY+gNWk9KcVnlTzJ5FkR86DcrXM/VH+hDZwxwGRmVdOh/SEhG9PpM7vp/ZxffXSaDAfxusNzx0j2jrxwC0+ADvuDzzXyEQX8K1vXZhjNHrbsgMS9Uwbp9OnskkoL+a4rX//4DaBB52A0rUrNvPa5809l86AoQ880BB2hY1C2MstIlJ1X2CAto+zj8deJMaj6p2CbgBsgAyl1tYubNxHm5t34uE4z+akw50FtXQGqHRWWg5KcBJoAxpN4mgXoghtbIq0Ro5rmsB4Oe/iMhBdtIMPlQWZ820vobQ23O70/s/dOjmnKSECERVaU0rfA3C9jMX08kj7TLyiA0WCzvTzZnvn4ru+w9sVi2+x8ZfJen+/EfR4+ng8fnwcCfF2QzwnyFMhvDD+d+b7bfEGLD735pSIdAfaNz8NT1ot8c/9OsJodEpm8d7Yme4HQc3C/pS2lzjbmqmQqzBolHmD69JJlSixrYire+U7v2Xl2unpzHxJ+sLBqHS6OyuQAPn3N+17H59YNuC0Mvs6JND+FyCTF6cRjdz7ucf14zx718w2a3uoJEsYnOgMFCebkN4CCTC1ZTAu9VGpDhbD96TW8hVcqnsIzPFmPti7PfhyLjwPwIfSPJxTLh/GOv5650HnawASgm6IxDci+YnxfbH3CkUZxzvrjicCVjRfZ1MntF3FW8JAKHlhnNgBVsQVlsBIVqyqHHqJFrxDOmdCUcH5i9GwUmo4q9+EreYNOb0R5F3pDp31EjgeAyiquKZZBz5KTKchUH8FnHCdGnWYSnRhRLgAzxOGpKXosX9POZgHnCzPYAeil0MRCvj8f2Onvev8+O3Om+UDR8gUoX9t4euerBm6Tl72P3V12oTMAve8F4jbMGYTGTw3X5cgKulmm9Mz8KtbTZ0VH55KYwKJ31nzSidsUPJrZMJrRrlOXbAl8TLP5dSG2zBxosmUhSH3my8750hwwxbr38wl8dQ8j6icZzvlOEhYUXM52nALUaYrYLN+hZ16c8lmWN+OLoDMNQHs6CNIPQKkjj+1+Byjo5PsAAFSMev0DUDWskoNC9kITjjzsCzpBqt8LKjRBpx/GA6BAE4zyFaUBKOjcs0VoO/fCVAWBA9FZDW9tLk59+LsigpoH6JgiwgRolwYwrRHDyfBKgIrusJ1Ws6TT+1MsaMpqifqUYSPr9/BSCPMNnQnkGZJToWCG9iWfMpBPgMaIakeF5oUOL0a0AD0CUxzTk3xUKuYTn+ej+cZw7Ki2069piVG+uTFfNWDLZr5r0/074zPrjdnDfLr7HKYF2SOrdVzoJJL1ndsqEJ6tr2dFPM9kb28B2rsievbWdzDqUFd04vM5o3egqfNbLsGo6BSgmM/z8b1GtABlxBEjigWNERWmztj6QDUf/fA7SQCUZwQi1e0UFMHuVItS82l3Jy7jHIlq0YtO+/pMggKIGNErCgedTIj6EWaufM1n7ehmPjWWBah21Ad/4JJUAaodDTRrR6mm/QO+VyPA2TAaHKxeXoTwH6DEjIrRFSGCx3oKneVgl/VV9CGs8ZE86OSblhkZ2GpUauh5pv1sj2YJ5dDAwxjUUiY1JW6ToNpRAarZ0Zy2MEjlpvlEZQwdC1C0YP9+cURJv5P+/fPz8Ern/gQ098/ClC4+X8MOTP3QG44vFbFyyS+m5KsGTwFoP8rA/p1svG8XD0DdqQYhvD6XEX2sEgBt/47Pw37693ngzjnznd6k6xh3bocY3QDKkuSjTwM0LXF8QgHFxe2FZnt5n5g5HuYDNAB0nw95vYNRoMljCh7uCtBOUww0i9ENnUEqDWYDCEkbOIeDzfTsDrhBp2ObbZWKH/LS0R0JUwA66Ew3heFki9P6C5dgMQ9VYjs1sRlrtX/Xjh5YKek2m3eAZuA06rmbz7Y2TR6k1Ytf1ASgwme1RaqUMaib/vLJZQcFzKiwL6AtINmDWSH19P66hlyLDwToJ5hdRtSGX38oKk6NFaDe3aItLI2Xda9yauIsDM983zEOTvR9XrlH0L1fjh+Xw+fl8HI5uPKCpzHs/O4zGT5qLSLnK+3rO5l8TYtlxPNFGD/+CZC797FWNWNQAYoRZQZeaxNJ9evQF0M1unhXH7Oy0y4+q0Do/J54SuRsvOj0CuN+SPlXz/7x7ii+B+MMOncwO3bUxouNwRxrPq+MQd8BaCwo6LSjx44e+RCkH/L6IMCtSwCqEdV86tvRM+ES8xmYYjB5zNSZDbt2FM+BWeAINAWoVw4TJ1yfrqQy4Dfm+AqQ/u3jhUUhH++vR77f+PFy8NFRn7m/Xrcv4H7kO7j5kFdo+MZjbKfoJIDoN7a0ZXPQC9O27dz1Uar65FDRObbxJ9hKKjAziUqkBZRf+ocxKKMdP9eZVxM6xOZuBZh6Fy9nGs6Ax4maNCTP4UhojT4jRAqYjEVn7+WXBQ1AGYGAj47fmTGyU8Dn0TBriFw5UXTyxbiPC88DD3x/7hn/s9AUpi9+bz3o7Eew8xXXfImQqR1e+6Av1t8AyrdDBqB08T5D9CZJRVR1Vc/UU4Bmbbw+a+c2gDJA81lR0FmAcpnVcNq5YyMXRvkwFrsxg87CFOuiu2WU5kqnK+j0PonJjIMfHzuyx7jfIssjXtDZD3kdWLWiEeUuOWsGXZVBQGhSnNXgkTQTQ9QC02JdHg9NgFYAn6eDmwX1o51+XsWlqXyG8fYOEF9zfQtTviXnApHPl/359fDBpypf9Lk95dPcn4b92NznK98iz+0RY1MCbIDKmzhO7AlTcOkaFY3OHJqwHkvDoqfQBLGah81QxFbUxIbCF2S+fEwWYKbKPrYIi8GiBZwY4vlbvG5+iw9nUzlyIetrOJcRnS5+AOokCLeaGFMAmsdiApRVIDzq/Xm3oJ9+LyPoxHfxBdC8W9C7EUXDfomQD7n6rbf1Na07QLMzdyyoY1D7eu/i06jI6/Wr7qZKjkFrQV+ZbLoDVAvqoC8dzL8saGo+GPVOregEptjRGYY6VtOCnq/6T0c/+gUu6ccL00IzMI3h3Hp5uhZHnx2JBpqOVwpQhG//rgVd5hPdzxwTl5DLjGNBXY5qAFwC0MA0nwrla6mvOj4Y2u8dngPH91c/I2tH73e551OIHwFob5JEJxh1y/qru9n72lgsKDcZgU91AgbV7B1JantASKTxIVjmIlGkmzboDEyhy3UoQIGpZHIeFqRiQduEj60JWW83wpZGbkNbmNYlc8AC4m5BOYGxtifd0AbQTJDaxYtR+3fWJDGK1HYWo9O5x4Ke7eI3I9ovDceCfj8wwqoFpX/nK6D/2cUDULWkrNVN0Jna0RNiQV9YIa//3xbUYagLeO4WdPVhqAk7qgVd/btGNEM0YhyoIdMBo3V8Ph2dwwo6N4BqRONcHmPnvixoAAoIGNxGm9hOAZpd861C7OgyoHaU/z0GdRUlFjQAtaPfLGiM6LuLlQrEzYLyGVlhCkbBruh0GMDkVDr33suni8+rjcI0trN2FGWgXzz/442GczrQIoMhjZoWw6TBXPCX9w7nY7KYBq9Gn1fZCUK2wTz5Tn8fX5P/3poanaTJGT0pQNs9TZ+n4GoSx92F/R5P/ZmUY/CVhyBZTMZahCxfd40C88NMtzAr/nS8vGIMGczxHc8jC4cO24cv8+1Lkt649Xzx7vPNz1/zifYTE+wm+h0tvvWWzxdN6W7heWNnbm56mMp3nTOi3hWD2DlPBbCavvXGe0Wuf8ZwZdayfbJrPrIqInfRzHe6rj4fEMdqgsv6/1zYI3sNbbBqRTKXpMo58bFG3nviO6O+5sOu0bzMFxdocpMXjM5NUjGKj8VvUUBz0Fm1wjHolPUcXPq0dm1ne/k0gbdKKNyX31z/UbUz/v11vPCVevy3E/dozNVzNTgE/jjt35gvY0bCVxK8kow/YfNxxC/H12r8iAL9+wZQB6Dp4mMHq2lxMkqfCDGjUpJw788SK7UjQb+VwhpBNycOOQ+9XHODb+uFKvQyOf21H4DG6qw2za/pad1cB5M0qtOa4hxnpjP3kZ02Hjsd3zWQXQPky1sMRE/MIj/tT8+6gx+E5gvZ+wPm+3W/x38xwA3o2+a++XH2t35dmE+48p1MvkTI+8h8RMvl+3EEsm98H+7eAYpkqwZVH/PZt76QyTiNl0OyrPOpvmuU+pydS00b2ft0hOS7wDPuxFKCzr/8rEC0IvdUF98+6Q4v52j3H5/7j/oCY27bB5fLiAJNLk+2ifYhWjn4XnCu+9rO9vICNOj011KnYC2TlQsI1HaGiT7MZObr6utJ+8tP3qVjDRWrhlyuoCFxZOJHkvZ8x0MLmgqy9JOAU2YmuULfDy3w/pbOQEefd4BWuZg6BIgQUYonHAVYUipbhDQ64LNv8BmDAGV0AmL89B42AvwwRvxKDECfFkAp6LE4Da3NnPKqi4SLwsyD0DDcXTB7lwk84LF/o58McFnz5RCDlx59AhdoFqBg9IXb3gzmnvfH4FKAilFGUAL0VzEagL7zfXYwGoDmO5m7VwYFBSg+jtFSXnlwxmd18dQaySt8mpTHPxtAvXtEVoa+A1BW0OWhs0aUZ5gBqMNNAu3TgSmnWDB0sTBadcenBzwUWHbQLE0uOgNQe/Ng9BGdwI0qFJoD0AXN3wBqY/L3MApdAKVhFkBjPsQljVKYMr8FNIvRX359DiAugHr5CdD64HIwah0HnQn4FS+NaO6WOvrURwegjqI96lfDCpTIRDeoCZMMerEJuRkHoKyCyFJWEOOyAZ/6dkWHdBAX/bvT/zwA1AICU3jkGEEsOiNgAgGoltIC8bcZZh9Wp+IqToBmFai+92xeCVmJHAu6MLoAugtAY0H9fnfsqOaTz7LH8QXsfsUVny8R5uO1ohM7ijZdSKJRDEARVOGrm1ZD6bGgfWMYvwD1tQ1gumfR8wJoDAlPMoPIVib37AEoN4fqZDAaJVaVmwW1k2L5ItPQYz4/7UVn3JkAPe0sodoAyjIEDYmGs+jEZxTlyIyGBRCYz84xgVPi08I2Hg2BL1YSCDoDUK9YLejPnRjlbeQsHMKIgsVW6itAM0rTguYF5sKUcScZa0GZb8rcTCZeq1GlyL8a4VDD/TF2aEZCCBFV+FgXxXd5MospZoaMURPz13QjnyAkXIPmxf70P7t08WW6+SkGwhrRMB0xCk0RbpncpqNQLShXABp0GO/FGYCOD4zAxOmZpznTy9vqrNR43h0ou108gRef0oFOpureCLzq/qcYpTd8AKgWtOikS6CLB5qYTwcZkb/mUx/51QqxvkzAVgvt5bmpcPrVF4x88c3Vx1m5w4B6LCgYnastN0Y7BdaCelj1v3x+1CMaRwmMBFUFZiBdvF+AsaPPy6cufGTmIN+Xt19jiKvvFuf6YNRRZMaSjCgRhsZ0qGRhKnUsaGLSyChfORRoAJr7GG+0vZV5zyvyNaIFqF08lx/zYunc+xgsM2VaUI2oMNWCro4+Y1AeS934OhmLmH0Iom+J/GudvELuGiYu4lRJ0U2SFTX1kDRELNFCUc7fAlMr56oOLmNmsZlug6T1Lj0WlK7VjCm4vuceYr5kUcdEZmVA5g3hhB0F9cxu+2QjV7KkACajbWdCwBAjeB4U+6zY7WRA4UELqvMGzXElPgD1+SgTIKDT6eRX4fvyjdkhv5TEp4Vf+AI2m9mzcwf3IX7oLW8puweOa4BducVVokkZn7pWW4i0AMrL7AqDJuziB6CulPMiAxOMg2wh0AlGfc6epynOd3pXFHXAXaU8YBSVMtTJKOqWLv6WMahfbEMPziUVlMXlHaA3X4RifRXWtOjEZ9AVgGbyJYh0AOrVZlNasMW3Ddv0OaMlGIYih7M2jhrZwwH30w+m8sDbR6gDUCroF7qs5gAU4Dqbiws6iYfAGa3rH9mZ4sU3Ibx6sKMCVAkUIFLcNZyE0XhhI4JLa+Aue67GbA7ESJSquUSHR4XYd9iXMn5yLICWff1hNeqwDON7ufgzTimFpprBeGjI1KMYscfKHaEq55EHd2sC1JUhwvTwcitAgWDQGYzmU8mz1CYAFZrfdmztAUD9/LXfZ883hsPT72QSCDTja8ORE7H9iR/12Y4LoO5Xw7ZKoPmp72RqQcWWzxQcg9JyYrTt53olZ5ECUxpJ7Ns0VdAdo+oBJl6lvveB4aRzx4IGoGgA+e+G8w5QIzWfpP7vALVf9xjdRvt4aY3tgqGG3pXqsBlOXgrQm728N0l2cJpPLWiq85aLcACaVzcFaBa+AFy4fWM/n90Vk1B/ZreRkjRrrxbuRzQ8p+jdNOkio4AZjY3q+BGdWlCXEUDKM0+Xxon/RbOV8ABQ+EA+hyGJc/hran+JRkH1A80aUS+wXuP6eUIORpnTAKAYLW2nRpStInZHLWgwusynMOWxaCyoRpTncK+7HwPQ3cuh6IzPx+jCU7YDUB+Lu7QQY27HQ/lKm7rHynAyXXz2AmEpggDNO5k8YfUhmyvKXJ8LB9GZpopFodmclqf9BOjoGu6qgqN2lEvDcZVWhregkSQA9Xu5TDvZoQ9A+eST90ZMiBWazLNkHaytRV629dBfXTxa9mLb0JmLf5OgAowkCFbzaRf/aEELUC1o3oDTUlpBAdp5XIGrC1gdW3zLgqRu6fMSdeG3c3d2a+otAqqB9uzRTdRjqEcooKMS0lZUfQEaRxdPAut88pS6V0HIzIrz4EPnYCOtmXPjKSGpQxKWq1iyCk59Xe7iQaOBAFQmQkOAClPe1uAJBQBdvbwYtXMvRseCgk6NKBPw9u/p4n1sjnOaibt4+nfMJ8OBfKJ9AdRuCI1rRNPRC9BY0BrR6K7qohO91SpgEnj4MgDlRt6v27k0GSNqFx8Dk17eHjDQ1KYSdr7zQcsWlQOMCi9XxVjjAShrlvnUd7AoRoFmcWlg4dUxqOZzG4M6GpJJhaG8AFR9xvmU0z9Vnz9bgIAtNuYTmA5Ab+niB6D2DLGgC6AdvSzbCUB5+gs0wSKK5gIWoIyofHR6FaCINWPQAYUCcLRwQ+i5qp6fkTCdjumS1iE11RwLSkLMJ8P0jiDIN2TlfvqTR8E9ogaDFCT7aY5lg4jP2JxhJ83RY54bqUryONvKa4/Marm4nFcmXWKOO32eH/c8eDkzALz5LP7ME/n966dTR6888DyfX84sC+J5EgSnb+fTq+74jZX3F8ec9qE3VgsxdHNywMIZ3bMZlIuFWNywTTNhRFsNGngCTjOxaxK7fLHCDkPnW8LI5Y4g9sp20L5OxJJ4imZ9JyvoskbJ9R95kslNPEN7XoLVz5CmFye28/g3dtNyLE0m1P9wvBzYQ4UPObHqv44toFxLe8yK2vj2774I686IX+7inc1ZE84xoQEoHhClafRtoV6MqSvvurqhTV56dUH/z/P+F+4T380uPs+HT8Q689Br/37AsQeOjzp5bfbpfPiDi+mTGwNvR0CngQMAZZbwgP/sUMqSi1Fb2opGtfFETFHCaa9iJk6jjfQBkg+YBBZHWjP3ETCCM00JAQiVreR1nGJBWem/HVBIlKOUDYe9SWC06GSkg8P0y35URrs4LZ1VEOvxHu9x8DLE2SnHn3ml3BsT1ojwDEeYvrov3K4YfXHRGui8vOQ5z+vnEYB++zz9wTsirFIPOnk39s/b8R9fmePAZ0GDPbQY5W30VtGrZWFUxVklp5nYIVGMXgWob7JnLxBed3ClFy8S+V4RwrLoOKuPweUpa5RYBcLeJkzVOZM8LsYy1g5di87BaIaAvrfMWgMy8GTJ1abcAQSjbg/Bm89265mf575VdLJOMKDnyZhI5bmf6LStHa48HFQ4BdCD+FIIdjVdhT5PkngdhjdtvCdC7F/n3c/PHf7b555ljWd9AyjqDYDmBeUsJfNRGY6nekKTHkqAOjdSdNKzTRc/FpS6gh68oNSA6lXJgaawXOgSndCZvsV6ZlNm2zJak1NqEYxyKwbPUOItLjT/gwVNQXgcKV9gSlxFEEkEFtQXGPtUMzEBqInesJ727PVxPrFg6Vj/88TnFm11LlamdlwXsiyoEHSlSDEKQMWoi+7cjUQL+nlEvG88jHPDK5BkxdgL9s/97efe77PHgvo2khh9eOWDdi0uFV2dZKI++3cyiToWNDvVjAXNK2/UCovPM9BAE5j6FsdYUB76sEGettN+nACdBfSaXoczKqkYZfdIbGcdAF0WNDB9sKCa0qAzGBX3MaK9ALqaqc88aHkgOjOhYw5qGgYhtgnKF52fKMkHnu8YTtCpj7sOOs8HLSh3cIzoD/vv+DTHK+t1BqNF58BUgNK/M+7ibkEczTAUaYSE9S1E1LMa5oggXlhxRix0BqnJZFqMXN7V9y6XugFQp301L1YqbmqHBX0AKEW0oPCCfU7jpZXT7Ws7edMwpdAV1XwKfgAadLr91EIn2yO4LdPp+ecnG8QIUCfH80X4T33RSRcfny4+S9NRnJs5AU0ASv9OL390T1uuCTtit6azMtfClJWuQWdeoRCKuZjUlSerPpmoz/6d7JA4FrT71fAWBsaznNPF815RodmeXYyyuPnEfg9Fj8/qvS12IEUvbxe/qQmMOmPFumd3R8Np+7Wg8d0y4t6/aztFZ2Aawxz0y/w+UX+3oMLUlrS7ZZhpP1ZEtKIYzsEoRpTxLwD9eQajuzf7d7v4wpR51z95kBWM8kqr6HyllzcwnXuNKAANOl8cg7ra13a+TzNR46BjELIwiixzvSwCMVqiwA48atns4rU4TJHbSBmtyR+e/A1ltXr6gZJ73FszIA7kgtR1KYRA1WCkZYOOUFVMKY8JKZuFaw7M9B2D4sfxPVC38LwcfXqQpzcvF/abxR3Y3dNHQ/rc/tgvsvL/x+WKz06wbgbLMEAmvpZKEb7BTfswaGf+4HL7zru9uX8Hc97Fp7qQBabqaDDKmPxwc+9jGV5/7HbsQcc7Ur7N1zeFrYRvDBPDW2/z1iijXV4fRYvM36JS+lBnwvsKeQJkyd1JRgiMEoD6/if3KXS4qCU8MRG44ErNZdzsUwYC6WZNZTwdUOpzq7YGoBomWAlMbiByh2DbCQ1/VbhDrFwjlOhOi37Dl2q8n2+/LjckwX+jpoxN2XHtcvjOJpUMqNjmnAUNtoi7/vrpXu4HTn6lnCfP4xyDzhzTzINS1B2gyhEp+C0somoB6pRsYSM0tRTGrijrpEHQ0zKkfmjD/l2AtmbmNx/HiRe7/OVI68oKHklTPU3iXGUlCeYqtLLkRsFl6G7kwi01LznkSZsrstn9uAvLT0wwZSPFp+vp6XZyEvSqc4USd+Y8I9LnLt0lyGwilNcQWLnkS2cuwA0f7RY7gQN76pEK1v+WJ0mgkwchj8/ilXirFV08M6jZ8tiJehcm+LiN5Sf009lMabZa4I3hyjzr4Sm6C31YoLQeYM6TzMzGz4ySd0Xp2R2k3n5x1dBI0bGdY557CUqx+IjRdAq0DdedKiVv/a2LR+c94BGgwjNNnrYQCuTIleskAlrBx4bzcPLn9cJe6jjC2GRel+H+jodmjilV9fhPRjrlh+/9u0md0utNEr38jRdJYkHnRj4VG3wEJ147AVN8UuqsP1ABMwO7tIdpgaYQDRzpL3wWy6svrN02czA68BSgTnJ7FJoJ6YWsbRygwnkwCttcA14sAWh6uuzl4ipsMbqgmca+nN54dfIkRjFGLDwedILRo9CMyphA+p4tQLNM/hcY3dBJwHt07rJpUO48uOoeDswSN/LfeHhF2wABVIKc+ktrItVpJm5IQScw9XPz7t/JGmoByiZK2041vMkuNFNi3ytyVbyr0lxBd18FkseYRSeYzj07/QFDTwYh4qYYRcsAFFAyFOUdDdIKVm/vOHXjM40HprTQFG6sIGSaCZjnQfwdoNpRa2SnhQK4AGiwNHdzF5p0NAD0/epO/0EnL8LSlbrBIRAkIDSdsdMoPCeS5rCX5+lJ0Zl9d19ZJpY5pk42OQDlSlujGQum6Px7xahhzqJwRRrRAs3IKaUZ4gvQYEgckUxr5FGnb5KXoOAL/e7EnqYNWYr0d1Yxm0kUi0lCBsJe6HIHoJkBBaaMydgfa9AJTIWm1oghu3t8gks/myFMBehLrloWIYPLWtDvaicvcVzPCbzXdgrTcMvIz2UvjCAsejman2kIzOf3TtSjFdVlAyv6qI/mufWrBjSYTzAcudJ9M4EqQLe9QCjuHfdgR3lzo0aU9Z3bKhCeEo3LfKfQdNzJvFLGhpQbjCKkN+r07AQK03b3RaqLMOj3F0CFJmZwu4vXYqDrHHOTZCtYJ5sDjHurTxvH4fmFbauzE6BsFHG9cM1zQbr9ZrDIkn1AaWeFUcBechrbqRHVbeaTjr43SU6CMgy1c+e6CUyDtEI04mwABTpYdCWLi5yV1tggyLh28ULUNkzP4AvZmE+MaIBf4jDHgtL8qbUWx6M+nCTIJdvIXK8RRq5iVO1hf2AqQLWgsHIljb18bCc3IC/H2YRWaLqt7b8t6OriXxdAeUuIJfOFZjt6Z5NU8lhQr0Atn86Gj+LwuVy8qJQ6FrT1idAAtF28FjT3VXTxTO/jMxYtQPGxoJRVmFIRLDcWtA6A+gyTuZqYTx5j6m5szMJ8rtDsXRFCRcFK+IbeuclHwrgOswiDS6GZxTTd28/1qHbFXPn4a80id0XUA9p1UCFbPwANLgWoTRHDCUA3C8pGF99E54MFZRKrFlQgfrWg6ehrQQvTuwXdAOp9knYUCfxTFPxHKxDhMgANWLQS6h6yB4B6buPx50FlNJ95c9DN7uQZZ8DjxFvbDemvZjWxBCjD+JxoPom2ASxFY5GtYbxuA1BYca94+dzzDrjvg7OCHscbRfgUpM+Uu7e4FzZX5t4c35skl9vzMMf40rOf9lM3Xpz3yrlHdbkSN87e5G63XwboRm0gL3HlUlrE/d2CJku/thF70PsdehX7gHlNm9Fst6lxtwXln1c1tnc2smQu6ztnFQiF5rEQ05yd7ORufbp1XzEVdQ/qtV+mkaPGtGy1GrlpLjv2YvRhDEplPNY0k4qv9tMocMOO0vXyVnZuj3jokAA1vSxHGA2zXBm9GYi2XZt99D0ApmVtDp2jEcW2N+/1o3XHUj9MMyl+1KzskT/XPyemBJ1GJ0WAErK+c00lQVxyIQla6H1JwdVeoBM/fFLJQJXT3wEaxQ0ZzGXPEYBGEovUcZgMNOtykwQ045iRA4i8SHS4sAkLmAtA2XlJdBJfjQjQpS8BKl6hv/BsJ1nOvLOQXQ/YMeYAdOjGmX1kjolcbHYxUwTeeWSosQE0nbu2R5Ut9fGs/f5FGKJd7m+h+L8B1AsjFxjvs/vG8CkvZPrgIYNRF4YxM+eUb1eB5ElmppMC0wwrYzIdZdpQG0aVhREkEhNABv5UcFvRRnNkqhHtRL1VYHpw2U9/q3p4GoC56BSjOB8jiU4Byj37aQGUPU6XnjHyTOYOQAvTJKH2w/FVgNqVB6CafAx8hh8YIm+SSMr1NehL8yPJpmECVndzpnhiZVeswYCHwYlVEKBwZvalXTwAJbqevxw86Qlsk3XQ2TD5h6ba1K82RSdSW5LopHNPgN1lAegH6MxM4JN7gQE1bWGd6IwDYTWfDwB1q+xCk01ryYjd/WuMKOBgySK2E86uqEChC51shJRhWHzkUfQ7QAuE1Mr5/UxX+ckiGj7odK6IlZLZ6MLZKuZSe0l4gTn9f7ed671hjKh2FIXmkbpP0n3U3keaznd6wdC63AZl+BElL4yqwLQKqOJoe0ZkLYzjJaDGNBOIc6myLR4XI6odpaFVfhsZBkJTgBIYaPLA06vOJ8yBJuh04oOdX2ILCNBTYTidfWX1q69Rjb1w21Qt6Dbt4IPC7HHrNZV4fOUuhBY4ovNUzGvujlHpcvmlgsml4ObnGgy6tKPmdGcAHIEhC1WJsWcZgzpyk9YDP+APNyOkl9MAIDq6A5T+PTDVfAadzIO+jBUc8xmkTv8ORrv7sqpp/z5aU3HgUpiOHeUrHgAl4Ij5/NgzDb26eD+QBexym8b1wjt6GFFUki4eaW3hyK30IiZTs+bSqm1GFIAKTRxdPNfAdO5sqHTKbgs+aRikajvrnLt22UfcM2/K+cC9s/EBaG7Sx4KqwdrRTaLciX8FqP27d/GORNvFz6L6hU7qw6BBa6bq7S+yADYY3QDKJChIDSjt4oNRPtFUQ8A7jgToN3zZMXhtjA3hAIAPTxajGtHMM4wRfQToYGes1yADUVI3TuPEX1AjjsQsx0ojp8NPR4re5GmVvwI0F6AJ4cAz4ljQMmmDGvZqkGTFG7AwoaujDAvuNJP3SbYxKyGxRqwu4LX8vJlf320Ps/Mh+yUedDxc4Sk6d634vnDq48I0y8FtpULMKgYtU3bb4j6aFSjsAOV6DmKcy9E+5eGS2ZEDo0WrK7JWR8n1iwgjbVnuRpPL1V2MDrnnwgfEASjopApsaqXzsZRme+0FksDsC2Jn5PtutaAdg/KUyYfsxzxusg9HQi8JG2NdJpRTVVfxKlIxF0zTv2d8b4edtjONajwctILdItVyzGrz9A6JfER4h8SF6uwElo8t0XRu7W1NVXUUTt0JYKnRSePbFmoDZVK2geniKQRWAtf4mFKE9oghT0BtKxMmAdmoVJ3ChSyw4YyToCrovI9ByeZmdxrRWNBge1jAl76pI9OUknIIBYkpabymphDtJ0x6zAB0LKhtzKoMXTq+8YGaDmhuXaHTfc4Pp3ey8gmgOPapDLHvKhP4JVZq/72LZyNS5oXI5RCDcVcCXiVaUP1InjanKqnFqK/0K1fUncblwqj5rO8F4DUQfbU3v+Nyi9xsZ9Z3IrAPMFkI0ieZGk7v02lORABGhVQE2TCapoqmbU+OQIwLyJYEJ6LXnhB02heMgza6V/3my4mkwSWZYzdyW8Ou/HFelg4BUDi2wKmspXPnRIhP0jREUtMcYjHqjW8DacC9KESdgut5CEMOKlT4JTkUJlbKO54iq1ceog6PjJcyDL138ZKF7QNAW47xhrh2N5pFm99B5leA5m6JLpIWYWWwAA0i8Z8HncbM2jPX/0Uv0ZdXczRVX8MZ1wCRA4v0gHR/WlBwGWiqwYAbndrpRWnU3SYblaUyhENZesb+amfaybEe11WemIpOppY6LUe57keenWrmIkkXT1M9AHTHrD/Pt1lKx93bAFTzE4Di23A0bDBajQ9GkdVhlVpOk9tersJB0AKUM+867ugsOclxJJO1J7YW0OQS5YeLMKAUoDyd9R58gFg4puLtsga4YnS0wcaUNaILoGYPLpffSlBydMzZvwCq9q1MCRQxeRJrOBdXGok6c8R8egv/MAYtsamMnB5ukozpMVdDOKQ8UeuZyOx1asih3BqDkjbmk8DCmX39sqYuOQtMGbGplPhoTZVFL1zi7dnJMgEvL0DJXTxvL2tEmW8io+0Y1QtQAIcQRaqXVkCpr+6UW4DacjEJdvRmwT7Vr+2cLr7oBKl3w7l916EwZSWQU0uPzqVJsaBgdMwnVyFgs4uOFLGjo0xNIzpvw9oSG0AVigN9YN1tga8A1aCKSacC4ExyrZA8bBNigk4145dKxohSa2oqBONDY8VFZDv9aYs2BPEqh2sKdQlKWBF2pFg/6sSzNHx1m6iKqz+uFBo6iVasNWAoYmyqR4K38AxD48sXerzJ5YLZrEMPE4uKtuS3aEzZIolOgj8eWxeP/KJzw+gdlK7TqNu6eJTFPiEMBdPvqCzqj4JYc4YNGws6AfvZXF55GmIXz138dPGqD222c0cUwuJyYdRAYcBNkrouRn0FLM1g+9JariLQOQblYrOLH7OdjZMYcSKAjksFM4m9fLSgKDAWFE0uCypGuWDSoUQcNCik9Jb2eciaJojebQ1TAzv0C3Js2HT0Dxb06128TMMtjAVo1JiixdZjF190akEHmmrAFX7typa9EN9VDs2pU71ZxiFA61SoQguDHEvDrVzqMRTUHYj0JP6E5eC1ODzUrS+0zRhUymFuEesmiSD5OIgcETzfxLCtmx5ghgd9DKV0BMg1xktsrJ5yVxOHtt7hxnetrm816BybEsktcNGJ79W83g9Ba+QSoyDVJb3k3f80xmX6vKLKw3N70mULAZytAvgUIsIzaFNQfeRvldATLTHojI2hXgzobSF8n4FFQdwV2904wSkoHftS9O7TXb50zBO8plLIENlqR7WdkSoL57JGiZksm5ZwVFhTGIgipF21ehajCfRcldqeOOpk/w5pLC+n1EekmmwWveJytUYtnJco2lAGZzVWF29No2q1XafOi1GT0pvFTGo+dYxSlB+YWguTjBSjHhEgkvRcDROqukNQT3MRkaUlW84U2SGPCUaITjGqFZC1zOOSCbiopqpMJoSGW3+bUsVYBqFxYZXl+1TWFX7uZ+KDcW+3xRZzTPhFqrgUsoFpNeKjFvWVh0DUPOFYUDEqZegZz2FBHUT7EqB1ADdOtkR9+kWnV2SED0aLgirOKkT76joa1zhRHPAmkKHPGFGe2Wo+czUPTItX+yBQqPkcC6odTZ+QSjEx0PWdDkC5GGjajERVadW9fNtk3B2jqrSIU71BZNA5uKQ16ZDTSnPl2UblY4DsUWPKFWHUNGNQMCpMa0GxCyBe0BOoXVjQ1F4IQVwsZaoAyoNO1NRZ+qSmXItsIEpXw0InElmPlQadZ4IxaUkhRH1Ap1MoyhO7wHR9Rj6LJFz+bUHlTkG5ICxvxDGSIBHC0h8LaI18/Gi9ik5eJBWpAWLhGJ+YoDaYc8uGoNPLGr0UnbGm2k4o7TczFWCACvjCuhjNy1ZYUEGQDqg2w7Ebj4TQr4YG2ZA2ElZu/GTBqtGE6N0WUkGBqe94egHosGp5RFTzaZiiuULcg276hFRnLGhMqfGDTlcfQ+n7Uu0cKSF6siFwKm65/DqejB0dvUaz9jDaTxTC0fzBrwgoG0PS2vD8ElIh2rlg1PlLoRk7yjWpBRWdWMoYgug8prQNsVmKWkqLjnplaxePYm0j7/wUIEW2WIomgijlMnA/lNBGiIgKvJxSB51pJ2RWyaCzFjTcSywv1P3Al3jO8Dn0p/ZEqpmgtte3voUjfJbyYji1nUFnu3g7awxMrGZ6diEbmG5XbZpzu5q1oJquGN3p4jVadKD2szWf3CRNF4/W4gLuDZ2I3Frbro+6i9GN+dQqUDEvX+quWWoXnzGo5vPey+f+rNZ0/2y3HpdrJta0V1GEzMJ4YSo6a3jSOVqUqtzcJtZd1cGoykXICI3BImyfTsArEWgHqaamXVK9gWZLCIzQCWosquzfg1HAKhYzsmq3Hp2nCIHbm6RYUJUpB3xY9RqTWzt3YapAj+DgnBjl4tf/e0VtCiMQ00DUIKn9u3GhJcLFoMGonbnUJTYvh/BqCN8C1tHaD9stkqIsYjmqQAWDUQeg1sXtFOzoxc/4aqyr/A1Yd6929K7LuAqhEkiWIF4+DhuCIjcgzq4fvD3LSnoe55khh7PziupJlUAlIqSVaTsaKL3TMDrO0AVAij+Pap2RGBeDnUJduB87SxMjDA97fK+tncbWgYRAUQcJgj+ObhlRFQfHtdBRO1FWIM0Uoa0D4xSOeMLAJnWYgqrNZaVAVGua5m59rUkjG/DMA7X0/pUacUQhzGGpdiI41Ye5iTmJ7z2FN7qkxstYkaiUEOGIp/QRtcIqZDSMzEJvucSaVXGJnARPLLqtrzxuy+dCu7yWusiaG1pBYH4UYOEN6ksJVZkbjLoSEFhZqx+EBU8Li4NLgBvUfvWNDOwiHIbGq1TOlFXBAuUtL4HCwv7dNzyKTnDw+1F1xrchU+sEUiVbNznQtc5qqSCe0OqnLV3Penf3svwkghvniM7iLyJpZbK0KsObYBdzXGk1zTq6U55bMr8FMsQr4ZRfMSty5EK+KLsYRXxNZmSuzmNBbR8lj0u7qDVOrYzeXLSe5TosQDnd1NXqV9s81yIJSG2WAuGIGRe+oacMWXtEyJRpZCPu6GxC/QGxRYXM3wSbzVJIo/RUM+gEpj6PLJlArPPWeyxoGciwR2RdwRVpSz86MVRLGfBpOxujXmgetbP8OW0W1FGXSii/gRAvDtKznwCNTWIMZ2CqEYUw1G1wKhUNGJcLDf1QPcMBaCLv9OgdetFJ504LrdncMTnOnfmGca31Zj4FX2AapBaX7Spj5llsuRDMzbHGUjP5gMuJ0aY2KVVQ8Ji11KB2FKGRP/ai7Qe9NcqACkWRQ1+C1CTVlxtnmkAPfqgOFUTb+BNr0TmqMXjIYmL4KUN80y3DjJSeJGiJ0vOwrB4TiKpDEcFCYpKF5CjgGEQQxdtfc2HMqW3KWByajHInjzl9uc78w0URDKdU5eqBXA6HPNSM5pN2BVIUs/C3kFqMPuBSjMayCuXEL3RqaMMQ3wsav/AtT8MxTsA0q3QGpkQimgd5ciSvZwiIfupHo1ZGlzZS3baWZhsZxoLWcArWzdmt95KgpiCvjnLr0BhXNX6NqEJuwwCBOObT+GDUh9xerhWTkh+kRpTRbLVO42ncHHRGcppiWVD0LqJEoXVKbVbN+R2mCVFc0YkOq21SyWDZcIw26oPjxpMUZiiHXl4uhEiqAPh1FVbdKoTScCQxpIPORItNLjTrN3UhQFTaGm2b5KkWlFpDRL8Uyskia6AgqH8/poD8VHHm9CjfVFWA1nVIEVtgTCeqt1QCWd2h/xiZcBmq8yhYgi9kDuuZuNYa1U+9UJxHfpoRX0c18VY9Pa1b5NgQlR6fwN3dY0i8lwXIFIB9zhuoL+KWE0BKOARZJgekGpMreUsVar875hYzvUgrEIhoVoP/adRWh1NdflJVPDGSsEHScoiptNGjGiepP0vVcpDHKKGc9CUwMauKUbcyF4P6OZRExeZnEkNERBuAZILLn7qkdQqbXhheakz8pUxVOu31CFBvY8NGPwfnkZAfy/KYKCmtfDQlUcASP8QmpG/CZ4uqNGZTF2Uq76swIi66IECkBRmQ8xZvGKOBo2BflcugJYHWSQW3cg3AMALDLZqznoqc/7aDCRrQycgvrEwyb8JkUoT0E9SD0h/9nMJRgePSnZullBOwRolpdugN4Me1Xs3O0BUpY0gkIL/SxXbFckxdJDYlzvq0qpXbUw5UEcGjz9TBS01negL8QrLC1flWcauvUw+Y1xZC9rQ/klM+4Tmi2wiMTCZFNqVSepx1IkyKuppzonLaUqSUXJNKPBMX5jJbVJFcLGBr5pw11RiIUlKiI0xC1UAqn6pS2whhDGnNZZOaam8Ho9FRlUU8kYQNDDcLakwDCcvWaijtHZ1lLEbFVLVpw0gZvafCyE5NUrHWpb3Z0DQjvgeqKZ8NpjCvS7ktvb6YG9gtqNFgNiRYrC8oPU3Mooe4tYhMFsepPu1q09IwbQR+zKvGSKdSiGA1JpUWSBVISwZPkmxFzDa5wjzgM12ViciGU03LqXqnIUIQHcovpUNOYNqI2iFJ/QRlW0BEOIhTJSIrW+QKZSQ1twJueZdUrZkm2uKGQCY5LIIu3p+J4Ufc59So1Njf0OgRpXDmip9wxM1p20R5q2mN6NAbJ+b0IYg6BqxVjepIUslscptWR6uljTfoiE/1OL7cwiQlj/ipx6pqStyyWItwIDCRYRa2SmeNCzWvosjQGA2hGFK21milKqdJyWheND54FXamirwVSGPYr4tRnWoRrjrigxLVnRoQA2PFhm9EzYmnnhtllsq0KTnFWdMqnKvRAG6pi3CJW/t7PMof8yFbrySZG9mjGFIPUbaRpBoO/xUZAgolf+omXWoakSzUUy3o1DoESlV+nA5Ak3EVsKjCqyfhLzczW0loR5po1nCErh8hQnlXlrnMu2KkgU/88gxBRC/Ptnd92Dc3fouqTq1jQsoThqMcJEolLYOjaH6gnOwP8aAzrMRCyxrMLeSNJAGfqh88UIUFzQTImxi4qJINuGEamDajAy5Ibf1ozx//czSSCkGj1qfFptTW2jaAaasddPbMgr6osfUaVaeO5LNXUTeLeHgOv0hOeGBayogZfUZkMntIKhsus4hXpiM4CVZKGgkSfpDafOFtaikX/aiC2fUJpbB4RFhSfkYIGFu68TxV8Oad1OUIe6elrzFIapqoDRXf+Ac3p9xOwdfGSIBT63D303zxaoDKYgEmFbU1JntE5AQh6zeUKkg2jg4cypwicYDa08zuwm3xFzp3CSZEDHczJkVaA5NyD6wI1zPlrTfknsPs47gnIBxZMKOghc6mPnLTbJHe1msL2jRtzGnTnKwwjKreLZBStkilbcVLQPXp3MQp9eX+LhpIiyoQgXLzWXTCSYqeFcszpBktJ8aIxEZukxIhCf9xYWuY4ug5nIF2viLno8ycpvzh4MKO8hqGFCbPNKqsJxQaPbnVkZE7bsMpYgqORoicGlrPlG38BKzzw2ma6K4UHoQmNTRtVeiN8mJOZcysu2Ou2fWjnocapVpW6k6cVuEUKb9EPlRsrN6Aar1XqVrBW05Hoan8kM0LmKFJuPnuuaVTWeMUajm0t4UTaKNDuRCaFhGTwaUtkYDtM1qhbaIYW2I0VD2hjnAn8vdihqAa/SJEWeHH6MgzciuGQnlQrtGVzAD8V1IIJhNxpaQ6yZXipEwVbIjRCWYuBKUP468ADdtwSUgKz6ZUQylpNWVVo/lUk7rWR1PacG7kv+hrdPeAwtEaebnEo5fJm6aFvg2bCpm8Shp4cTocrKcyzoH026mW8gs9ZtKY+GUon6lDhKAnZ4X8Oqzh/awSLbWS9EDGCfJ/OR4yymc5CqwVI+J35FCHGXdamw2ladTiID7KkFJilVDtGYhRzOnddqJzKkWkBcdfWYzELSHmNHISr8Bt+Cp0CiXSy8ODGFQXnChh4oilHJKkk0FCUnFKUrQudYlUr6SJlyhhxqBAak43vp6nW1kxKaN5Uthwbxmbby+fevIBrAnc1VTIDsEjOlP5u3KTtPEZaxQdWY+t860Ejgar1owbzWbliUVz/lgT62IKWUrfLPibK1hzutn5MBqYkf23ozGWAefib0Nh0kpwz4X2QzBZSLA97BTiuFma/t2Roc3X9kl7TiXSJEOdBia+LWqjRPPmjEONcaJzS2pq8rTUlDQEVgQX/vg93Xw1mOyRRQ8R9fVGSMKPbqIjYajudYpI5gvALQvHIU8dgY0x+8eb+86tRSd9XR+mr7y5keuAMwAIYQioVe79GFfIc4UdZiy3Rf4W2OgJlHgIeFhDWTge3GyVB4yNZAk8pUQ9FWP8xBi/CUcQSp70VjAkbyDFGUnjt/152hX+LWJ8Sm+hak9VVBarzcHJEsm8I8QqPJxD41XTnCqz8cnu2UryslrhBvDrLAuB/fGQ0iWGidwqsgKPajTXQ30fw1VIY77EV8IKFqmtuIWT4KFs/mxewsG3kVs8uSZH40IfhXNOiSnHuoS/qXe6nPGos0Wtohc780ud1IKbCKWko8iTS8OyQ/FqkD8R4OofeLowaPzosQ/wZrVQpnaistCE4ZaF+OYlho65zz5peJ7ze3lHIldEwdZ1MJavFCupUsUWpIKkWXvpMZQ+b09Etr4xxsbLpUsR5C1nL4lk4TTgI951bBAMf3mn1hEACZTW7MZDQy2UKjRRUATo6YpULGiX6KGGZ2oCjRqVu0ysJfGEF0ahQ/joXOtcbVsdnhpaTZMSaJVHpXnav4UD3G0Jlz2IfKJ/q+m/BSNjaq0kClGIJN5appITUDylVFDyNaOihsxIQqmNBREwgnL9ldya9gghQbbrSEQLffRlk4JMj7Qtr+yoJI0BP6pkcv6qL1YVqwJxGd+5igb0J6ym4tRyd4ZNIPHNS7EwrwMclKBr30V8iqYIsWi1WjMEtaKcqonWJxWoMJbe77FNQNkoAtVYO5hz6u4FUy6nG0Yls3xdZWm5nJSM6sOtkj5QRn0htQESgMxY5ROOMvbUWJhYm5ylqPCTrJUxrdm55pETQOiiQ+KFppGjfAJxITDSvBJLuaDcyPjqcylEcfirenMNIxWl60E0f0Z4eF7SqUhrph7uggtGaBEgR9aOW69oNSxSyyggXAUoGulRPjZTVFRZmkhSRRINMLIaVpWGgdZ/WORqLkZJUlNezZIZ9tRA9UJ4c0Inak3gTm+r14KOcYoGUn3tXCxcFN22S5WXHiNnqoXcqRhZtJoxosSZMTIwSIMV9CEkPFeFRTjzw5Wg7dTJyYqWkgqnkaKBVLACRznWTo2EphRwWA1je0RlaFNmQxdqhM0pkaNYTjmsfCpidJTPGYBDPAc8zqSnRu0lHNBanAqP2kfbK2ZTvoFGernYoMSgJQIeq7lTqHIpXkVUFxHNn0iWOhFVI5rYoFPOaM0apSatlwXJMfUPs2G8aFQ0ALWS20GMpDmUbxJagPQK3FS4s+FooIOOQuyaKd4vz9pi2ZJa7eAz55VTjWuSkpo1Vp52NWBMb8lYe+WSpoyxQAZtsJVNuUAnSRLQ0ZNFc65lk6xV8Dqzhjm0ml4tlp4+JcMDymWhlQ0cWrVJWdw34kCqYTVUMSyU6tc0qtulHgrtSZRAcMh62zP0SmEtIG7DTH1CrvpIChyAi7wlN3rikwRjm0BdWTNqJDq9opwMUIfVeUY+0bkxrXUWBLtineokJuHoP5FqRuZVhWZFAXMY8CxCEfDXJIMc/kZiAnFSG1n1IypMPUscAfIOiMFomQte+S+SaThPT36ZUTK9L3703Dw2aVhIwK0w1QYQDDe9dtkXUZhaLO/2sPjdnRIfHN/ASmS+JPUQn+/yhTLvGrFDFNn9qIz0MOdTT36PI46XM2gAbnztfyPNXRfiICLZYK0FKkHgajQqb8Xyzikr4KB3p6q6795e0+ocUoFLXkplgTJvr6zSlwwqsW79ojphlNJUozhHhpiQ3jLGvDnr45oyKOOclW/G+OY0Hg+zZ8qkSmV8nGV6wZMXIa2sulrUfOeSJdTKbwVRIBuqPrQCyp9GcXmWnKxIm8+rXTfASrub6lVAhSyeM4L6HqZBLIuKmh/pR9QKVVqySZRck0HrPnqAVbj6W1RaXvklF3WiGpNdYskrFYHUIsm5DFS/XYmXLHrEEqAjXZQFsRopRgvKgWZUEwWJvypu6UuUNFcDSYUsKPGrUoUpTYJkWgsC6mV0gURYDm4GNaXRGiIyCLMOVMR6xyGJ2zCzd46v9CG8l0FsD0Asz2KUBubVUSK3ot2WuO/qwcmCc7mLpigyfgqcU6bWUBGp+Oqql7Eqmvi0DQQ2kkoOhxXpaZOMpkY9wpu6WE174aidqkV1VhUNULV0LFQwX5VLW6Tig9Q0DRxoMpWZy6bQxCcyghSNEkSwwEb+xmxHChQmo2gSUuXhMNJKYHOhnYIPsshc/UCMZTEqJAaJkjpHeGtBvQo9pjUN2RD9y5n55AwF8sZ8qqNRU5UV+YK/WMFBanQkKJfza6aN7PWtWTVGdBKzLnQ+w7GZT+2ZhgHzySL3YhR5IpRicXnQZylMQKkqDCBrhJbUQE0IZbFBCcRsNkqhmsmAW5IoivYzsm5dJxpUZHhApwpCK6NLdWtLpuFrKYNOEKntHKfG1H5cGBiShSBMcHx1b8o4wlOpqaaVjSMvpLag0PTyQ0gWT28Kb4uk7mM+Ugu1U6kwnMSIWnlFPEvXylqoMli7oKM6JTJxCi69R0TNL0GzyINDwCRXWBlDanALj8xKNw6yaC+ZhiftYYgvG00EjHQc4aanghIBrE3VgDqQgjU6GjWlDWSmpkYLm4IaEIJbqmBdGmx8tgtRiT31bZ975x7rZRefeW7HEurOekabaBYBYkQTj4wkxt8qI/KsFogEnbQZXSFh4M63F8Ai6A+BFaeNNd7G13BukigVBUfj+kEjMStSmZJKUoylGFW8SBgtxXI4FlrIkwtOL8qOwvFyWjLTgxWLiu1E8/DkioWwdQxGC02gZu1U8uiZvr4f6anakWfQKSjteXSIZ0NT1l2rykGh8RXCsx6pfc6N5j9ViD/ZneAUxgJmcvETJiEniJmwAiWSpmUPVQvCP/FB8e1ECWBamnJrosVWS7l35oaU+ggab3IJ29dTGirIiNPPu/aLwW9+2/r6xuehb/iUdUjYD53+Mv7ya0+kp297vx9N6hvfKb9dvu0u+dTZ5ZWw7bF29NyzYTevM/BBDxzLHC4XPs/EnsJ+QoA19wia6zsjcSuTKiEs9JbF3rp7PjhIKZdve0q5vrJhiE+o6ghfnvd++zbfDecrLJcXPoRzQwz3QmDsx7Uwczv3O0C/k8lLvrDlW29KogNFftXAPXJn72Nvl+8L91VbsGEAobd7/HbrBQFMNAuxwl51NKpcEMK7oryBkn6fF8D4grEIsPXcMQxh/DKizn0yGL7S2RDvuCO3SZGE2y0akPZkfKSc0FN35h4d5VoUSINGrvcjABF3grceP0DRC9IGiEtU8JQGkUe5eC3m5SiqYwzXmkKlL2whXqwepp4AxxxtzcZ7SfhXT0qdKhpogs4BaGAqMOisi9F01nwiOOgEc/tf4HJ3wP+F7wd4iXwRl6r1CzpJDSIFxLfAVAyBLxUsRtnGGUTmne1smmGkIBAKziJ8QWfMgbXbm0WNe2EIUD62JDRxXAlwE3Zc0nvb9UmMxu0uL14n44AgHBQkjkbNhARDnmnafusNsJLktxkCx/u23AgZ1CqkhlUVVp02GarW1xOriF5fpdsy7TEAKMXrOxjVWPq6FD0Dlbxj1GsJkMV55WTbENDpVT2CJVB0wizyBJrsh07evVs+dM7DanoUYIipabS1jVpHqtQY65DeFULqIMaKzEUthjzcwzSoFprEwTYoCluzEYE3FjQRstL1iLImOD2gQopL4JLLXz9GlM6CIjOgBKNBKp+0xjZrR0HqQufb7Rhcaiy1l8AFte79aAqGE/TQ9uAS2yk6Y7eCVwsSoCQHDZrPZUdBgBaU14i0W1QgKlpdy1hQNO5NlO7X7fi+u/wZ86kRdRsQzGowCliBJl8M31+e3IjX6wQB+BALPlZKaMaOLoSIUZqQT7zl7UO+lhlbLhaJ1y9AfedPSrDLf3DptFWvceyoLWa76uNsQ2vSMIEC1JFM0AkTJ9e4bqeDhoUtNxgVXkVnfKEZEMBFaUFeZSsu49PbB5r5bDpXaYqKxjSiwqDoMcQxAhpUUpFkIEEJDVINRQpGSTYsWQmpCGaz7YVY2tHmL0X8eCfAMWcRQz5lleKGJ5kndXXxwjQ9ey8DfIy8Uxu1o0Xn+FjQI/ij+y4uazjfds/isj076GR7+9uFzr3orN1aMKUlpotfFjTm022HhGZ7VRFgP5PLqOpsZbyCfUmdNnDkY0tcMZyg01LYpGb17xpaoQlG08Wzlfn079r1dvFeKcJDqNDMBQz4Y/dze/kAsbbTCyZ4ddP4IJV+LP2pAHXq1pGRihSdc9BusEX6du4EY0GFBwHKC7gKtMwo1XzGgrbl7JS4Grcuns1DyEkvHzsKOn1vsLK1c1cMBwvt31UOsPZ69nrx9Vax5KEvDLSh+EhsbDSexKieuHb0RKl+BLdBctg6/HsZcuQdSJOtosy9yy3L4Wm20/s/wtijllimvxWamMTLCzY+xYmj6joUTzLfCvQDRH408PN6fL8e38bns2d8NfL688AH+nC7n7vdP/vdP7uPf3av/+z3/+zi9rsf183dflwPm/vOxsD2T+xnzRYpfB3g4+mGe9fffVx07IzzEYCmhvfrKbqxYjc+pTaNpA0+/zicvx8+8X8c2DLfjchxvN18gvnh4/nwHvfxcn3nS02v8Y9XhtP9VNn73vD7LT6R5ytfwPZDwn6Q3S8R8imtuuuFLxrwAWQ/ZpCduely6dt0GacwnDamUA84xWeQDD6sSAAan36EC0Lrp28X/3Dr6biTS0g97T5+8jEHN4P0VsprCUAGEuTk1tBJ+9nLIwMRpkeSjckKxwwOG7yxo2za1GvCWylvOjJMRJtVspjyyI9RQnFcMVXZIVn9WDCLKKmjXTw9I7hkia1i0ikW1GFLmwGq3enX3x1jTGS5WeYq0QQpm/cOTWFqF48zYDIf4v7gk/FC5vh+Ob7pn95wh/PP/fnn4fwLf3/953b5Z3fRv/38e//69+721+72g88XXy5/XC7L55uyfiwW/wcQesqGrG67zkcWfn3cfn7c8H997N8HnWAUbXNBUn8vJjW26YXm4FuKWKpcV2cA+sfx88/jOc6mZQPdOL6W8P58/Hh2Z75fBF4/3l8vHy8X/F9H77J+YvFxGTmPf7v85OvC+bSwH8HmK679Tubtwte0+JKBX4ThM9980sBhQiBEfLCEnyHijBTsftNsYjQV8dKPAzBoWWjSuLRY/XRZvWHPLVF7dtexbs0Kargw+tncJy4VvyRw44trfBqNMJ+KwPGp4zMfB1g3VdcnFIL+wDQ/WH+Qr3krTIUCB0kTmN8xgzZAnCTBqdbRFokBFElUgO2IbQ8ZOzxkhOX2q15zq+0SIPX0668FUPOGIL9wteSWPmi2lLGdY0GlL0ARYkMnGC06B6O/Dk8/98+/CtO90Pw5AL3+vf/11+71x+725wLowmihGR97kI8q5rsAAHShE5hSJteFH+oEoHzGM2IrbgS3toGpAMUwuEXkaS9A/wxAgekffJxDgPKJEXy+LgZAi04Dr8ei8+P1wlebhCYY3QWmjp8XUs/7n/k+O1/A9hvDAShfduJbb/2a1nwRxi7gDtNHjApNHY3lzswCVICAD9u1GC1A08UHptjCWNDfAArOAChNV4yCMr4Rnu8+oh++YpJegA9x8qWdT7/CvWF03cLbxW8AdUSEWAudGFHECkBgXKAgM4GoGhB4YQ1sbIQYCnw7/pBBlwqKTkbjkmjfNJ/cC1DfsILDBE4/C9DA21Ja1iM6W1zpC1BM5gLoowUdgMaObhYUjG4WNDANQJcFvf29v/3Y/fxz9wpAFzQxouc/xnbuNKL5eAZfVdDcjAXVfH5qQf1oZj5t2C5egEYxquPBgj593l69aJWcb1CDy82IYrOKzgIUwyk0A9MPALqMKBZ0zGdhmqtMsILUz1pQv9KOBe1XXPOdzAHofBEmAB0jGmu6YTToRNEaefDwexcfI2oHSyvTiPG3Lr5PNYWXN2oYUaxdG1KMoo+z35Pdne3b+MaOAOXTQ/H5JOCYTwK9i9eOxoJio0EnklDa1r9r8VRx/hIcPGmotA51wE40rqaY2Enm6rKa2ZN9LGjQGesCjYOKHtbi9Pb3Oi8E06zrIqEEEA6Z+A2mQfugM118TvmulhphGMjok15e/+AY9HLKSPRUk0LPF3f9ubv+M46e/fbn7vbH7u2P3csf18sf1+u4y+4HzlHp7bvfd+kAFJ+u8m3699ubXTzffHcM+saNCLXLZToYtZqpFXc/H7e345WPxzDG4j5AC/rHAYye/1hj0OwF8itj0AxAwejh4+Xw/npwDPpyfWPCw3s5Zx103jGP+3W+voHRz+vbec/32ek8+WRtPw3K0LMfKzLgd3McfTpcnGGoc1zpudG00Kzr6LNGdMwnqKMB7gDN8zPn3jMS5f6SuyKwD0C9K7KdPXY32peOhe/JnvM5bubp+L52vgmFEeV+kS9SxbEFojOg4xSkQOFWyfvh+xi0AFW1QUfwEmgKkQVFMCVsNlthQokiV3Y9od4in0cETPFxC4fdDxRtQiVPEbvTJ1ts55irLg06RZdteKehtdT3OySskaNP9OZEsKMUnx/qM5w4vu1v74cbdxMEfu13vw67n3vc/uf+8M+Bfb0PBL7tj9/35++7z++7BK7P3w+H7/u97nDiJgZoGsglx/CMu+IzHdbt83Q7n/CvBtLF04UB0wC0ikHS1gSJ7UVYQsHNutukIu+ZEvky/a2+ptkbc537Kz/dPp9xV/2X2+cr7nB+ZWNSPnfnlmJ+3RxnBxufW6szn5ilr9x/EjhnajKY8PO3GOd8ys2PaPXTROpLlWU7PF+bdJ2GjkbBbAUawVftqJ0glVG6AlQTgx1dFjTzerkF5PbIG0Hva7who2fHdoLO8882Ns3vR/r4wFw+1efnvLwRw8mND1HtDk98wHNHgJtSlgB1hoEunJxgFAm0eIGPWi3XRMR6GafD8Jqo3HZmCUxaweel07l661kQBaaeLi75xZ5w15JCC/nly3v+TLWkkBFo504NAlCf6VqCT9D8bAtN98E2tODycBWd+nztCFzuf4FOoSlGcS/7gxAUmsfvO2H6g9P983fjgSlhkk4EfjAG5UbYbtCbYjBaaBamArRffneD5CV2rqXqrpKfXEOHXMx7gjLR+WMwqjXLZkxMWAFWofl0O/O9ZQKvfBxcgIpRNlpe0CSQu2G+yIoDlEGnAMVcXvmW8PoCdgEKFDrIzUSCW6oS4NZ4/A2gabjxik5OMoNpk9vqQlNUGWAHvu3h8KcGFnbMd9IgJqoTPnzGh8dtuA2jkYRP0dHJgcs8nICh0298SEeA6rNAQyzyIWvuo7hi8vHIGFGZAaH+G0gYGSfw7zFoGqQwTUYQNE/Trs53cdV5h9QbGS/SApQSylMLOiGvU6AYf8lQmAa1jV83Sat/X+i0U7H1XDGkeTncakHj74Tm3YiKzucDNhIU4kDn8Qcw3fWUeR8wuv+x0ClGc2vrZI0YPZ9jOLWgOoae9O/a0bmLpxmjD6uK0B1cu/8cSg9GnWQBoBtGGdmipzq2HxeaTzGfBDCfL3vN51hQjKgGCDzELSOqBR2YPvHZ+Hzdmo+wa9f8xvD6EiEGdcxnAtpO7SiGz8lJzScHvnYtPh4aTytqBjROpnPTz6XIbNHjNBNAntaw/wN/fIGccSc9u9kWRrGadDX59qS+92IgNXZUw7lhlNnhjogdgSBBungYoU64ixQw1F9BEshq4A3XEWclxo4aDF3yjfmUUy2ovby3SqTmEE5pvtXFB37ToKGQ85QL4yYDXjLWgqKu6eLVitcvP8t80strPu8WlM79AEzx7dz5MhvQ/BF0/rCLP2svwegV20kStpOA85TT0Wsbaj7xsaCB5jW9/AxAaQ/3l0fdoxWkj9B6RraLL0Cf08V/FqOOH+jifYyPiwVNF/90HQuK+Xyhi/e7SRrOZUTt4u3lRep08YHp94tGi86dZXrTxfudXPrWGE6/QlYLmi4+HRAYTc/ufGUChSojMpsVXMYJ0wBUIwqFc5lZEdI1OppPhguxo1gmZpTQBndFsaB3jNrFa87ZAjVdvHYUgFL02M4aUdqWCfv28gUoeAU+7eLVqYDLMSgBGdF5pA14hKaEXlgG4hNFpeZipLpEeoekBY2pr01Z6CT19OEigxzmXYG2LiUutpNFBcxNEgBNvxLrXMNb85mVbMf3PcNQHiriOwzlKwT4b8Lm9rLbvex1r/v9y37/utu/7PYJ315J3X+87p+N3x9edzhS/fAM5hOdAVCsJoPbww4H7HuT5I38TNRHZLVS0amRVz12gFEIusa9c+Ovabyl+wagGgY7T1rltHP+/1n3/rx7f9l9vOzeX/U/Tu7Y986+fYxicFkYw6oYF8ac93wbmYl6vgAC+l9ue3r556u+Y9CTUOArrjwJ4PFmxDCgNe0cuEpJS9p0PTBqHOp/ACr2xAiXaGR101VZAJkw1RTSh3ghYy0BF9/11XFXVFDGat4+3HWwXYwKarGaL9TEMq509w6inahHcfhSUQgY70R9MqHV6jmA8Uw9SxymSGhcRA+UTJZAluTMFTg1BES5rsRR4VsUSs//6f09543cfBmqoO1wDEoq/LmUALwdgEYZrshuAAqXMnFZGxCgoDM+X3q/vOMY1DgGBIK7F2EapO72z0AQpIpakhK/BxmvoJb4Z0EsQHkzITDlHhycA/hinmkmOvcA1Fc/otJKH4GjOeS2k8rdAO3EoPPzeQc6zy87YOpdtA/Z7ci4SXovNJ93PqziUSc38lwzL/s3ILgf90aAVQbgte6wf/PDibs/D/vX4+3lCkZ3r/ggstCcMajt7uhz8xfGxExaDnmBWppwYhylCVMbWiMW86kRxfKBGgf/QsmeX4BqhXlWlNn4PXNJ3LP72W0GQvkQN3zeuaQ8KBDe1h1nmaK//G1o46Tyf0PnWNANGkktkuQXWcwyWRVMmH45KC/YpEBEFbUBUZtrSgzUkuv0FnGLTNh51I/Kck4ZKx5d3bt4GS+MWp108QCUx/F3dB5FJ48FcfkO8kCzWIwFFYi73XNQywwIGGU1O3brZf+KcpPKvW7QqQYZMhYoDGsJfPB5Tc3nmqi3caMSBbpXxg4yz5UxTWA95lOMfjJlzRMMGlhHF7/TcIJR7eiyoIAVeY5jPjWiOxbA4LhUsiQGQ37c8Y3El8Pu5aLh1MWO5i7e77NrRGs+a0dj+ByA+ji+AIl1SdvRcLR2kKpZEoGBqbZTJA5SibWONC39uxY0s/iAGAvKTCdLsfwEqRYUMWLFq5pdMcqJa7im7otnLgBKVXm9bh7MZwAaVG6omwDyKv+GUaOHRcBTQSfKsmifLBYR/eJIgKYy+MPT/MuChp0R/nvMReJV0UizK7W2M26hMxglA6OzvFaxWdBlRzGfopOe9GWPq5nknQqAGMPZHl9QbhaUAJZVjGpc8/FDl1zYgYmh/e0n4wUGDntukph+1TwAU0yILVbRe1UVq7GgQFMjimqwoC+DTm6JHm6SakHp5QemHy8YVM0nkgBBDWcd3bpuz1ItfZeoctcXjF60oJrPGFFu8jWifDsHiHyZZqJzxpTS/dhLax/TZlTAlqMK3rqgfFC0LCgtIUC1nZrS2dNdawwXzSfXXpRAV5InmQct6Kefhmf8I0B5Pcbm9B+MTpnLiLZ/lz+DX2Fg8fkVPVsvn+jygKYBGEKI3Dn1cuKEOKqSFK2ktDlyNSIqVaSGXFxaOTEagIbEtrNkjtMHKt+OButD1JYm1ZhcU8SNBXWaqciPHcXEbZOg3suvMagjUdBpL/J9rOY2AOXDggBU/L3UUtLC0pTgwBg0fSsYZVKr6HQMisksNEEngdjOrhfBhFDjaCX+Q81oZ2eHdTzCKDrXGDRdPAIy2cRd/Pvz1TFoRqKOQV9FJxjlo/UitWNQOonNgdEXhp77F54cHnhMNQNQdpFmGMoAVGjayd47d5Aa21mMOhIVh3XBJrWI+dRn0BwLmlYPemIn3e9fdHdIyw2wF2/sKPXv6irm4blb1YLyvFIfp35sSq+Ij3dVRZi64/syT6ecWDViazvBROm0vehcGA1YSJSVhz+y4U9rsDmC0T/X10IbIcMUNp28AHWESHGBKUC1rsk5jXf6fCM2R2MmHvaIphwcKWkM8ADUASj3HeNEKkXMXbzDset7nPOg3tHwNOj2crjxqUtAWWePyG3Q/vi6O8790HWSQnB8ORxfdcxB8gDbBQaxEpfz9Z8DT5L95Jbfzl4W1MkmrmDrr66mklaHf64lGtQZTx7XYHuc4Iz7fOHxjrvf90a+d/EfT2A0E6K5he886IcT9eM+dodxuYvnG8081H561ec5qhNM18PzTf/YaaZT7uJzC/94F2/YlYBUD3PiQD4wE5f28ri2mC0YzASgdwvq+CB3Wzwzzf1fItTVPMPkASbfcEy/oUGGiDJEpB0JzD8ZSmv3oiO/YuJUKEilPfOIy96RlmYIBEZBb57Fj5L58RAh/PtTCzowFTZqXx9nehrCBgL5NaCKk7t4eiCIBKhOwJmXg7v4O0CNm3h1ZbqNPbn48bJCxhrRYpRLODD1GnOKfp4kZYr+UP/2yg270KwThS+Hw6Awt+oilRv2YBfghqDoLEAPmD5WPAjQzIOKzut82d2JPadC08WrfuVU+AQU3gAYCDoHoEEnHb0wZQlKJuq1oALUSVCdGHWxiFfIh9NMfkpBjDIJWt+ZcpH6dD48HQejTwHoczHq7HfnQfUPD3NMA010l2+9KbATDBy0HK1nRYrRjI0fAJoBqJ0jXfyg02EsmRl5ORIlK9Ofa5kSAJWRptEZpaCTmoo7HJi6Y3ShU5iCSmdAZQy+sPeiEx6cCImgJAAJSAjlRH4EF2hyTal8m0CoTqNYNpW0puQrQH3aSV+yaBIw01cLGj6W3gZWTRIZY5UoKTdGC6CZGg5Acz+580nSwDRd/OH4fsAQaji5fRCgnVpaRvQVmApNLCh29BBoQuaUU2znYBRTemRtkKuVfJLEY6TaztjRtZpJU0rzROtIWSVWI+hzA6gwpWnBZdHJVPwAlCE7/eHpivksQHnUeUcnMD0JTTA6MI3tFKy7wx9nJpjE6BMBrCm281XzqQXtDGifdnK6Op0Gaj7RIHLHAtan5eyyOYAWd/2aT+oguHKjrb9NMwkikErPQPXT4XOvlyUgWUQnQANbYQoovCsSoPHbuoPR2k7RifN67ghEgII6RhPkGmNmPtEdWPKLwhsVaAKydmWqP7IvDAVAWlCvvQeAQuVjWlHkdSNDnccCaE83P+UNOiuGWcJfw7ndy6NbTvMM2C5+M6Kri+eu6HU6d2BKL+99RC1lfLt4pjk1nyB1JYXmjk5fHrpy67F18Q7989zSwFprR2B18dWdbbrqKUDt4hl/ch/BU6XYTmHKmg6GpU4zCVCfxcd2BqZ5gNTHSI5B/6uLb69Izx6A2sWfeITjM6QaUR8jcbEBU/r6oG1NMwWs+U7ZdPF3mIpOmzCHLbYwSsP3Fr6mcs0LMBLVPopOb7yojOs7u5Tu4jJLaqYdNbutOQCVb1EQO4qRLDqZEKXDVdo+nKr59DU6IDtHYLQBlEhtg2YPa5Ay0Hww+wWgaQ6gibnHcbkIZK7OtWY5XfwAlBSlO7ECnB+PCts2bVwKbVJyaYq8iOlLmiTvuOZlgskn095gHrl5zKMzfF6SdMcVHIGEs2ybwtVIvjOYQGmYf2bGuOMhOx2fUvINYXsleh3WIoHI9bITq5CZrh+M5i0dFYXE6F6518ElTePxzjHAYT4Vyqfd52nHtDz+TNTbAMa8x7FW3/kmNl5Zp07Fc/PbuS3uMJixcKef3TenH9zngdt2fKfLbs6APnce1AGR3eTxiWujFk7fzpm2Wf60b7Ra3aaXV8/UxDYxEOUTognQBhcglVz19MW9p77ypgJVlAvnVHgfr9dH27YgwOik28O4kxnl7QCbW7lEKiq+di4tnUKR7X4kPPIQFnhKCLkphUdqQTQZrR1ikCam1A/88dXDxjQhALoiwkWjI1n/VwYiG095QaeMitTgBsGJAZ1AM8so0gAAK6tjXMT1sJQrO8mI18J0wyhq9c406CR1rmYw+oMLOQDNpB16Z4qEEed7HM+tHPqyyo+5QESK5NT8Xs9UCWm3dkJ7AHHDaF47lj+O7yr7GglFFJ3AdGGUaaZBZ2HqNJMImwcOBuLYlCTQdLqeKc+iszDtDCg1EqDqbGCKzPboNl38tF9b8Y7OwJEKYhEYZpKZFqGSAlff5XYLlKiu6FTzXuS6LlNyiOp4dJxKzl0RAY47Ru0sB6MwtxaFKYWJuxxRsiebrgmg3MgjRa4i03stGeVBHTGdUlmG2sDBmCLuR5EdCzqRlpQMPYfLVvCI1PLU40Jn9RUjSqwAXUZU8xmlEKjuitHiUt/9ETSf4Abt1BWypHrdm6T5FFgUEQDhU4hG7uMBoEzUA1OnAG0sxK5vddYBQMsKn9Qxn0/C9GGi3q/Fyzy4HGgGr0I2AOV6EKZBJ77mM4ZzM6LOkhWgxINI1znawLZxWmLs6IbOGFE7lii8dkUDI2iNpEqb03biaAhwQO3Mwon9Rc0nSuZJG2ocnQeghWZhukFTDtytL3Si5B7FKBe1WCj6x3wORiGj2Pwnhycr0DB5C6/In4o9tERFXl0iOcHlYHQYpeDVeKd57kUa3BH64aDuc7QkTqIaddRevtCMrypFZ5Yn0h6rfwemUZaD+vbvxShKJCAu0VGv441AI8rXWQNfVjm1i18Y5UbSx4zgBozyQLwzTenoHa2kacdf4vNLY3dtHDc11OsTaD528TRWLoABqM85V+cevBagg8728tQ3PXsee8WO1oimi9+M6ECTQTswXV08hpMm0Y9ZIuA1XyVzwSSQmyQjB52OroLLmE+fzPqXGqbWWUvvm5kE0J7vFbF4WT9X+PJJsvkc5EbzD+POTVtgVIBGvEJgzGekLVlLXiiKLiBlBIBfF9ltiCFd7IFQXXrF0gpQoktJ1MNx4nnMdip3znBhYTxDdE+GZJSYUhN2MN8zsknr1czomhWcmTCNzyxm7xnRqjOauIz88e/1IeYhPkmuYfAm1jsxSRnok5MVuO1q+1zHLh7ApaMfC5o2jcRWP2XQfbvuUI+7BS0uNy3O27I6KS/Fm4YjslPx7/vD++EM+n1YxeOATOb22ZXLAPIc69vNxS2ub+H2b55CJHxlYs0Y/O1+sveWNAOXdq9o50Ls6OdiR4GbXoEQYXtLLVkqbzX821pXa5Lm9d43K0GjZ9855rQKx0errj5WEpZ1qszFUb7e4uKiYflYmC5T+CovaJgLKYxNDRzgUygRKD7krAtMjaIOQqg8EjACIQQA2m6dbOGM4FCFxKFZAV75QBU5JqknjoU21j0ho0XBNBIt32J8NAZRhogkej/jpKOrMvS5njPy4TEQUwsgmgyYidprq2vReCbRKtK0Hxu4e9cnrnNj69IcZMbx1i9bQ2RVEevOWAGu+bb+1J5f2xbGVafz0sTQFvxSdoidIeIhOWzp67BuOD4P/76L4/mQL/r7TJuCCPCOBwsKfM2D5VmpF2/w64ApGzu47orwvqc84ecUXyWoBytAgJbAoRZxGSZgifhAU0DmivfmNvpRyTbjclbCCkqXqiWfqY5LmU2imvg2BiRVqOtGLJoLg0f0aTYbMgoakZxRkokNoVN9DGNkEP0J3dj73MVbtLq0BA6oEzHZVnaZSWBzpDaclj2/1Je2ZjWizeFcge+4kpxmJ2NzyJ27+OKEYIob36RRgkFPJpPVH40BfRoX4SlPmNpJOmXm5YE60gD6dN2FJuXHjdUlW4SOrz7v6CToLasXFjnQI3ztBwqmN4HCQg021LkxRKEBuiUUoy8LH78a4USkOkVtCIYAkQfUYBFAH0BqoOkciwDt4/XAFJ4YEicKLIWlgkFnX0XiDT/wd+uSrKDTzUdYORiYitRxKkE43mEapIJXVVQfguJSBXj/IARzNRrQxnmp6VI1moimEYTEUOE4WqIYNUA1Q0CNIOAenNX3XiQoCqUQAwN+Kd3r3kEwreg9NAXgaFF/vCD1iRCgWkYaooelh3cLjwxhbHn+c4SidOqe5FQC1kbSUKLHI32kRpTqj00ppVywoChlHSljTsIwrGSW8ixCbqmll6v1sBRhKndSgtG0StsGvTAQ0i4GpkGqwqYZlLPM/V2209aSuRIXpkeuNm2QRo4Jv/ca0Q+MqM7lUw59M1GvoEiLFqKnVeE8Q7E0GMJBaMZ84vt8PuYTkViAjAUNNA+Uwh45mwXVYK9Frc/TudeCikXWLoFO1u6B2hhRsUvv74XqI5k7TAOL+2ngqz5QQGCq/Dj1Ey3ZYdoPq+XgSo2pOE8I0RgGoKeOOulFPDG0DVUWmhEDYcqi2lGhxs/jA5hGcQVYToJR2mKmmcQoh2DgZ2nY0hNdjTfRiBBQFKkyJsbSrRdTzrk0hE1GcK4pYGwiKwum1RYzLGi4yy885OwBrSnBYsq0ACICnaorvoYNpupTaxcfOdIw0zyxmuhMjOLCm0xeGLJQa+LI5iDVeMQMHhWzIzaHTnJ3FgvcYNK4vr2bdtGGDeCUJJMnSynyrvThbYvS0nHAcWbD0tHXdsq8FpRHl4Gmy5QwnBrRtfyU3oZy6e7/ZFXW3YL6miRwfAadLnph15ymAtZCc7SRNjFMSwQZWjUD4smKR5PpKFKRGtE0F/rRUSsxqcJbQZUZ1QWdATR9PRXv2q8q3OLGWEofJyNZPJhnWRo3B6rWyFplhBSawhQhiiGpQo2ndlfeSKPmU5C0gyH4EWmy8jMpHIwS0UZhGhohQ5Osw2fHa1XrKM91JqNFZNjyyr0lW8GtdNIIk4yoEg3h8AJk1C29tRgERoS9a+6989ekxGM5Zz6k9DAiQCmB0WKSyHCjPcQ1YYoeqaDOaX5SaItOrhA7KDH7OJhMoZWtDL/SSEAjtcG8veA080S2H3MXW0OWLLNLjSyB6JvuctqbsR0ZVWB02AD6o3QaVK1WsVGqdZKYuNaylYO8evcUGkq00MhJAFYUQUVwmzCkEqamGT5ZL04hs0YPrvRwmEMJOPgpKiNW45DCa8i27zHSSruiEuSy0fAgWKgJ4CgUMgIeD/QnRPRIykO89e9hgISc4/kbtDZcTSVxRIZ2XIpHy21pq22LDpKMXEkio1hpzBZeAKroZKGgwgikOiewOAyM0qISQzeVGT2i+hALZdoGJpWKEUnCmE9jNjfyWJzjDPxVbhBGuwaXq1Gz9lAteylSU4orQWqdU9oedAoIlWD8QjbhKrDNRriWRIu6KZNA1EpMyZaWV0VlgsblNIUuwCES9SIyRY8wyqkwqgIbtkFTyaV8kD84gEMPpLCM7aRnans0vtKMWDBqPSZlq2Yz0HbwMLJ8v7JZFjREFrEVToat0GhK9sEj8ZszLpGmVpvl0GKqr8Bo2n6A8ggR1KdxL8gKHYgHEIJJjqRSB5nglwndLWQbRpMFypZfX5k4NkQmb5ncMzYyPJly2oC4sBtRN5o0XhEQcyjU2rptclu9WBxM2NjSm3Gg2ZiSZbLprk/ExqE8hNzaBGgSZiC0aXoja+1MTjXxSCrIplAlj5DhWVGXPFYNYaJ5MDpXV1PT8xqD64FIjwfNMccKzC8/CRVwkiFTj2UyiUNRUolLrUNyPHTaIse4U5vf7HP5GeTYeE4A4gw+eopfXOoXyu1k4o9CUwL50ALSrGoLR8FR0MSvuYJMpK4YYWReYyoPIKasDUB5mBx7DLcYVE2OcuJXptbRuqLl3KdrCBMOczM23sC4ibSgETJVmHK7aXiYiAOt4DR/DRLMqSm+qavWntZqJimqWLmiHETuH/pDWiShHvhUh3Ndq6IGbHeruY4tSLzHVmhsYYWhIri7bBHPJPQZ+iS5uD2ijnUvPfXa0IBIc2ylboFK9XCqLBuo7vFWnPj60MgT8XgYttFsgShzSoyCJjxV9UxtzO/62RSx1JYIFUtJJS5JfaOF8+MB1oewP1JMen9NJ7QiTXuQekhX5FBBsHBpZkUpl+S9Zw95Th/bOTxNunPbwi0v/PR6eg8Mry3+Tl6h73k2IVYgElTWxXX9lmtLIfwlx0LoQ3yGAMlb+0DGlhuxLKLyLX/9tsWmUMXRcWxiTMOu80VpfonKp7GE76fh4OnUcckj6RRq6pBpT0Msi7uoojlHr9HFPQVzstrZrEmDjVasp/fIKXCqEsqWYfChvEGNJZYJBS3FbYFhG8FTrEy2MgnUjUSrqR4pzYosCttAJLJUeaf9EjAmBI03qWWRlWPLdae5y/Go7lVX1WX8urpS8+HSn42lgWTbvGRWnDjLX+FV98ZNfFMVMnccChxWEicQaoqZ0xVnTAofPtGTEVIur0HOwnZ8U78cU81kDAiT+tBAyagAJixvfkMGQU4paISa0/LUx6jbaaxqkT6uolWgAo8kIzn4mZAlrDN5T4EtRn+kM6+I+cq8Z8k1MK0aS0m4giVvmFvqVnKuucYoReLnwjcphYd8wl5ZNTPy99CfyEZMHGJG2tBHDCtyL3qqpfg5ci5ByeZ3i7Ae/tfdw2bfspCa0/GnTWQ1h3VUHxzmisISmIhUJAwVO/WySOnHhz+n27/RoYegnCdj1TNXa/Kn6kkdBU/sYlypQrBSIsNKX8WQqEgRSq/BVqpNk8hRRFgtC5qTepsMG57gpAgKYA3j5KfBmcjFfoPGKr+qMl/lGh4ykedd2AlOI0gfAC2SOTN+E7AEEVOyxN+5KtmjsJA8HE36wipCKkYqoXSNiZzhhaJFJCQGZL4Og9P+BHVD80C3kTcQX68ck4ucEXvYisIxIFtBXumlLXETIqMJA1yC5M3xIMjka/wSf9VD+smydKyS5Nzo34B052LyEuCRiTlHqbBQc5FJ8nCM1+o0ey/BLY3AQxff8kI4xVmsNP7O/woOGac9cj6tvZqXuCFLiRIOt8k0P1vq/0IvE/SUvAmr0RHMgPlTy4r6GF6s+7vlKsMpfkm10TSe05V7xN5Ok30TdlK3XOS7U44CTLxHrnBj9EsWn8xtxkXV30SvqAUpeFpWXJlVirtfgvv5ED9GGC6TxX4121eqVRV/V/hO8VBnIxfDCW+cm2TsiorcVmirAM3UEsKE5+RfS5uzkk+7y25dTIaGQWLvJxIvA5qMciZbOTbQnCteCbZUC0kXtsU8EFsdqSuWlDl9iNlSKlVOYS6zhvEXjb9lVb08JH0hTnxrMdWsSC0CHzYrZguUklNjQjDhxDyGH7OrqLuASjenYbJJLsceI3myEcMpGfhttp56oxwXghYRomF+L/GhsLCRIW1IePxySHuWAMZDuTEnS6W1jIgUPx4pC3gReauW/MvIwsZhSRertU5Vjh5SWXaa9i5B0mQ6LCwMOt2KbGA7tWaerCIbSASejbe5lMqpkSvJopu98nMeabYGkLRH9EjQJJiUjLwNkICQhD0NaeINVjU9TeJkKXHit0TSladCpuITNiFJcA9ByvtCbMb/PIbejBZUspZOeAkwMqRZoJoKGhqa3wJDP4lpIWraIpr2WFCV0JjFD4aDy6SqvRylGtFWlsqpv5S/pRA5WR/1FlbUYjUK53SDEiKktUx++RkAoHd+j8GyiY+3aPg12J9GRgPwmuaxjCmMEo1MwcMhZI00YUv1ZLH9Ghi2qaq1iMoINNzTZI5ntUYrZNw0OyWuvJBGxMmysQq3yS6NRCMVHLazu9hLDyNkaqpsyTd5G16Ud9VVY8nyGGlm2a3LO7ws/c50ETSmlaKUBCxtC6TQ4Zd4Cho2/KQQz0uPb2YPUjyS1CD+RPY8Jzb6xqf0Sd34lHaUkywmFYUp1LYiPgW1guVnYSPqV4Amu2zbykrg2RIuZVhAIu8Jj/ErTGol0+eA1eJm/riKO6mhmiwb/SNlqhGq8YRC5eM3gZ7JpKcV1bAEiziJQ7rCPZVQ5kPMT+XE51jCSNCYBhKu5BvZ4ynhOjhMeONQnmFOyaYiJwEcJ/y2IMMT3wAnoVmVMqeFW0ddpyxkuDikCUhqEeGdHObiMGOOkMhkMJCCLN7/Ocyd098xugj6K0vItowNR9ItjoK2oks8/ftQ8F7FYtrAVNTIJXIqtVKnRB4nQ0kkIuqHSQP1yRy3NNZT80yMz0n6tGQo/03/Ne8XMmu1itgC0m9yb+HKNsS/55oitnwh+1KuSxso+q6X8kuOiNQSh/+DkKuC2vE4n+g1EG7y4TTK84HYIksAOS2RvKrzS1KQM3wecv3O4SGp2SWgd1sa8Lnc6D+R6fhK2bGrok3D9gdJbHFomjAB5GxoJSVdL9Ej/DJrxG0V7xMzCCTkP5WejBJ5/AdAE78Jss6aAX9zVCMwbQyig9XGGEh5UyoFx90jo800fCgflSsg8rTxgcM9Y6uxkoZDV1WsSCUmPAchpPkiD6krI/GcTPr8IAzr5zZuK2BMD0BzN82J6pxhHsVuCNiaH/7TSIuVJZbb5q8kW2uFv5Alsjx/J7jzty5bWdv1YOSDhjeC4f+QlMeOacfoLJ76W+gaXW4/SyMPv63RUpRFePzr8qZQHvZXDa1vmqLUj77fmO4hqjjwk+9+rZDTyAjZ1Ed/w+iWt6nkoeCp/ABuNDs2KdJVuLbKg6a+tAH08PwXzeh3a9Et+29VpYgt+0asbBkXRAC8FJBHv4n5z+Ik4x9uOWjp1nWTxMAmxuLzJfUBQPAQKxyLklMq/uhP0gNNYrr+dstItgnL8N8CrBhT474GyP5gPlsl0ANl9BYR47Xiv0WS8lsMGXvYbDnWr6VzxJd/sxJ4iDeWg5jkultQuN0xWqJSljs+kIszp25BthiFOKkywS2lWNKD+4K8xBPTyH8nkfFL3yfPosotE36jvzMxGxLMQSGPAvxbsOHzv4g9bCmaHgNeG2P5rpN/VbYI2HBAxsfwXZ7KGD1A8FuNQpa6WNbXWiRL+ci5AmxirECTvhT9mLQxecje5hskVLytmqu69+gKNucPPyt+wLClwMFCAQr1SuzyTTHprtQS8Om1kmw8JlBWnKyAZDX1K0N/Gw+XCSxG99QU22hFezg1Ev6JrE4mF5E5tku7p9ImSS+B0veUsKmbXUseYip1fwg3iwzCoQQE11mL8lxmFbhaCsVK9hdW0fSd5zDvz1ZSSCUe+qWEEJTK1gmBPxTe2JGqcZXQvAo2cWPpekquLd50TxR9Ih8CK0oquNV5EtJCZSvlC89VOqk9fktd0f7CB/WW4JGeGNYqWmoOf79yuWd5mAddJJAbZCTYCqUQotLwIcLjRD8UGDVuGpPHXJImmSga2ftJcZaA8ogIkwK+yphXp9ooQ1YCya0Hf2SwrvzLgMPyTPHcsOmUXCIoKbaEk8bPQxaz6koSptuJgcV5K4MMU6nc5lnl1LNcKddUCjCQ6jfGyBmWkqQoHNLJTnL/Rn47B6mVDSqFMhynFlNUtJbsRpAmr6jYX2okob4vjDSHRCbJjIBFSqOGVFeySGpkJQpXxQlR5DUvRB6WuJ14ln+9cXDZImWS85U7ZahgmCdFBjJUEIOwaY6w5UnSxBpJML6e0amj0arMqhnHP+krH5FRalBKQqufilsQ1OYms3kViVOdLGREDEeYRldNJVdElj5ZkN4QQionPt8xaEBuD/EWZpGQTAmls7DSwabhlL9lHm6ySgEpSS6RdhM7ZJbQg+rbiFYzDcxpRE966mDS0ASBc2pGM1XF/DaHgt95pYzIE+rUSQHIZWaIW2hlNjyRhlqoiFR4EkYSy12tZ4hT8uuW5CFVCQpF/mSPfC12sqc8S0yS9LLTg+yexzq2mKGTKgUu0qLBPJRm9vk3nQ+z3LOZIpG+RBSdxGRNTYgmhtjGK7qhyBBqI5IapZTRqHGgZv5IUOQhqRyCCzOTFCgqBoGkisxUKUwDM+UbApXmKWwhg1moW0YSoCuxGTiSccrMaWLvCY2TNtkqJ34Kaf1Rg+1m21tb/AiwnSYmCoEybmKiuygo2ZGinFSCTOQYcVWKlTezvPMvgSScxFelimXpclBLYS69HIznp0JCliIqrbnMn1wGUuKIY/ZIYi0VHSaWEiJLIJs/kydpaS7pOCJUhG/O0imKBZiaoiu8hSVKdslZvsrmk6R1pFQImhrJtjMjZZo088GKk1Tc6idFnViV6CG6GgGIt2Y4j00nxlRmo6TxrJTJHvLQ65kwoLEe5WZOJTN74qCgfKlJiSeXkKmGUDdGlonwlMNT88TztNnuJJHQ1k1d6keK8YwhD1pZBBtxpUXAkEjmIUNjmnHSFGEYLUmgG9nJFJlbk7CwrgbMx2980aYKiLbJwjJiSxii8okGwrAZwzZcpCJrmBI2Tk4c5Qvj0JVfyEKSdMk4iJVo6rXKrTRqOaWH0usE0tabjCOSWQDoytn2bYb4G2/PrPNQ+lMWUcHiEFW3DPRuHry6x/BEpmVagpWQ3J9Fb/JQNnXULFUrje+RnHhzOgFbg5hWKQFpG0iOKqMNMPHlVj6ljG9V7g6prNxUvOXD5U5wJ7YGId5SbdRHSmhXzJSylRtpmzjiNUkhUwSnsGozGPAsMSEo8bpjT6FpE4mGoMGJGOZtvTvNMCwRNCnHMzRgiQSVADkVMt4wXCcmcTT2S9pEm38530wb8sn3BaCT1CJzMjz4Id/GXR7KVl7TVFubQWbL1E+g5M1ufHJvp5Zh3Pw0xyIbPqRR2OZ6mhzNtYzDnP1OacaUgF8m5bAx/BJYpiG51NMXYTwjrsegahFYhv9b+pD9xuHfpyvjljXGJE0Ps7CMtUktPLU++V0lxP7khGglhz4UVICYTatmDdnmky79il8MiZj4MFvR+W0RG9MtrwI/HpFwiKuZ5afQB2imOs1tpmQcTg8WdPGeZEVcUTXTSnKPTSJekZqAGer4JaAf3WzxBsZ2DuWdYbL8B/1dUypdITaxvgTk26SNJgGyTI7Gz0lYVfqJDzQNLxw3fntOlco5avhSncQ+xFjxLy7lGfNbxpyqowe3LZBr0Qgu1MJhYsInSFUR5E3ioyJalPE4TvBaBCG5hVY/YckaGKZJTkZLjt1tlvBLtnIdQtm0Kovsv4QKcYRRD4/VNP9SuMWSnJ/I9WUM2rKnWHn5vwpNNCctYyNaeKIeFtJcv7fEgiSplF8OhntdDy9LmqQt3nP/SYpr+G4vy4uk0jVQ4odcJj7QNKy/XNgqvopekZOLU5IVOzVMWKJWpKekL6Zbl12a5tWX3eaqqKjCSE5LAdGX1rpLiBhJjNAhxmskkpRfAsYOsya3lBXZ340bgTjFxy0pCA7zxt9PQmMyhX3FpZSbTOG0nW2B5MNroeYP/ufUeNnq4JYgAN1vW5c245Y9SofWQ5HgloBvEKctubzcFI2HpWxOwfurbkHJR1tliH97yseF9Q+3J3aI9/TaSDdwwGWDe7cbwyrF55GxZAfJ/DbxIadeX35Ekb27+713Ps7NxnPsu54N78w+Wxn5xBkpF1rUgIdyOy3oJvS8I15i76WW4/tW7OTOl1nLH9/iZiN8KqI8qQLqYoNNtmNxK2h3g9YRdusotrFhC3wC7vGDM5A9bYT2BEULzm2TaAEhn1NkzGDVvZV8DuwkNmLWBX+pFDF9StydciDCuGvfbUu5eeQJruXx0YlsCeUeQpybZw5EayaLIDW++4iF0yrKmVSOFGCxwTamzyOXkdiwGo0xueo2xibwh7S0RlNoD22nH12FNhvnS+Dub9G5DaY8abhh5r7tKSGF4SU+hcamWHeTemNlYVBwAsDc9YlHtsBRgLIdqqwO+ns+aHx5AmdCM60bdA5qxaV7+td588WeDfpyPJMl+BhYBBniFYjT/PHZYUB1tgFpTJFqdp9OEI2MVhKho5tUyX2AkisAXcSU61Z3bBLqBqNiNAXxiZt8oyGFgs6IJEbzTjxfuWbf/EIzfjHqPks494cdLPAjUBFP2WzqFSgUuJqosrLYlEtANqITW1YhezNRDXVdR2Mkr8Dh8aY/1gvfjdc8EmleNr2cawbOJkiw4RQyZTPaNHlw1SshL8ajtjAlAhSRHTMkDKbxLQ0MWCmPqFuYGchDVyKVzy8fkVHCB/SUTXbTCrFvxKN8AEo1wZLwUoICUQtagBqdvPFVqP/GtFwzJJd8oi435XPXPgzncc8GabTfYJTvvy54FZ34YwvBK3YUFjWf+EIEn9L4/tpA0+tpYCG+cft/2GYUJvhsjhtbONd+ml9h4YNGEU69wVDBrZO1RfoAdGUMaIRLy2UnRvay1bmp7UJnLqEHMVK7/297Z5s0t42DwXrtTar2/sfNxtnuBqCRnT3A/ggtc0gQAPHxkNRMHOnb129//oJOXtwVGngjmE81JuWHA5JvFLuybSyUMl3sBRxGOG8WpsgrMoUxjo71gsZCcL+g0/fJFgQhUAImu7y4RFT1UhPW8gNENQpICgZsaa+nh9HOw/Md+B/VTAWLzboXODK/iHMDFAYTZO02wPR1acr8KxPtcgDfUFIu7CnMxRyI+sS30cB2wAOoWf/zPyDFY9YsvALtpx10cpoRuLwWOI2k0e+S9upZcb6I3YOeI/62T5/p3WbzoLPzEWi2m7KPhk7eaiVShQg18LLtwQqI20cHmm6oUDg9dxPVGZJgQjri3ThpGyVqTczWrJ/IaHfMSLX1uiTkd2EgyHOVfXijL1/fY503MfEWGR+S3PLIEU8Dg+iuySb6g/oaHvHtoHvEk/rDqFnv2ZNiSBgdNE1h6CzZAlSfdCUQHYBwaMSEHiMhQSck+7QgAYUI3ULiKk3PopONA+Y1p+2yFaQxR63VButaDp2iytMFVe6gYPSTfKEH5rQ/PPhRNPnEJOqK2BGRMnsttx3S7r9ugSGMgkuvL8LLXZPJ0o7TtDcVslNSePUxqfxt4NCHggMjVSO2syR12zGs54TujLmqHXnZdGhqe0Ox/7QLSWPPYI0J1bEx04rQ+IhI3CJdpsaPGGllj2F4hmMmwcIuQ0741bJF00vIRUSG9e7ierz3qfi6PAGpvwGNydDPjCPj2EZpZBP/mahVGXbmqSRj0rG5PPFhjl+p9FlNQ4SZ6HpLFG0ZVWNg8Ag8HkOpCMinYXumOo3LdTphiJvqLh4e5nOJLSPKgI1N7TTVa0vhcOZidYuaZcgKbUGxJXkn4Y5WgxtVt3d2qw0ySl26Xz4b0u84neqsJTcCtwNexMUT6N3JbPtE76Fwj0jj33wh+/HlvrV63IxQOOKotY+HGqbBuTgOo1xOb7Gq8SJVq7DbOXZXLs3zy1T3Y5iBVW6yHnm8BOELyvdvHhffvQ33LofTgONJtHocYAsNNns2424YeruZ9n/jNqut2gfG+8ZITgnYqKFD4cnd3n1Sc8AafXNJ1I2yV8AqCTpm+EmGKTEpeN1j/KFjBG0My6Q2xM6p7qvavNDGtmSGaHQfYy2/qfJbjP/WyLs3dM33DOZyp/aguqJFlTVEYyVldAMxjOH2TUfWQv+D85AjyzNdif+UuIDSQYgt8SvGN49uBUaDUbA4d393drp4nkWaofwcks+dzIyZs8Eopyge6qBYJMGCwNpgAxTvPEWqnut2Q7wE4dCJD8J0L24kgCZfTX7Y4ApMT42xqzlcFkrjbZlFSahFnlN7MV2qxDra6H5GeYiV6JSNp9SzMMYFrBWdXIRV2PF6GaEJXkFbyeZJyjqPQ97LLv5MQ92HIkxFp3gFo9bsEa5GX6Y5swMdjCgbrQRT64VrOhtaP/Wg2dkbJQfA1eeOZwyvGDzzEJ30SDGl8pgBzIbNpO4lnSfKQhOpZld7go2dYqsddZo2lmCjEfQoLlnNNRdMAtmG39n9VtQvPxgqfTBKSwZ5ZooPQCFCM7UxzMxNYzXzGZ0kmXIv7j6R8GoBtXc+GG2PIb7uQIfO9jChGXD9hnDopOGXlfZOcSk46HZr+OPrd5E093/e/DnjwLRG+JaCecUF92gVl7wdCM72yaTE2h+JwjraMg/xVRs6f+etYCwkLLlN1NfICKPv4s83Z7RRuQ6ZLCgMDqh5WchcodD2YnR+K3B/BbX8ZMEPCGEUtbuJGmzB8zhSevHE40i3jL3hfvKYq0scjOJfMwpQl5DdgSZdQddFg4vSOWDtrAJUmHjrqqBPIvTFIZDACGDiU5DYG2DUqzLmldA0o4khPMhJyq/C/gDUzz7wY67+hFEZ0nwN8tQRbzrNj/SZRhn/WCbxtYWmXgxGOd3hmYIoPwAdRg+dRKMco8mgY6q/XOwm6g5q5CbGX2BiQOkLDgSHkIVCjGYHdfvsoBedTBzuzU16niN+DD4/g2ngE3lNzaSi0xqkMvvurLNxCk32iyEaOPz1HGDNsIP+6zcA5wneQd/Ln833Jn6yTgJeZ7pw3FPeg95DvOvQSfevH0CfBzxiq29T4qswy0ZYQKGIKMNEAOkY8eo8LK7E3Ugak8DX/mfc6M4GKdrgD+ZkCjUd4szl3qlQXph/E4yyFrV+EWYUlX012mCUKpJjGWIj2tSTBKybzKNki1P7syMHkcEHDU45GI1FEzSw8j/+Uyej6Nza1hUFRyyiXdFV3GwodmBb6/NBD2zcRfvoO036zrlcil/fuPR/5lXTYwRmDVUuyqdetqi11+zR81K1mkfnST3h1hCGBD8XnaawHct4YVeKozmW5Q/lLFu2Yf61Ti6iKz+3pkZ6bKiRu04iMcV+wPlTaX7FszK+NpCYXmrt19WZabz0QIBO3FBXahnLaxXTek08bGpbBllP1cOIQkPkH5ezmhl7pp7GSI3NGcURv8qUX9JwTe+m9HMnHc6YMj+yRotOuawptacuZlJobPthePQ+lIfn4c96TNCK6pduZxhRPW7uZYM3fkXgGMFRMpPqCdFdtXAXtcSOmdHHbJSMg0NRadfHqbP88TcGJ0+E4RGZRlCDoHz0zHHG52IAm17GpEt9FXqPRRI+o6dhblte+mfvbQqVz1wRN23qgayIo/FIi1hj2jPujCmhMuxXXs23YCw4nFMjqPNp2Hp8qI6b3+6HdBYYj+aCbKsp3/NBSGGDDD8XA8N9lPJ0eyeDSyfecpqXUjNOaY2UHX2UyVyGZtatR2aYNM6/W2jOhb4Wd4OZcUOoXJ6/a44HQd5wuOCAdS3XwjX6KOeUI2+28Q7Kx82nfY0ZfaR0/X0VjIUIVtGypjinstkVJSLUoTRsNYXWdFIuLbZnricUw754OBy4aJXYQmM1Y4UrOqyoU9Tt0PCKw9j7xF7J6ZKTkerVwAdl6tGyuvye/y6yKBOst2rcXGP7isnCXxcYlC7jt9057pv/Rg3qc6V/uylnhFLgq0vhMZQYJ4tnG9OBaEPxEuYnlNAo/wRiuRwbooqwcUbTtHRFXtM9DI/lZ9h4vU41uwYsG61s+lDqHtuOvroI6sLHkgIf5WOkU1qgUG3H5gk6aFlV6/uoVkrBZwr4pvumz3g8VCpudISUaFaJcdY7XKZtOKNrCeVks3psS3g0nz35K8IyHrFRYd2NuP2uB23q/nu5uP0yskZ8lDL+E03+GU3yFd36U8nwGLj2rGEypBAP3oXeQ5jGL91hfoae0dO3yqIXgJf2N/OZ/3Li5dBQb+w+R9X1+LzmzrHIuRln9D3pq+0g3blGYkdfKXmCR+Nhjm1nHpF3fZP7qdQC5RPVN0M8nyEX+ykence8vSO+k2b76Md+n9GtfuIBoP+UfyLw/xuB/wK1NlJXWJEW9gAAAABJRU5ErkJggg==", + "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -457,8 +457,8 @@ }, { "data": { - "image/jpeg": "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", - "image/png": "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", + "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -470,13 +470,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "1 Mat TSImage(shape:torch.Size([8, 3, 100, 100])) torch.float32 0.007843137718737125 1.0\n" + "1 Mat TSImage(shape:torch.Size([8, 3, 100, 100])) torch.float32 0.019607843831181526 1.0\n" ] }, { "data": { - "image/jpeg": "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", - "image/png": "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", + "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -488,13 +488,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "2 GADF TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 0.0 1.0\n" + "2 GADF TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 2.980232238769531e-07 0.9999997019767761\n" ] }, { "data": { - "image/jpeg": "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", - "image/png": "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", + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwBOM1JxVfvUlDQNEqYzUy4qqnWplqWiWi0cYpKYelFRYysP4o4qOj8aLDsK+MVC2M09+lQt96qSLih3FKuKi/GlWqsOxIcZophPPWilYVitv5qTf7VV3c1JurRo1aJ0cZ6VMr+1U0bk1MDUtEtFzeMUm8elRbuKTdUWMrE2/wBqN3tUO6jNFh2JHfjpULMN1I7cVCzc1UUXFEu6lVqg3UqtVWHYnL80VAW5opWCxSwc1Jg0zvT61ZuxUzmplzUSdTUy1LJZKQcUmDTj0pKgyE59KMGlooGMcHFQsDuqZ+lQt96qiXEbg0qg0Uq9aoYHOaKD1opAQd6kqPvUlUxsVOtTLUK9amFSyWTdqSlPSkqDIKKKKBjX6VA3Wp36VA3WqRcRKVaSlXrTKA0UHrRQIj2HPan7D7U/aM0/aKGxOREiHNTqh9qRVGanVRUtkuQhQ47UbD7VMVGKNo96i5lzEGw0bD7VPtFG0UXHzFZ0OO1Qsh3VcdRioWUZqky4yK+w+1KqGpto96FUe9O5XMRFDRUxUZoouLmIe9SVFu5qTdQxscvWplqBW5qZWqWSyc9KSgtxSbqgyFopN1G6mAj9Kgb71TO3FQs3zU0XESlWm7qVW5qihx60U0tzRSAgxzTwKKKtlMVBzU6iiipZLJccUYooqDIMUYoooGMccVCw5ooqkXEbinKKKKoYEc0UUUgP/9k=", + "image/png": "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", "text/plain": [ "" ] @@ -506,13 +506,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "3 GASF TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 -5.960464477539063e-08 1.0\n" + "3 GASF TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 0.0 0.938302218914032\n" ] }, { "data": { - "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDkqSiivmz5ADSUHpSUIaFPSg9KD0pD0oGMPUU16ceopr1SKQ3NKvWm05etNlMfRRSVJIUUUUwJs0maKSpIsKTSZoNNppDSHk8UhPFIelB6UDSGE8imuaU9RTXqkUkJmlU802lXrTZTRJmgmkpKkmwuaKSinYdifIoyKMikyKgzFJ4puRSkikyKY0hSeKCRigkYpCRigEMJGRTXI9aUkZFI5FUi0NyPWlU89abkUqkZpspkmeKTPvRkUZFSQGR6mikyKKY7D8n0oyfSm76N9KxNhST6UmT6Uhek3807DSHknHSkJOOlIX4oL8UWHYaScjimuT6UF+RTXeqSKSDJ9KVSc9KZvpVfmm0U0S5PpSZPpSb+KTfU2JsOyfSim76Kdh2JD0pKdtNG01NyLjTSd6cVOKTac00xpgehpD0pxU4pCpxRcdyM9RTXp5U5FNdTVJlJkdOHWjBpVU5p3KbF7UU7acUm00ibjaKdg0UDuWaKKSsjAD0pKUnim0xocelIelB6Gg9KAGHrTXpT1FNeqRaG05etNpV61TKZJSUdqCakgKKTNFMZNRRRUGYh6UlFFNDQp6GkP3aKKBjD1pr0UVSLQynDrRRTKY/tSGiipIEooopjP//Z", - "image/png": "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", + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDjKWilr50+QFNNXrTjTV60CJhRRRUkDGpncVI1M/iFNFIc39Kj71I1M7mhDQClpKWmAUUGikAuaM03aaNppgSE01TzQVNNVTmgRYBozTdpo2mpIsDGo88inMppm05FNFIex/lTM805lNM2nNCGhwNLmmBTS7TTGOzRTSpooAlxRRRUkDiKavWnGmr1oEiYCjFAoqSBjCmY5FSNTO4plIVhTcc09qZ3NCGgoopRTACKKDRSAj3Uu6o+fSl59KqxdiUtTVbmmnPpSLnPSiwrFjdS7qjGfSl59KmxFgZqZu5FDZ9KZzkcU0ikiVmpm7mhs+namc56UJDSJN1G6mDPpRz6U7DsSbqKYc+lFArC7vpRu+lR0vPrRYqxIW+lIrc9qafrSLnNCQrFgN9KXd9KZz60c+tTYiyBm9hTN3I4FDZpnORTSKSJWb6Uzdz2obNM5z1ppDSJN30o3UwZpefWiwWH7vYUUzmiiwWExRS0UxikU1RzTzTV60AS0UUuKkzGNTMcintTO4potDmpmOae1N7mhAhKXFApaBiGilooASjNFFADjTVPNFFNCJgaM0UVBA1qZnkUUVRSHN2pneiihDQZpaKKAAmiiigD/9k=", + "image/png": "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", "text/plain": [ "" ] @@ -529,8 +529,8 @@ }, { "data": { - "image/jpeg": "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", - "image/png": "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", + "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -542,13 +542,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "5 RP TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 0.0 0.7775982022285461\n" + "5 RP TSImage(shape:torch.Size([8, 24, 100, 100])) torch.float32 0.0 0.8106333613395691\n" ] }, { "data": { - "image/jpeg": "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", - "image/png": "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", + "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -572,6 +572,7 @@ "for i, (bt, btn) in enumerate(zip(bts, btns)):\n", " dls = TSDataLoaders.from_dsets(dsets.train, dsets.valid, bs=8, batch_tfms=bt)\n", " test_eq(dls.vars, 3 if i <2 else X.shape[1])\n", + " test_eq(dls.vars, 3 if i <2 else X.shape[1])\n", " test_eq(dls.len, (100,100))\n", " xb, yb = dls.train.one_batch()\n", " print(i, btn, xb, xb.dtype, xb.min(), xb.max())\n", @@ -614,9 +615,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/012_data.image.ipynb saved at 2023-11-13 08:08:02\n", + "/Users/nacho/notebooks/tsai/nbs/012_data.image.ipynb saved at 2024-02-10 22:40:32\n", "Correct notebook to script conversion! 😃\n", - "Monday 13/11/23 08:08:05 CET\n" + "Saturday 10/02/24 22:40:35 CET\n" ] }, { diff --git a/nbs/022_tslearner.ipynb b/nbs/022_tslearner.ipynb index 3c52eeaac..2061edb91 100644 --- a/nbs/022_tslearner.ipynb +++ b/nbs/022_tslearner.ipynb @@ -124,10 +124,10 @@ "source": [ "#|export\n", "class TSClassifier(Learner):\n", - " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, \n", - " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, \n", + " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None,\n", + " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None,\n", " o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None,\n", - " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, \n", + " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True,\n", " weights=None, partial_n=None, vocab=None,\n", " train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None,\n", " shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None,\n", @@ -138,28 +138,28 @@ " # Seed\n", " if seed is not None:\n", " set_seed(seed, reproducible=True)\n", - " \n", + "\n", " # Batch size\n", " if batch_size is not None:\n", " bs = batch_size\n", "\n", " # DataLoaders\n", " dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, vocab=vocab,\n", - " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, \n", + " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n,\n", " device=device, shuffle_train=shuffle_train, drop_last=drop_last)\n", - " \n", + "\n", " if loss_func is None:\n", " if hasattr(dls, 'loss_func'): loss_func = dls.loss_func\n", " elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat()\n", " elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func\n", " else: loss_func = CrossEntropyLossFlat()\n", - " \n", + "\n", " # Model\n", - " if isinstance(arch, nn.Module): \n", + " if isinstance(arch, nn.Module):\n", " model = arch\n", - " if arch_config: \n", + " if arch_config:\n", " warnings.warn(\"You have passed arch_config to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", - " if init is not None: \n", + " if init is not None:\n", " warnings.warn(\"You have passed init to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", " else:\n", " if init is True:\n", @@ -174,32 +174,32 @@ " # else:\n", " # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", - " model = build_ts_model(arch, dls=dls, \n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, \n", + " model = build_ts_model(arch, dls=dls,\n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs,\n", " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs,\n", - " patch_len=patch_len, patch_stride=patch_stride, \n", - " fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, \n", + " patch_len=patch_len, patch_stride=patch_stride,\n", + " fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn,\n", " device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", " try:\n", " setattr(model, \"__name__\", arch.__name__)\n", " except:\n", " setattr(model, \"__name__\", arch.__class__.__name__)\n", - " \n", + "\n", " if hasattr(model, \"backbone\") and hasattr(model, \"head\"):\n", " splitter = ts_splitter\n", - " \n", + "\n", " if pipelines is not None:\n", " pipelines = listify(pipelines)\n", " setattr(self, \"pipelines\", pipelines)\n", - " \n", + "\n", " super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter,\n", " model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms)\n", "\n", " if hasattr(self, \"recorder\"):\n", " self.recorder.train_metrics = train_metrics\n", " if splits is None or not hasattr(splits[0], \"__len__\") or len(splits) == 1 or \\\n", - " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))): \n", + " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))):\n", " self.recorder.valid_metrics = False\n", " else:\n", " self.recorder.valid_metrics = valid_metrics" @@ -265,11 +265,11 @@ " \n", " \n", " 0\n", - " 1.344642\n", - " 0.400000\n", - " 1.338323\n", - " 0.400000\n", - " 00:05\n", + " 1.446255\n", + " 0.266667\n", + " 1.403359\n", + " 0.300000\n", + " 00:00\n", " \n", " \n", "" @@ -287,7 +287,7 @@ "X, y, splits = get_classification_data('OliveOil', split_data=False)\n", "tfms = [None, TSClassification()]\n", "batch_tfms = [TSStandardize(by_sample=True)]\n", - "learn = TSClassifier(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms, metrics=accuracy, arch=InceptionTimePlus, arch_config=dict(fc_dropout=.5), \n", + "learn = TSClassifier(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms, metrics=accuracy, arch=InceptionTimePlus, arch_config=dict(fc_dropout=.5),\n", " train_metrics=True)\n", "learn.fit_one_cycle(1)" ] @@ -339,9 +339,9 @@ " \n", " \n", " 0\n", - " 1.418544\n", - " 0.333333\n", - " 00:03\n", + " 1.286023\n", + " 0.400000\n", + " 00:00\n", " \n", " \n", "" @@ -360,7 +360,7 @@ "splits = (splits[0], None)\n", "tfms = [None, TSClassification()]\n", "batch_tfms = [TSStandardize(by_sample=True)]\n", - "learn = TSClassifier(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms, metrics=accuracy, arch=InceptionTimePlus, arch_config=dict(fc_dropout=.5), \n", + "learn = TSClassifier(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms, metrics=accuracy, arch=InceptionTimePlus, arch_config=dict(fc_dropout=.5),\n", " train_metrics=True)\n", "learn.fit_one_cycle(1)" ] @@ -369,15 +369,7 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[W NNPACK.cpp:64] Could not initialize NNPACK! Reason: Unsupported hardware.\n" - ] - } - ], + "outputs": [], "source": [ "num_classes = 5\n", "X = torch.rand(8, 2, 50)\n", @@ -389,12 +381,12 @@ "for arch in all_arch_names:\n", " if not \"plus\" in arch.lower(): continue\n", " try:\n", - " learn = TSClassifier(X, y, splits=splits, arch=arch, metrics=accuracy, vocab=vocab)\n", + " learn = TSClassifier(X, y, splits=splits, arch=arch, metrics=accuracy, vocab=vocab, device=default_device())\n", " with ContextManagers([learn.no_bar(), learn.no_logging()]):\n", " learn.fit_one_cycle(1, 1e-3)\n", " del learn\n", " gc.collect()\n", - " except Exception as e: \n", + " except Exception as e:\n", " fail_test.append(arch)\n", " print(arch, e)\n", "\n", @@ -477,11 +469,11 @@ "source": [ "#|export\n", "class TSRegressor(Learner):\n", - " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, \n", - " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, \n", + " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None,\n", + " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None,\n", " o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None,\n", - " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, \n", - " weights=None, partial_n=None, \n", + " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True,\n", + " weights=None, partial_n=None,\n", " train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None,\n", " shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None,\n", " arch=None, arch_config={}, pretrained=False, weights_path=None, exclude_head=True, cut=-1, init=None,\n", @@ -491,15 +483,15 @@ " # Seed\n", " if seed is not None:\n", " set_seed(seed, reproducible=True)\n", - " \n", - " \n", + "\n", + "\n", " # Batch size\n", " if batch_size is not None:\n", " bs = batch_size\n", "\n", " # DataLoaders\n", - " dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, \n", - " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, \n", + " dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace,\n", + " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n,\n", " device=device, shuffle_train=shuffle_train, drop_last=drop_last)\n", "\n", " if loss_func is None:\n", @@ -507,13 +499,13 @@ " elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat()\n", " elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func\n", " else: loss_func = MSELossFlat()\n", - " \n", + "\n", " # Model\n", - " if isinstance(arch, nn.Module): \n", + " if isinstance(arch, nn.Module):\n", " model = arch\n", - " if arch_config: \n", + " if arch_config:\n", " warnings.warn(\"You have passed arch_config to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", - " if init is not None: \n", + " if init is not None:\n", " warnings.warn(\"You have passed init to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", " else:\n", " if init is True:\n", @@ -528,10 +520,10 @@ " # else:\n", " # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", - " model = build_ts_model(arch, dls=dls, \n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, \n", + " model = build_ts_model(arch, dls=dls,\n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs,\n", " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs,\n", - " patch_len=patch_len, patch_stride=patch_stride, \n", + " patch_len=patch_len, patch_stride=patch_stride,\n", " fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn,\n", " device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", @@ -539,21 +531,21 @@ " setattr(model, \"__name__\", arch.__name__)\n", " except:\n", " setattr(model, \"__name__\", arch.__class__.__name__)\n", - " \n", + "\n", " if hasattr(model, \"backbone\") and hasattr(model, \"head\"):\n", " splitter = ts_splitter\n", - " \n", + "\n", " if pipelines is not None:\n", " pipelines = listify(pipelines)\n", " setattr(self, \"pipelines\", pipelines)\n", "\n", " super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter,\n", - " model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms) \n", - " \n", + " model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms)\n", + "\n", " if hasattr(self, \"recorder\"):\n", " self.recorder.train_metrics = train_metrics\n", " if splits is None or not hasattr(splits[0], \"__len__\") or len(splits) == 1 or \\\n", - " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))): \n", + " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))):\n", " self.recorder.valid_metrics = False\n", " else:\n", " self.recorder.valid_metrics = valid_metrics" @@ -608,11 +600,11 @@ " \n", " \n", " 0\n", - " 210.839890\n", - " 13.863370\n", - " 204.376419\n", - " 13.876650\n", - " 00:03\n", + " 221.239578\n", + " 14.241582\n", + " 208.787231\n", + " 14.034328\n", + " 00:00\n", " \n", " \n", "" @@ -628,8 +620,10 @@ "source": [ "X, y, splits = get_regression_data('AppliancesEnergy', split_data=False)\n", "if X is not None: # This is to prevent a test fail when the data server is not available\n", + " X = X.astype('float32')\n", + " y = y.astype('float32')\n", " batch_tfms = [TSStandardize()]\n", - " learn = TSRegressor(X, y, splits=splits, batch_tfms=batch_tfms, arch=None, metrics=mae, bs=512, train_metrics=True)\n", + " learn = TSRegressor(X, y, splits=splits, batch_tfms=batch_tfms, arch=None, metrics=mae, bs=512, train_metrics=True, device=default_device())\n", " learn.fit_one_cycle(1, 1e-4)" ] }, @@ -706,13 +700,13 @@ "metadata": {}, "outputs": [], "source": [ - "#|export \n", + "#|export\n", "class TSForecaster(Learner):\n", - " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, \n", - " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, \n", + " def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None,\n", + " s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None,\n", " o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None,\n", - " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, \n", - " weights=None, partial_n=None, \n", + " patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True,\n", + " weights=None, partial_n=None,\n", " train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None,\n", " shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None,\n", " arch=None, arch_config={}, pretrained=False, weights_path=None, exclude_head=True, cut=-1, init=None,\n", @@ -722,28 +716,28 @@ " # Seed\n", " if seed is not None:\n", " set_seed(seed, reproducible=True)\n", - " \n", + "\n", " # Batch size\n", " if batch_size is not None:\n", " bs = batch_size\n", "\n", " # DataLoaders\n", - " dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, \n", - " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, \n", + " dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace,\n", + " path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n,\n", " device=device, shuffle_train=shuffle_train, drop_last=drop_last)\n", - " \n", + "\n", " if loss_func is None:\n", " if hasattr(dls, 'loss_func'): loss_func = dls.loss_func\n", " elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat()\n", " elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func\n", " else: loss_func = MSELossFlat()\n", - " \n", + "\n", " # Model\n", - " if isinstance(arch, nn.Module): \n", + " if isinstance(arch, nn.Module):\n", " model = arch\n", - " if arch_config: \n", + " if arch_config:\n", " warnings.warn(\"You have passed arch_config to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", - " if init is not None: \n", + " if init is not None:\n", " warnings.warn(\"You have passed init to a model that is already intantiated. It will not have any effect.\", UserWarning)\n", " else:\n", " if init is True:\n", @@ -758,10 +752,10 @@ " # else:\n", " # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", - " model = build_ts_model(arch, dls=dls, \n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, \n", + " model = build_ts_model(arch, dls=dls,\n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs,\n", " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs,\n", - " patch_len=patch_len, patch_stride=patch_stride, \n", + " patch_len=patch_len, patch_stride=patch_stride,\n", " fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn,\n", " device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path,\n", " exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config)\n", @@ -769,21 +763,21 @@ " setattr(model, \"__name__\", arch.__name__)\n", " except:\n", " setattr(model, \"__name__\", arch.__class__.__name__)\n", - " \n", + "\n", " if hasattr(model, \"backbone\") and hasattr(model, \"head\"):\n", " splitter = ts_splitter\n", - " \n", + "\n", " if pipelines is not None:\n", " pipelines = listify(pipelines)\n", " setattr(self, \"pipelines\", pipelines)\n", "\n", " super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter,\n", " model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms)\n", - " \n", + "\n", " if hasattr(self, \"recorder\"):\n", " self.recorder.train_metrics = train_metrics\n", " if splits is None or not hasattr(splits[0], \"__len__\") or len(splits) == 1 or \\\n", - " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))): \n", + " (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], \"__len__\"))):\n", " self.recorder.valid_metrics = False\n", " else:\n", " self.recorder.valid_metrics = valid_metrics" @@ -814,7 +808,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAABZcAAABoCAYAAACNDM73AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAeWklEQVR4nO3deVTVdf7H8dcF4SIgIIosJouIVG6pKVFqOipgjaNYk5Yzo05p5jaOaf3sFIvjZGl1HE3L8ox0ps1sNK3cTTQL11xyyVxAcMQ0ExE3ts/vjxlv3kThGlwEn49zvufc+/1+vp/P+3Pt3b2++/T5WowxRgAAAAAAAAAAOMClugMAAAAAAAAAANQ8FJcBAAAAAAAAAA6juAwAAAAAAAAAcBjFZQAAAAAAAACAwyguAwAAAAAAAAAcRnEZAAAAAAAAAOAwissAAAAAAAAAAIdRXAYAAAAAAAAAOIziMgAAAAAAAADAYRSXAQAAqkhaWposFouysrJs57p27aquXbtW+lgpKSmyWCx258LDwzV48OBKH+uXsrKyZLFYlJaWZjs3ePBgeXt7V/nYl1ksFqWkpDhtPAAAAAAUlwEAAGy+/fZbPfzwwwoLC5OHh4caN26snj17aubMmVU25rFjx5SSkqIdO3ZU2RiOWLp06U1bpL2ZYwMAAABuRXWqOwAAAICbwddff61u3bopNDRUQ4cOVVBQkHJycrRx40b94x//0OjRoytlnJUrV9q9P3bsmFJTUxUeHq677rqrUsa4bP/+/XJxcWwtwdKlSzVr1iyHirhhYWG6cOGC3NzcHIzQMdeL7cKFC6pTh5+2AAAAgDPxCxwAAEDS3//+d/n6+mrLli3y8/Ozu3bixIlKG8fd3b3S+iqP1Wqt0v6Li4tVWloqd3d3eXh4VOlY5anu8QEAAIBbEdtiAAAASDp06JBatGhxVWFZkho1amT33mKxaNSoUXrvvfcUHR0tDw8PtW/fXuvXry93nCv3XE5PT1eHDh0kSUOGDJHFYrlq7+KybNiwQR06dJCHh4ciIyM1Z86cMtv9cs/loqIipaamKioqSh4eHmrQoIE6deqkVatWSfrvPsmzZs2yzfHyIf28r/Irr7yi6dOnKzIyUlarVXv37i1zz+XLDh8+rPj4eHl5eSkkJESTJk2SMcZ2PT09XRaLRenp6Xb3/bLP68V2+dwvVzRv375dvXr1ko+Pj7y9vdW9e3dt3LjRrs3lfbG/+uorjRs3TgEBAfLy8lJiYqJOnjxZ9h8AAAAAAEmsXAYAAJD0360dMjIytHv3brVs2bLc9uvWrdP8+fM1ZswYWa1WzZ49WwkJCdq8eXOF7pekO+64Q5MmTVJSUpKGDRumzp07S5Luvffea97z7bffKi4uTgEBAUpJSVFxcbGSk5MVGBhY7ngpKSmaMmWKnnjiCXXs2FH5+fnaunWrvvnmG/Xs2VNPPvmkjh07plWrVulf//pXmX3MmzdPFy9e1LBhw2S1WuXv76/S0tIy25aUlCghIUH33HOPpk6dquXLlys5OVnFxcWaNGlSBT6hn1Uktivt2bNHnTt3lo+Pj5555hm5ublpzpw56tq1q9atW6eYmBi79qNHj1b9+vWVnJysrKwsTZ8+XaNGjdL8+fMdihMAAAC4lVBcBgAAkDR+/Hj16tVLd911lzp27KjOnTure/fu6tatW5l7Ce/evVtbt25V+/btJUkDBgxQdHS0kpKStHDhwgqNGRgYqF69eikpKUmxsbH6wx/+UO49SUlJMsboyy+/VGhoqCTpoYceUqtWrcq99/PPP9cDDzygt956q8zrsbGxat68uVatWnXNWI4ePaqDBw8qICDAdi4rK6vMthcvXlRCQoJmzJghSRoxYoR69+6tl19+WWPGjFHDhg3LjdmR2K70/PPPq6ioSBs2bFDTpk0lSX/6058UHR2tZ555RuvWrbNr36BBA61cudK2Grq0tFQzZszQmTNn5OvrW+E4AQAAgFsJ22IAAABI6tmzpzIyMvS73/1OO3fu1NSpUxUfH6/GjRtryZIlV7WPjY21FZYlKTQ0VH369NGKFStUUlJSJTGWlJRoxYoV6tu3r62wLP13BXR8fHy59/v5+WnPnj06cODADcfw0EMP2RWWyzNq1Cjb68vbiRQWFmr16tU3HEN5SkpKtHLlSvXt29dWWJak4OBgPfbYY9qwYYPy8/Pt7hk2bJjdNhudO3dWSUmJjhw5UmVxAgAAADUdxWUAAID/6dChgxYuXKjTp09r8+bNmjhxos6ePauHH35Ye/futWsbFRV11f3NmzfX+fPnq2yv3pMnT+rChQtljh0dHV3u/ZMmTVJeXp6aN2+uVq1aacKECdq1a5dDMURERFS4rYuLi11xV/rvZyRde7VzZTh58qTOnz9f5mdyxx13qLS0VDk5OXbnryzWS1L9+vUlSadPn66yOAEAAICajuIyAADAL7i7u6tDhw568cUX9cYbb6ioqEgLFiyo7rB+tS5duujQoUP65z//qZYtW2ru3Llq166d5s6dW+E+6tatW6kxXbla+EpVtfr7WlxdXcs8f+XDBwEAAADYo7gMAABwHXfffbckKTc31+58WVtLfP/99/L09HRo24hrFVfLEhAQoLp165Y59v79+yvUh7+/v4YMGaIPPvhAOTk5at26tVJSUm4onvKUlpbq8OHDdue+//57SVJ4eLikn1cI5+Xl2bUrazuKisYWEBAgT0/PMj+T7777Ti4uLmrSpEmF+gIAAABwbRSXAQAAJK1du7bMVapLly6VdPW2ExkZGfrmm29s73NycrR48WLFxcVdcxVsWby8vCRdXVwti6urq+Lj4/XJJ58oOzvbdn7fvn1asWJFufefOnXK7r23t7eaNWumS5cu3VA8FfH666/bXhtj9Prrr8vNzU3du3eXJIWFhcnV1VXr16+3u2/27NlX9VXR2FxdXRUXF6fFixfbbb/xww8/6P3331enTp3k4+NzgzMCAAAAcFmd6g4AAADgZjB69GidP39eiYmJuv3221VYWKivv/5a8+fPV3h4uIYMGWLXvmXLloqPj9eYMWNktVptxdDU1FSHxo2MjJSfn5/efPNN1atXT15eXoqJibnm3sapqalavny5OnfurBEjRqi4uFgzZ85UixYtyt0/+c4771TXrl3Vvn17+fv7a+vWrfr444/tHrp3+SGFY8aMUXx8vFxdXTVgwACH5nSZh4eHli9frkGDBikmJkbLli3T559/rueee862utvX11e///3vNXPmTFksFkVGRuqzzz7TiRMnrurPkdgmT56sVatWqVOnThoxYoTq1KmjOXPm6NKlS5o6deoNzQcAAACAPYrLAAAAkl555RUtWLBAS5cu1VtvvaXCwkKFhoZqxIgRev755+Xn52fX/v7771dsbKxSU1OVnZ2tO++8U2lpaWrdurVD47q5uemdd97RxIkTNXz4cBUXF2vevHnXLC63bt1aK1as0Lhx45SUlKTbbrtNqampys3NLbe4PGbMGC1ZskQrV67UpUuXFBYWpsmTJ2vChAm2Nv369dPo0aP14Ycf6t1335Ux5oaLy66urlq+fLmeeuopTZgwQfXq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", + "image/png": "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nz9f5mdyxx13qLS0VDk5OXbnryzWS1L9+vUlSadPn66yOAEAAICajuIyAADAL7i7u6tDhw568cUX9cYbb6ioqEgLFiyo7rB+tS5duujQoUP65z//qZYtW2ru3Llq166d5s6dW+E+6tatW6kxXbla+EpVtfr7WlxdXcs8f+XDBwEAAADYo7gMAABwHXfffbckKTc31+58WVtLfP/99/L09HRo24hrFVfLEhAQoLp165Y59v79+yvUh7+/v4YMGaIPPvhAOTk5at26tVJSUm4onvKUlpbq8OHDdue+//57SVJ4eLikn1cI5+Xl2bUrazuKisYWEBAgT0/PMj+T7777Ti4uLmrSpEmF+gIAAABwbRSXAQAAJK1du7bMVapLly6VdPW2ExkZGfrmm29s73NycrR48WLFxcVdcxVsWby8vCRdXVwti6urq+Lj4/XJJ58oOzvbdn7fvn1asWJFufefOnXK7r23t7eaNWumS5cu3VA8FfH666/bXhtj9Prrr8vNzU3du3eXJIWFhcnV1VXr16+3u2/27NlX9VXR2FxdXRUXF6fFixfbbb/xww8/6P3331enTp3k4+NzgzMCAAAAcFmd6g4AAADgZjB69GidP39eiYmJuv3221VYWKivv/5a8+fPV3h4uIYMGWLXvmXLloqPj9eYMWNktVptxdDU1FSHxo2MjJSfn5/efPNN1atXT15eXoqJibnm3sapqalavny5OnfurBEjRqi4uFgzZ85UixYtyt0/+c4771TXrl3Vvn17+fv7a+vWrfr444/tHrp3+SGFY8aMUXx8vFxdXTVgwACH5nSZh4eHli9frkGDBikmJkbLli3T559/rueee862utvX11e///3vNXPmTFksFkVGRuqzzz7TiRMnrurPkdgmT56sVatWqVOnThoxYoTq1KmjOXPm6NKlS5o6deoNzQcAAACAPYrLAAAAkl555RUtWLBAS5cu1VtvvaXCwkKFhoZqxIgRev755+Xn52fX/v7771dsbKxSU1OVnZ2tO++8U2lpaWrdurVD47q5uemdd97RxIkTNXz4cBUXF2vevHnXLC63bt1aK1as0Lhx45SUlKTbbrtNqampys3NLbe4PGbMGC1ZskQrV67UpUuXFBYWpsmTJ2vChAm2Nv369dPo0aP14Ycf6t1335Ux5oaLy66urlq+fLmeeuopTZgwQfXq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", "text/plain": [ "
" ] @@ -866,11 +860,11 @@ " \n", " \n", " 0\n", - " 4276.123047\n", - " 47.886517\n", - " 8040.518066\n", - " 75.065742\n", - " 00:04\n", + " 4616.225098\n", + " 53.340523\n", + " 7969.317871\n", + " 74.670258\n", + " 00:00\n", " \n", " \n", "" @@ -887,10 +881,11 @@ "ts = get_forecasting_time_series('Sunspots')\n", "if ts is not None: # This is to prevent a test fail when the data server is not available\n", " X, y = SlidingWindowSplitter(60, horizon=1)(ts)\n", + " X, y = X.astype('float32'), y.astype('float32')\n", " splits = TSSplitter(235)(y)\n", " batch_tfms = [TSStandardize(by_var=True)]\n", - " learn = TSForecaster(X, y, splits=splits, batch_tfms=batch_tfms, arch=None, arch_config=dict(fc_dropout=.5), metrics=mae, bs=512, \n", - " partial_n=.1, train_metrics=True)\n", + " learn = TSForecaster(X, y, splits=splits, batch_tfms=batch_tfms, arch=None, arch_config=dict(fc_dropout=.5), metrics=mae, bs=512,\n", + " partial_n=.1, train_metrics=True, device=default_device())\n", " learn.fit_one_cycle(1)" ] }, @@ -908,10 +903,10 @@ "for arch in all_arch_names:\n", " if not \"plus\" in arch.lower(): continue\n", " try:\n", - " fcst = TSForecaster(X, y, splits=splits, arch=arch, metrics=mse)\n", + " fcst = TSForecaster(X, y, splits=splits, arch=arch, metrics=mse, device=default_device())\n", " with ContextManagers([fcst.no_bar(), fcst.no_logging()]):\n", " fcst.fit_one_cycle(1, 1e-3)\n", - " except Exception as e: \n", + " except Exception as e:\n", " fail_test.append(arch)\n", " print(arch, e)\n", "\n", @@ -937,9 +932,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/022_tslearner.ipynb saved at 2023-07-03 21:01:36\n", + "/Users/nacho/notebooks/tsai/nbs/022_tslearner.ipynb saved at 2024-02-11 13:56:13\n", "Correct notebook to script conversion! 😃\n", - "Monday 03/07/23 21:01:39 CEST\n" + "Sunday 11/02/24 13:56:16 CET\n" ] }, { diff --git a/nbs/026_callback.noisy_student.ipynb b/nbs/026_callback.noisy_student.ipynb index 8a6ee14ef..f36da27f0 100644 --- a/nbs/026_callback.noisy_student.ipynb +++ b/nbs/026_callback.noisy_student.ipynb @@ -43,7 +43,7 @@ "metadata": {}, "outputs": [], "source": [ - "#|export \n", + "#|export\n", "from tsai.imports import *\n", "from tsai.utils import *\n", "from tsai.data.preprocessing import *\n", @@ -61,26 +61,26 @@ "#|export\n", "\n", "# This is an unofficial implementation of noisy student based on:\n", - "# Xie, Q., Luong, M. T., Hovy, E., & Le, Q. V. (2020). Self-training with noisy student improves imagenet classification. \n", + "# Xie, Q., Luong, M. T., Hovy, E., & Le, Q. V. (2020). Self-training with noisy student improves imagenet classification.\n", "# In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (pp. 10687-10698).\n", "# Official tensorflow implementation available in https://github.com/google-research/noisystudent\n", "\n", "\n", "class NoisyStudent(Callback):\n", - " \"\"\"A callback to implement the Noisy Student approach. In the original paper this was used in combination with noise: \n", + " \"\"\"A callback to implement the Noisy Student approach. In the original paper this was used in combination with noise:\n", " - stochastic depth: .8\n", " - RandAugment: N=2, M=27\n", " - dropout: .5\n", - " \n", + "\n", " Steps:\n", " 1. Build the dl you will use as a teacher\n", " 2. Create dl2 with the pseudolabels (either soft or hard preds)\n", " 3. Pass any required batch_tfms to the callback\n", - " \n", + "\n", " \"\"\"\n", - " \n", - " def __init__(self, dl2:DataLoader, bs:Optional[int]=None, l2pl_ratio:int=1, batch_tfms:Optional[list]=None, do_setup:bool=True, \n", - " pseudolabel_sample_weight:float=1., verbose=False): \n", + "\n", + " def __init__(self, dl2:DataLoader, bs:Optional[int]=None, l2pl_ratio:int=1, batch_tfms:Optional[list]=None, do_setup:bool=True,\n", + " pseudolabel_sample_weight:float=1., verbose=False):\n", " r'''\n", " Args:\n", " dl2: dataloader with the pseudolabels\n", @@ -90,18 +90,18 @@ " do_setup: perform a transform setup on the labeled dataset.\n", " pseudolabel_sample_weight: weight of each pseudolabel sample relative to the labeled one of the loss.\n", " '''\n", - " \n", + "\n", " self.dl2, self.bs, self.l2pl_ratio, self.batch_tfms, self.do_setup, self.verbose = dl2, bs, l2pl_ratio, batch_tfms, do_setup, verbose\n", " self.pl_sw = pseudolabel_sample_weight\n", - " \n", + "\n", " def before_fit(self):\n", " if self.batch_tfms is None: self.batch_tfms = self.dls.train.after_batch\n", " self.old_bt = self.dls.train.after_batch # Remove and store dl.train.batch_tfms\n", " self.old_bs = self.dls.train.bs\n", - " self.dls.train.after_batch = noop \n", + " self.dls.train.after_batch = noop\n", "\n", " if self.do_setup and self.batch_tfms:\n", - " for bt in self.batch_tfms: \n", + " for bt in self.batch_tfms:\n", " bt.setup(self.dls.train)\n", "\n", " if self.bs is None: self.bs = self.dls.train.bs\n", @@ -111,12 +111,12 @@ " pv(f'labels / pseudolabels per training batch : {self.dls.train.bs} / {self.dl2.bs}', self.verbose)\n", " rel_weight = (self.dls.train.bs/self.dl2.bs) * (len(self.dl2.dataset)/len(self.dls.train.dataset))\n", " pv(f'relative labeled/ pseudolabel sample weight in dataset: {rel_weight:.1f}', self.verbose)\n", - " \n", + "\n", " self.dl2iter = iter(self.dl2)\n", - " \n", + "\n", " self.old_loss_func = self.learn.loss_func\n", " self.learn.loss_func = self.loss\n", - " \n", + "\n", " def before_batch(self):\n", " if self.training:\n", " X, y = self.x, self.y\n", @@ -125,26 +125,26 @@ " self.dl2iter = iter(self.dl2)\n", " X2, y2 = next(self.dl2iter)\n", " if y.ndim == 1 and y2.ndim == 2: y = torch.eye(self.learn.dls.c, device=y.device)[y]\n", - " \n", + "\n", " X_comb, y_comb = concat(X, X2), concat(y, y2)\n", - " \n", - " if self.batch_tfms is not None: \n", + "\n", + " if self.batch_tfms is not None:\n", " X_comb = compose_tfms(X_comb, self.batch_tfms, split_idx=0)\n", " y_comb = compose_tfms(y_comb, self.batch_tfms, split_idx=0)\n", " self.learn.xb = (X_comb,)\n", " self.learn.yb = (y_comb,)\n", " pv(f'\\nX: {X.shape} X2: {X2.shape} X_comb: {X_comb.shape}', self.verbose)\n", " pv(f'y: {y.shape} y2: {y2.shape} y_comb: {y_comb.shape}', self.verbose)\n", - " \n", - " def loss(self, output, target): \n", + "\n", + " def loss(self, output, target):\n", " if target.ndim == 2: _, target = target.max(dim=1)\n", - " if self.training and self.pl_sw != 1: \n", + " if self.training and self.pl_sw != 1:\n", " loss = (1 - self.pl_sw) * self.old_loss_func(output[:self.dls.train.bs], target[:self.dls.train.bs])\n", " loss += self.pl_sw * self.old_loss_func(output[self.dls.train.bs:], target[self.dls.train.bs:])\n", - " return loss \n", - " else: \n", + " return loss\n", + " else:\n", " return self.old_loss_func(output, target)\n", - " \n", + "\n", " def after_fit(self):\n", " self.dls.train.after_batch = self.old_bt\n", " self.learn.loss_func = self.old_loss_func\n", @@ -170,7 +170,8 @@ "outputs": [], "source": [ "dsid = 'NATOPS'\n", - "X, y, splits = get_UCR_data(dsid, return_split=False)" + "X, y, splits = get_UCR_data(dsid, return_split=False)\n", + "X = X.astype(np.float32)" ] }, { @@ -229,10 +230,10 @@ " \n", " \n", " 0\n", - " 1.884984\n", - " 1.809759\n", - " 0.166667\n", - " 00:06\n", + " 1.782144\n", + " 1.758471\n", + " 0.250000\n", + " 00:00\n", " \n", " \n", "" @@ -249,7 +250,7 @@ "output_type": "stream", "text": [ "\n", - "X: torch.Size([171, 24, 51]) X2: torch.Size([85, 24, 51]) X_comb: torch.Size([256, 24, 58])\n", + "X: torch.Size([171, 24, 51]) X2: torch.Size([85, 24, 51]) X_comb: torch.Size([256, 24, 41])\n", "y: torch.Size([171]) y2: torch.Size([85]) y_comb: torch.Size([256])\n" ] } @@ -323,10 +324,10 @@ " \n", " \n", " 0\n", - " 1.894964\n", - " 1.814770\n", - " 0.177778\n", - " 00:03\n", + " 1.898401\n", + " 1.841182\n", + " 0.155556\n", + " 00:00\n", " \n", " \n", "" @@ -343,7 +344,7 @@ "output_type": "stream", "text": [ "\n", - "X: torch.Size([171, 24, 51]) X2: torch.Size([85, 24, 51]) X_comb: torch.Size([256, 24, 45])\n", + "X: torch.Size([171, 24, 51]) X2: torch.Size([85, 24, 51]) X_comb: torch.Size([256, 24, 51])\n", "y: torch.Size([171, 6]) y2: torch.Size([85, 6]) y_comb: torch.Size([256, 6])\n" ] } @@ -353,6 +354,7 @@ "soft_preds = False\n", "\n", "pseudolabels = ToNumpyCategory()(y) if soft_preds else OneHot()(y)\n", + "pseudolabels = pseudolabels.astype(np.float32)\n", "dsets2 = TSDatasets(pseudolabeled_data, pseudolabels)\n", "dl2 = TSDataLoader(dsets2, num_workers=0)\n", "noisy_student_cb = NoisyStudent(dl2, bs=256, l2pl_ratio=2, verbose=True)\n", @@ -380,9 +382,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/026_callback.noisy_student.ipynb saved at 2023-01-21 14:30:23\n", + "/Users/nacho/notebooks/tsai/nbs/026_callback.noisy_student.ipynb saved at 2024-02-10 21:53:24\n", "Correct notebook to script conversion! 😃\n", - "Saturday 21/01/23 14:30:25 CET\n" + "Saturday 10/02/24 21:53:27 CET\n" ] }, { diff --git a/nbs/076_models.MultiRocketPlus.ipynb b/nbs/076_models.MultiRocketPlus.ipynb index 45f4af317..fe07d6d5e 100644 --- a/nbs/076_models.MultiRocketPlus.ipynb +++ b/nbs/076_models.MultiRocketPlus.ipynb @@ -68,17 +68,26 @@ "outputs": [], "source": [ "#| export\n", - "def _LPVV(o_pos, dim=2):\n", - " \"Longest stretch of positive values (-1, 1)\" \n", - " shape = list(o_pos.shape)\n", - " shape[dim] = 1\n", - " o_pos = torch.cat([torch.zeros(shape, device=o_pos.device), o_pos], dim)\n", - " o_arange_shape = [1] * o_pos.ndim\n", - " o_arange_shape[dim] = -1\n", - " o_arange = torch.arange(o_pos.shape[dim], device=o_pos.device).reshape(o_arange_shape)\n", - " o_pos = torch.where(o_pos == 1, 0, o_arange)\n", - " o_pos = o_pos.cummax(dim).values\n", - " return ((o_arange - o_pos).max(dim).values / (o_pos.shape[dim] - 1)) * 2 - 1\n", + "def _LPVV(o, dim=2):\n", + " \"Longest stretch of positive values along a dimension(-1, 1)\"\n", + "\n", + " seq_len = o.shape[dim]\n", + " binary_tensor = (o > 0).float()\n", + "\n", + " diff = torch.cat([torch.ones_like(binary_tensor.narrow(dim, 0, 1)),\n", + " binary_tensor.narrow(dim, 1, seq_len-1) - binary_tensor.narrow(dim, 0, seq_len-1)], dim=dim)\n", + "\n", + " groups = (diff > 0).cumsum(dim)\n", + "\n", + " # Ensure groups are within valid index bounds\n", + " groups = groups * binary_tensor.long()\n", + " valid_groups = groups.where(groups < binary_tensor.size(dim), torch.tensor(0, device=groups.device))\n", + "\n", + " counts = torch.zeros_like(binary_tensor).scatter_add_(dim, valid_groups, binary_tensor)\n", + "\n", + " longest_stretch = counts.max(dim)[0]\n", + "\n", + " return torch.nan_to_num(2 * (longest_stretch / seq_len) - 1)\n", "\n", "def _MPV(o, dim=2):\n", " \"Mean of Positive Values (any positive value)\"\n", @@ -107,6 +116,150 @@ " return (o_pos).float().mean(dim) * 2 - 1" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tsai.imports import default_device" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[[[ 0.5644, -0.0509, -0.0390, 0.4091],\n", + " [ 0.0517, -0.1471, 0.6458, 0.5593],\n", + " [ 0.4516, -0.0821, 0.1271, 0.0592],\n", + " [ 0.4151, 0.4376, 0.0763, 0.3780],\n", + " [ 0.2653, -0.1817, 0.0156, 0.4993]],\n", + "\n", + " [[-0.0779, 0.0858, 0.1982, 0.3224],\n", + " [ 0.1130, 0.0714, -0.1779, 0.5360],\n", + " [-0.1848, -0.2270, -0.0925, -0.1217],\n", + " [ 0.2820, -0.0205, -0.2777, 0.3755],\n", + " [-0.2490, 0.2613, 0.4237, 0.4534]],\n", + "\n", + " [[-0.0162, 0.6368, 0.0016, 0.1467],\n", + " [ 0.6035, -0.1365, 0.6930, 0.6943],\n", + " [ 0.2790, 0.3818, -0.0731, 0.0167],\n", + " [ 0.6442, 0.3443, 0.4829, -0.0944],\n", + " [ 0.2932, 0.6952, 0.5541, 0.5946]]],\n", + "\n", + "\n", + " [[[ 0.6757, 0.5740, 0.3071, 0.4400],\n", + " [-0.2344, -0.1056, 0.4773, 0.2432],\n", + " [ 0.2595, -0.1528, -0.0866, 0.6201],\n", + " [ 0.0657, 0.1220, 0.4849, 0.4254],\n", + " [ 0.3399, -0.1609, 0.3465, 0.2389]],\n", + "\n", + " [[-0.0765, 0.0516, 0.0028, 0.4381],\n", + " [ 0.5212, -0.2781, -0.0896, -0.0301],\n", + " [ 0.6857, 0.3583, 0.5869, 0.3418],\n", + " [ 0.3002, 0.5135, 0.6011, 0.6499],\n", + " [-0.2807, -0.2888, 0.3965, 0.6585]],\n", + "\n", + " [[-0.1368, 0.6677, 0.1439, 0.1434],\n", + " [-0.1820, 0.1041, -0.1211, 0.6103],\n", + " [ 0.5808, 0.4588, 0.4572, 0.3713],\n", + " [ 0.2389, -0.1392, 0.1371, -0.1570],\n", + " [ 0.2840, 0.1214, -0.0059, 0.5064]]]], device='mps:0')\n", + "tensor([[[ 1.0000, -0.6000, 0.6000, 1.0000],\n", + " [-0.6000, -0.2000, -0.6000, -0.2000],\n", + " [ 0.6000, 0.2000, -0.2000, 0.2000]],\n", + "\n", + " [[ 0.2000, -0.6000, -0.2000, 1.0000],\n", + " [ 0.2000, -0.2000, 0.2000, 0.2000],\n", + " [ 0.2000, 0.2000, -0.2000, 0.2000]]], device='mps:0')\n" + ] + } + ], + "source": [ + "o = torch.rand(2, 3, 5, 4).to(default_device()) - .3\n", + "print(o)\n", + "\n", + "output = _LPVV(o, dim=2)\n", + "print(output) # Should print: torch.Size([2, 3, 4])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[[0.3496, 0.4376, 0.2162, 0.3810],\n", + " [0.1975, 0.1395, 0.3109, 0.4218],\n", + " [0.4550, 0.5145, 0.4329, 0.3631]],\n", + "\n", + " [[0.3352, 0.3480, 0.4040, 0.3935],\n", + " [0.5023, 0.3078, 0.3968, 0.5221],\n", + " [0.3679, 0.3380, 0.2460, 0.4079]]], device='mps:0')\n" + ] + } + ], + "source": [ + "output = _MPV(o, dim=2)\n", + "print(output) # Should print: torch.Size([2, 3, 4])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[[ 1.0000, -0.0270, 0.9138, 1.0000],\n", + " [-0.1286, 0.2568, 0.0630, 0.8654],\n", + " [ 0.9823, 0.8756, 0.9190, 0.8779]],\n", + "\n", + " [[ 0.7024, 0.2482, 0.8983, 1.0000],\n", + " [ 0.6168, 0.2392, 0.8931, 0.9715],\n", + " [ 0.5517, 0.8133, 0.7065, 0.8244]]], device='mps:0')\n" + ] + } + ], + "source": [ + "output = _RSPV(o, dim=2)\n", + "print(output) # Should print: torch.Size([2, 3, 4])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[[-0.3007, -1.0097, -0.6697, -0.2381],\n", + " [-1.0466, -0.9316, -0.9705, -0.3738],\n", + " [-0.2786, -0.2314, -0.3366, -0.4569]],\n", + "\n", + " [[-0.5574, -0.8893, -0.3883, -0.2130],\n", + " [-0.5401, -0.8574, -0.4009, -0.1767],\n", + " [-0.6861, -0.5149, -0.7555, -0.4102]]], device='mps:0')\n" + ] + } + ], + "source": [ + "output = _PPV(o, dim=2)\n", + "print(output) # Should print: torch.Size([2, 3, 4])" + ] + }, { "cell_type": "code", "execution_count": null, @@ -119,7 +272,7 @@ "\n", " def __init__(self, c_in, seq_len, num_features=10_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=9, max_num_kernels=84, diff=False):\n", " super(MultiRocketFeaturesPlus, self).__init__()\n", - " \n", + "\n", " self.c_in, self.seq_len = c_in, seq_len\n", " self.kernel_size, self.max_num_channels = kernel_size, max_num_channels\n", "\n", @@ -147,7 +300,7 @@ " self.register_buffer('prefit', torch.BoolTensor([False]))\n", "\n", " def forward(self, x):\n", - " \n", + "\n", " _features = []\n", " for i, (dilation, padding) in enumerate(zip(self.dilations, self.padding)):\n", " _padding1 = i % 2\n", @@ -191,11 +344,11 @@ " num_samples = X.shape[0]\n", " if chunksize is None:\n", " chunksize = min(num_samples, self.num_dilations * self.num_kernels)\n", - " else: \n", + " else:\n", " chunksize = min(num_samples, chunksize)\n", " idxs = np.random.choice(num_samples, chunksize, False)\n", " self.fitting = True\n", - " if isinstance(X, np.ndarray): \n", + " if isinstance(X, np.ndarray):\n", " self(torch.from_numpy(X[idxs]).to(self.kernels.device))\n", " else:\n", " self(X[idxs].to(self.kernels.device))\n", @@ -292,12 +445,12 @@ "metadata": {}, "outputs": [], "source": [ - "#| export \n", + "#| export\n", "class MultiRocketBackbonePlus(nn.Module):\n", " def __init__(self, c_in, seq_len, num_features=50_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=None, max_num_kernels=84, use_diff=True):\n", " super(MultiRocketBackbonePlus, self).__init__()\n", - " \n", - " num_features_per_branch = num_features // (1 + use_diff) \n", + "\n", + " num_features_per_branch = num_features // (1 + use_diff)\n", " self.branch_x = MultiRocketFeaturesPlus(c_in, seq_len, num_features=num_features_per_branch, max_dilations_per_kernel=max_dilations_per_kernel,\n", " kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels)\n", " if use_diff:\n", @@ -308,7 +461,7 @@ " else:\n", " self.num_features = self.branch_x.num_features * 4\n", " self.use_diff = use_diff\n", - " \n", + "\n", " def forward(self, x):\n", " if self.use_diff:\n", " x_features = self.branch_x(x)\n", @@ -339,7 +492,7 @@ "\n", " # Head\n", " self.head_nf = num_features\n", - " if custom_head is not None: \n", + " if custom_head is not None:\n", " if isinstance(custom_head, nn.Module): head = custom_head\n", " else: head = custom_head(self.head_nf, c_out, 1)\n", " elif d is not None:\n", @@ -362,6 +515,15 @@ "MultiRocket = MultiRocketPlus" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tsai.imports import default_device" + ] + }, { "cell_type": "code", "execution_count": null, @@ -379,10 +541,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = MultiRocketPlus(5, 3, 20, d=None, use_diff=True)\n", + "model = MultiRocketPlus(5, 3, 20, d=None, use_diff=True).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -405,10 +567,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = MultiRocketPlus(5, 3, 20, d=None, use_diff=False)\n", + "model = MultiRocketPlus(5, 3, 20, d=None, use_diff=False).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -431,10 +593,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 5, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 5, 20)).to(default_device())\n", "\n", - "model = MultiRocketPlus(5, 3, 20, d=20, use_diff=True)\n", + "model = MultiRocketPlus(5, 3, 20, d=20, use_diff=True).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 20, 3)\n", "output.shape" @@ -459,9 +621,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/076_models.MultiRocketPlus.ipynb couldn't be saved automatically. You should save it manually 👋\n", + "/Users/nacho/notebooks/tsai/nbs/076_models.MultiRocketPlus.ipynb saved at 2024-02-11 10:53:13\n", "Correct notebook to script conversion! 😃\n", - "Thursday 08/06/23 19:37:58 CEST\n" + "Sunday 11/02/24 10:53:16 CET\n" ] }, { diff --git a/nbs/077_models.multimodal.ipynb b/nbs/077_models.multimodal.ipynb index c77d326bb..0794bcfc5 100644 --- a/nbs/077_models.multimodal.ipynb +++ b/nbs/077_models.multimodal.ipynb @@ -81,7 +81,7 @@ " return [idx]\n", " elif isinstance(idx, list):\n", " return idx\n", - " \n", + "\n", "\n", "def get_o_cont_idxs(c_in, s_cat_idxs=None, s_cont_idxs=None, o_cat_idxs=None):\n", " \"Calculate the indices of the observed continuous features.\"\n", @@ -132,7 +132,7 @@ "source": [ "#| export\n", "class TensorSplitter(nn.Module):\n", - " def __init__(self, \n", + " def __init__(self,\n", " s_cat_idxs:list=None, # list of indices for static categorical variables\n", " s_cont_idxs:list=None, # list of indices for static continuous variables\n", " o_cat_idxs:list=None, # list of indices for observed categorical variables\n", @@ -223,7 +223,7 @@ "k_cont_idxs = None\n", "horizon=None\n", "input_tensor = torch.randn(bs, 6, 10) # 3D input tensor\n", - "splitter = TensorSplitter(s_cat_idxs=s_cat_idxs, s_cont_idxs=s_cont_idxs, \n", + "splitter = TensorSplitter(s_cat_idxs=s_cat_idxs, s_cont_idxs=s_cont_idxs,\n", " o_cat_idxs=o_cat_idxs, o_cont_idxs=o_cont_idxs)\n", "slices = splitter(input_tensor)\n", "for i, slice_tensor in enumerate(slices):\n", @@ -259,13 +259,12 @@ "k_cont_idxs = 8\n", "horizon=3\n", "input_tensor = torch.randn(4, 9, 10) # 3D input tensor\n", - "splitter = TensorSplitter(s_cat_idxs=s_cat_idxs, s_cont_idxs=s_cont_idxs, \n", + "splitter = TensorSplitter(s_cat_idxs=s_cat_idxs, s_cont_idxs=s_cont_idxs,\n", " o_cat_idxs=o_cat_idxs, o_cont_idxs=o_cont_idxs,\n", " k_cat_idxs=k_cat_idxs, k_cont_idxs=k_cont_idxs, horizon=horizon)\n", "slices = splitter(input_tensor)\n", "for i, slice_tensor in enumerate(slices):\n", - " print(f\"Slice {i+1}: {slice_tensor.shape} {slice_tensor.dtype}\")\n", - " " + " print(f\"Slice {i+1}: {slice_tensor.shape} {slice_tensor.dtype}\")\n" ] }, { @@ -277,7 +276,7 @@ "#| export\n", "class Embeddings(nn.Module):\n", " \"Embedding layers for each categorical variable in a 2D or 3D tensor\"\n", - " def __init__(self, \n", + " def __init__(self,\n", " n_embeddings:list, # List of num_embeddings for each categorical variable\n", " embedding_dims:list=None, # List of embedding dimensions for each categorical variable\n", " padding_idx:int=0, # Embedding padding_idx\n", @@ -292,9 +291,9 @@ " embedding_dims = [emb_sz_rule(s) if s is None else s for s in n_embeddings]\n", " assert len(n_embeddings) == len(embedding_dims)\n", " self.embedding_dims = sum(embedding_dims)\n", - " self.embedding_layers = nn.ModuleList([nn.Sequential(nn.Embedding(n,d,padding_idx=padding_idx, **kwargs), \n", + " self.embedding_layers = nn.ModuleList([nn.Sequential(nn.Embedding(n,d,padding_idx=padding_idx, **kwargs),\n", " nn.Dropout(embed_dropout)) for n,d in zip(n_embeddings, embedding_dims)])\n", - " \n", + "\n", " def forward(self, x):\n", " if x.ndim == 2:\n", " return torch.cat([e(x[:,i].long()) for i,e in enumerate(self.embedding_layers)],1)\n", @@ -451,7 +450,7 @@ "# **kwargs\n", "# ):\n", "# super().__init__()\n", - " \n", + "\n", "# # attributes\n", "# c_in = c_in or dls.vars\n", "# c_out = c_out or dls.c\n", @@ -465,7 +464,7 @@ "# self.splitter = TensorSplitter(s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs)\n", "# s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs = self.splitter.s_cat_idxs, self.splitter.s_cont_idxs, self.splitter.o_cat_idxs, self.splitter.o_cont_idxs\n", "# assert c_in == sum([len(s_cat_idxs), len(s_cont_idxs), len(o_cat_idxs), len(o_cont_idxs)])\n", - " \n", + "\n", "# # embeddings\n", "# self.s_embeddings = Embeddings(s_cat_embeddings, s_cat_embedding_dims)\n", "# self.o_embeddings = Embeddings(o_cat_embeddings, o_cat_embedding_dims)\n", @@ -479,7 +478,7 @@ "# else:\n", "# self.patch_encoder = nn.Identity()\n", "# c_mult = 1\n", - " \n", + "\n", "# # backbone\n", "# n_s_features = len(s_cont_idxs) + self.s_embeddings.embedding_dims\n", "# n_o_features = (len(o_cont_idxs) + self.o_embeddings.embedding_dims) * c_mult\n", @@ -492,13 +491,13 @@ "# o_model = build_ts_model(arch, c_in=n_o_features, c_out=c_out, seq_len=seq_len, d=d, **kwargs)\n", "# assert hasattr(o_model, \"backbone\"), \"the selected arch must have a backbone\"\n", "# o_backbone = getattr(o_model, \"backbone\")\n", - " \n", + "\n", "# # head\n", "# o_head_nf = output_size_calculator(o_backbone, n_o_features, seq_len)[0]\n", "# s_head_nf = s_backbone.head_nf\n", "# self.backbone = nn.ModuleList([o_backbone, s_backbone])\n", "# self.head_nf = o_head_nf + s_head_nf\n", - "# if custom_head is not None: \n", + "# if custom_head is not None:\n", "# if isinstance(custom_head, nn.Module): self.head = custom_head\n", "# else:self. head = custom_head(self.head_nf, c_out, seq_len, d=d)\n", "# else:\n", @@ -518,10 +517,10 @@ "# # contatenate static and observed features\n", "# s_x = torch.cat([s_cat, s_cont], 1)\n", "# o_x = torch.cat([o_cat, o_cont], 1)\n", - " \n", + "\n", "# # patch encoder\n", "# o_x = self.patch_encoder(o_x)\n", - " \n", + "\n", "# # pass static and observed features through their respective backbones\n", "# for i,(b,xi) in enumerate(zip(self.backbone, [o_x, s_x])):\n", "# if i == 0:\n", @@ -530,7 +529,7 @@ "# x = x[..., None]\n", "# else:\n", "# x = torch.cat([x, b(xi)[..., None].repeat(1, 1, x.shape[-1])], 1)\n", - " \n", + "\n", "# # head\n", "# x = self.head(x)\n", "# return x" @@ -586,10 +585,10 @@ "# c_out=c_out,\n", "# seq_len=seq_len,\n", "# d=d,\n", - "# s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - "# s_cont_idxs=s_cont_idxs, \n", - "# o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, \n", - "# o_cont_idxs=o_cont_idxs, \n", + "# s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + "# s_cont_idxs=s_cont_idxs,\n", + "# o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims,\n", + "# o_cont_idxs=o_cont_idxs,\n", "# patch_len=patch_len,\n", "# patch_stride=patch_stride,\n", "# )\n", @@ -705,7 +704,7 @@ " **kwargs\n", " ):\n", " super().__init__()\n", - " \n", + "\n", " # attributes\n", " c_in = c_in or dls.vars\n", " seq_len = seq_len or dls.len\n", @@ -718,7 +717,7 @@ " self.splitter = TensorSplitter(s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs)\n", " s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs = self.splitter.s_cat_idxs, self.splitter.s_cont_idxs, self.splitter.o_cat_idxs, self.splitter.o_cont_idxs\n", " assert c_in == sum([len(s_cat_idxs), len(s_cont_idxs), len(o_cat_idxs), len(o_cont_idxs)])\n", - " \n", + "\n", " # embeddings\n", " self.s_embeddings = Embeddings(s_cat_embeddings, s_cat_embedding_dims) if s_cat_idxs else nn.Identity()\n", " self.o_embeddings = Embeddings(o_cat_embeddings, o_cat_embedding_dims) if o_cat_idxs else nn.Identity()\n", @@ -732,7 +731,7 @@ " else:\n", " self.patch_encoder = nn.Identity()\n", " c_mult = 1\n", - " \n", + "\n", " # backbone\n", " n_s_features = len(s_cont_idxs) + (self.s_embeddings.embedding_dims if s_cat_idxs else 0)\n", " n_o_features = (len(o_cont_idxs) + (self.o_embeddings.embedding_dims if o_cat_idxs else 0)) * c_mult\n", @@ -763,10 +762,10 @@ "\n", " # contatenate observed features\n", " o_x = torch.cat([o_cat, o_cont], 1)\n", - " \n", + "\n", " # patch encoder\n", " o_x = self.patch_encoder(o_x)\n", - " \n", + "\n", " # pass static and observed features through their respective backbones\n", " o_x = self.o_backbone(o_x)\n", "\n", @@ -808,12 +807,12 @@ " custom_head=None, # custom head to replace the default head\n", " **kwargs\n", " ):\n", - " \n", + "\n", " # create backbone\n", - " backbone = MultInputBackboneWrapper(arch, c_in=c_in, seq_len=seq_len, d=d, dls=dls, s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - " s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, \n", + " backbone = MultInputBackboneWrapper(arch, c_in=c_in, seq_len=seq_len, d=d, dls=dls, s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + " s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs,\n", " patch_len=patch_len, patch_stride=patch_stride, fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, **kwargs)\n", - " \n", + "\n", " # create head\n", " self.head_nf = backbone.head_nf\n", " self.c_out = c_out\n", @@ -823,8 +822,7 @@ " else: head = custom_head(self.head_nf, c_out, seq_len, d=d)\n", " else:\n", " head = nn.Linear(self.head_nf, c_out)\n", - " super().__init__(OrderedDict([('backbone', backbone), ('head', head)]))\n", - " " + " super().__init__(OrderedDict([('backbone', backbone), ('head', head)]))\n" ] }, { @@ -845,34 +843,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "arch: InceptionTimePlus, patch_len: None, patch_stride: None\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[W NNPACK.cpp:64] Could not initialize NNPACK! Reason: Unsupported hardware.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "arch: InceptionTimePlus, patch_len: None, patch_stride: None\n", "arch: , patch_len: None, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: None, patch_stride: None\n", + "arch: TSiTPlus, patch_len: None, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: None\n", "arch: , patch_len: 5, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: None\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 1\n", "arch: , patch_len: 5, patch_stride: 1\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 1\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 1\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 3\n", "arch: , patch_len: 5, patch_stride: 3\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 3\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 3\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 5\n", "arch: , patch_len: 5, patch_stride: 5\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 5\n" + "arch: TSiTPlus, patch_len: 5, patch_stride: 5\n" ] } ], @@ -906,7 +891,7 @@ "patch_lens = [None, 5, 5, 5, 5]\n", "patch_strides = [None, None, 1, 3, 5]\n", "for patch_len, patch_stride in zip(patch_lens, patch_strides):\n", - " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"MultiRocketPlus\"]:\n", + " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"TSiTPlus\"]:\n", " print(f\"arch: {arch}, patch_len: {patch_len}, patch_stride: {patch_stride}\")\n", "\n", " model = MultInputWrapper(\n", @@ -915,10 +900,10 @@ " c_out=c_out,\n", " seq_len=seq_len,\n", " d=d,\n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - " s_cont_idxs=s_cont_idxs, \n", - " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, \n", - " o_cont_idxs=o_cont_idxs, \n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + " s_cont_idxs=s_cont_idxs,\n", + " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims,\n", + " o_cont_idxs=o_cont_idxs,\n", " patch_len=patch_len,\n", " patch_stride=patch_stride,\n", " fusion_layers=fusion_layers,\n", @@ -938,19 +923,19 @@ "text": [ "arch: InceptionTimePlus, patch_len: None, patch_stride: None\n", "arch: , patch_len: None, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: None, patch_stride: None\n", + "arch: TSiTPlus, patch_len: None, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: None\n", "arch: , patch_len: 5, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: None\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 1\n", "arch: , patch_len: 5, patch_stride: 1\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 1\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 1\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 3\n", "arch: , patch_len: 5, patch_stride: 3\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 3\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 3\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 5\n", "arch: , patch_len: 5, patch_stride: 5\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 5\n" + "arch: TSiTPlus, patch_len: 5, patch_stride: 5\n" ] } ], @@ -984,7 +969,7 @@ "patch_lens = [None, 5, 5, 5, 5]\n", "patch_strides = [None, None, 1, 3, 5]\n", "for patch_len, patch_stride in zip(patch_lens, patch_strides):\n", - " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"MultiRocketPlus\"]:\n", + " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"TSiTPlus\"]:\n", " print(f\"arch: {arch}, patch_len: {patch_len}, patch_stride: {patch_stride}\")\n", "\n", " model = MultInputWrapper(\n", @@ -993,10 +978,10 @@ " c_out=c_out,\n", " seq_len=seq_len,\n", " d=d,\n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - " s_cont_idxs=s_cont_idxs, \n", - " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, \n", - " o_cont_idxs=o_cont_idxs, \n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + " s_cont_idxs=s_cont_idxs,\n", + " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims,\n", + " o_cont_idxs=o_cont_idxs,\n", " patch_len=patch_len,\n", " patch_stride=patch_stride,\n", " fusion_layers=fusion_layers,\n", @@ -1016,19 +1001,19 @@ "text": [ "arch: InceptionTimePlus, patch_len: None, patch_stride: None\n", "arch: , patch_len: None, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: None, patch_stride: None\n", + "arch: TSiTPlus, patch_len: None, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: None\n", "arch: , patch_len: 5, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: None\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 1\n", "arch: , patch_len: 5, patch_stride: 1\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 1\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 1\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 3\n", "arch: , patch_len: 5, patch_stride: 3\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 3\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 3\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 5\n", "arch: , patch_len: 5, patch_stride: 5\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 5\n" + "arch: TSiTPlus, patch_len: 5, patch_stride: 5\n" ] } ], @@ -1062,7 +1047,7 @@ "patch_lens = [None, 5, 5, 5, 5]\n", "patch_strides = [None, None, 1, 3, 5]\n", "for patch_len, patch_stride in zip(patch_lens, patch_strides):\n", - " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"MultiRocketPlus\"]:\n", + " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"TSiTPlus\"]:\n", " print(f\"arch: {arch}, patch_len: {patch_len}, patch_stride: {patch_stride}\")\n", "\n", " model = MultInputWrapper(\n", @@ -1071,10 +1056,10 @@ " c_out=c_out,\n", " seq_len=seq_len,\n", " d=d,\n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - " s_cont_idxs=s_cont_idxs, \n", - " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, \n", - " o_cont_idxs=o_cont_idxs, \n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + " s_cont_idxs=s_cont_idxs,\n", + " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims,\n", + " o_cont_idxs=o_cont_idxs,\n", " patch_len=patch_len,\n", " patch_stride=patch_stride,\n", " fusion_layers=fusion_layers,\n", @@ -1094,19 +1079,19 @@ "text": [ "arch: InceptionTimePlus, patch_len: None, patch_stride: None\n", "arch: , patch_len: None, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: None, patch_stride: None\n", + "arch: TSiTPlus, patch_len: None, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: None\n", "arch: , patch_len: 5, patch_stride: None\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: None\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: None\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 1\n", "arch: , patch_len: 5, patch_stride: 1\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 1\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 1\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 3\n", "arch: , patch_len: 5, patch_stride: 3\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 3\n", + "arch: TSiTPlus, patch_len: 5, patch_stride: 3\n", "arch: InceptionTimePlus, patch_len: 5, patch_stride: 5\n", "arch: , patch_len: 5, patch_stride: 5\n", - "arch: MultiRocketPlus, patch_len: 5, patch_stride: 5\n" + "arch: TSiTPlus, patch_len: 5, patch_stride: 5\n" ] } ], @@ -1140,7 +1125,7 @@ "patch_lens = [None, 5, 5, 5, 5]\n", "patch_strides = [None, None, 1, 3, 5]\n", "for patch_len, patch_stride in zip(patch_lens, patch_strides):\n", - " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"MultiRocketPlus\"]:\n", + " for arch in [\"InceptionTimePlus\", InceptionTimePlus, \"TSiTPlus\"]:\n", " print(f\"arch: {arch}, patch_len: {patch_len}, patch_stride: {patch_stride}\")\n", "\n", " model = MultInputWrapper(\n", @@ -1149,10 +1134,10 @@ " c_out=c_out,\n", " seq_len=seq_len,\n", " d=d,\n", - " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, \n", - " s_cont_idxs=s_cont_idxs, \n", - " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, \n", - " o_cont_idxs=o_cont_idxs, \n", + " s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims,\n", + " s_cont_idxs=s_cont_idxs,\n", + " o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims,\n", + " o_cont_idxs=o_cont_idxs,\n", " patch_len=patch_len,\n", " patch_stride=patch_stride,\n", " fusion_layers=fusion_layers,\n", @@ -1180,9 +1165,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/077_models.multimodal.ipynb saved at 2023-07-01 18:56:31\n", + "/Users/nacho/notebooks/tsai/nbs/077_models.multimodal.ipynb saved at 2024-02-10 21:58:47\n", "Correct notebook to script conversion! 😃\n", - "Saturday 01/07/23 18:56:33 CEST\n" + "Saturday 10/02/24 21:58:50 CET\n" ] }, { diff --git a/nbs/079_models.HydraPlus.ipynb b/nbs/079_models.HydraPlus.ipynb index f7f983e13..d843472e5 100644 --- a/nbs/079_models.HydraPlus.ipynb +++ b/nbs/079_models.HydraPlus.ipynb @@ -70,7 +70,7 @@ "\n", " max_exponent = np.log2((seq_len - 1) / (9 - 1)) # kernel length = 9\n", "\n", - " self.dilations = 2 ** torch.arange(int(max_exponent) + 1)\n", + " self.dilations = 2 ** torch.arange(int(max_exponent) + 1, device=device)\n", " self.num_dilations = len(self.dilations)\n", "\n", " self.paddings = torch.div((9 - 1) * self.dilations, 2, rounding_mode = \"floor\").int()\n", @@ -79,14 +79,14 @@ " divisor = 2 if self.g > 1 else 1\n", " _g = g // divisor\n", " self._g = _g\n", - " self.W = [self.normalize(torch.randn(divisor, k * _g, 1, 9).to(device=device)) for _ in range(self.num_dilations)]\n", + " self.W = [self.normalize(torch.randn(divisor, k * _g, 1, 9)).to(device=device) for _ in range(self.num_dilations)]\n", + "\n", "\n", - " \n", " # combine c_in // 2 channels (2 < n < max_c_in)\n", " c_in_per = np.clip(c_in // 2, 2, max_c_in)\n", - " self.I = [torch.randint(0, c_in, (divisor, _g, c_in_per)).to(device=device) for _ in range(self.num_dilations)]\n", + " self.I = [torch.randint(0, c_in, (divisor, _g, c_in_per), device=device) for _ in range(self.num_dilations)]\n", "\n", - " # clip values \n", + " # clip values\n", " self.clip = clip\n", "\n", " self.device = device\n", @@ -132,7 +132,6 @@ " # diff_index == 0 -> X\n", " # diff_index == 1 -> diff(X)\n", " for diff_index in range(min(2, self.g)):\n", - "\n", " _Z = F.conv1d(X[:, self.I[dilation_index][diff_index]].sum(2) if diff_index == 0 else diff_X[:, self.I[dilation_index][diff_index]].sum(2),\n", " self.W[dilation_index][diff_index], dilation = d, padding = p, groups = self._g).view(bs, self._g, self.k, -1)\n", "\n", @@ -165,7 +164,7 @@ "#| export\n", "class HydraPlus(nn.Sequential):\n", "\n", - " def __init__(self, \n", + " def __init__(self,\n", " c_in:int, # num of channels in input\n", " c_out:int, # num of channels in output\n", " seq_len:int, # sequence length\n", @@ -173,7 +172,7 @@ " k:int=8, # number of kernels per group\n", " g:int=64, # number of groups\n", " max_c_in:int=8, # max number of channels per group\n", - " clip:bool=True, # clip values >= 0 \n", + " clip:bool=True, # clip values >= 0\n", " use_bn:bool=True, # use batch norm\n", " fc_dropout:float=0., # dropout probability\n", " custom_head:Any=None, # optional custom head as a torch.nn.Module or Callable\n", @@ -189,7 +188,7 @@ "\n", " # Head\n", " self.head_nf = num_features\n", - " if custom_head is not None: \n", + " if custom_head is not None:\n", " if isinstance(custom_head, nn.Module): head = custom_head\n", " else: head = custom_head(self.head_nf, c_out, 1)\n", " elif d is not None:\n", @@ -229,10 +228,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = HydraPlus(5, 3, 20, d=None)\n", + "model = HydraPlus(5, 3, 20, d=None).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -255,10 +254,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = HydraPlus(5, 3, 20, d=None, use_diff=False)\n", + "model = HydraPlus(5, 3, 20, d=None, use_diff=False).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -281,10 +280,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 5, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 5, 20)).to(default_device())\n", "\n", - "model = HydraPlus(5, 3, 20, d=20, use_diff=True)\n", + "model = HydraPlus(5, 3, 20, d=20, use_diff=True).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 20, 3)\n", "output.shape" @@ -309,9 +308,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/079_models.HydraPlus.ipynb saved at 2023-07-03 11:59:53\n", + "/Users/nacho/notebooks/tsai/nbs/079_models.HydraPlus.ipynb saved at 2024-02-10 22:16:56\n", "Correct notebook to script conversion! 😃\n", - "Monday 03/07/23 11:59:56 CEST\n" + "Saturday 10/02/24 22:16:59 CET\n" ] }, { diff --git a/nbs/080_models.HydraMultiRocketPlus.ipynb b/nbs/080_models.HydraMultiRocketPlus.ipynb index 9138694bb..c3cbab9c8 100644 --- a/nbs/080_models.HydraMultiRocketPlus.ipynb +++ b/nbs/080_models.HydraMultiRocketPlus.ipynb @@ -62,7 +62,7 @@ "#| export\n", "class HydraMultiRocketBackbonePlus(nn.Module):\n", "\n", - " def __init__(self, c_in, c_out, seq_len, d=None, \n", + " def __init__(self, c_in, c_out, seq_len, d=None,\n", " k = 8, g = 64, max_c_in = 8, clip=True,\n", " num_features=50_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=None, max_num_kernels=84,\n", " use_bn=True, fc_dropout=0, custom_head=None, zero_init=True, use_diff=True, device=default_device()):\n", @@ -71,12 +71,12 @@ "\n", " self.hydra = HydraBackbonePlus(c_in, c_out, seq_len, k=k, g=g, max_c_in=max_c_in, clip=clip, device=device, zero_init=zero_init)\n", " self.multirocket = MultiRocketBackbonePlus(c_in, seq_len, num_features=num_features, max_dilations_per_kernel=max_dilations_per_kernel,\n", - " kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels, \n", + " kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels,\n", " use_diff=use_diff)\n", "\n", " self.num_features = self.hydra.num_features + self.multirocket.num_features\n", - " \n", - " \n", + "\n", + "\n", " # transform in batches of *batch_size*\n", " def batch(self, X, split=None, batch_size=256):\n", " bs = X.shape[0]\n", @@ -93,8 +93,8 @@ " for i, batch in enumerate(batches):\n", " Z.append(self(X[batch]))\n", " return torch.cat(Z)\n", - " \n", - " \n", + "\n", + "\n", " def forward(self, x):\n", " x = torch.cat([self.hydra(x), self.multirocket(x)], -1)\n", " return x" @@ -109,7 +109,7 @@ "#| export\n", "class HydraMultiRocketPlus(nn.Sequential):\n", "\n", - " def __init__(self, \n", + " def __init__(self,\n", " c_in:int, # num of channels in input\n", " c_out:int, # num of channels in output\n", " seq_len:int, # sequence length\n", @@ -134,13 +134,13 @@ " backbone = HydraMultiRocketBackbonePlus(c_in, c_out, seq_len, k=k, g=g, max_c_in=max_c_in, clip=clip, device=device, zero_init=zero_init,\n", " num_features=num_features, max_dilations_per_kernel=max_dilations_per_kernel,\n", " kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels, use_diff=use_diff)\n", - " \n", + "\n", " num_features = backbone.num_features\n", "\n", "\n", " # Head\n", " self.head_nf = num_features\n", - " if custom_head is not None: \n", + " if custom_head is not None:\n", " if isinstance(custom_head, nn.Module): head = custom_head\n", " else: head = custom_head(self.head_nf, c_out, 1)\n", " elif d is not None:\n", @@ -180,10 +180,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = HydraMultiRocketPlus(5, 3, 20, d=None)\n", + "model = HydraMultiRocketPlus(5, 3, 20, d=None).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -206,10 +206,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 20)).to(default_device())\n", "\n", - "model = HydraMultiRocketPlus(5, 3, 20, d=None, use_diff=False)\n", + "model = HydraMultiRocketPlus(5, 3, 20, d=None, use_diff=False).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 3)\n", "output.shape" @@ -232,10 +232,10 @@ } ], "source": [ - "xb = torch.randn(16, 5, 20)\n", - "yb = torch.randint(0, 3, (16, 5, 20))\n", + "xb = torch.randn(16, 5, 20).to(default_device())\n", + "yb = torch.randint(0, 3, (16, 5, 20)).to(default_device())\n", "\n", - "model = HydraMultiRocketPlus(5, 3, 20, d=20, use_diff=True)\n", + "model = HydraMultiRocketPlus(5, 3, 20, d=20, use_diff=True).to(default_device())\n", "output = model(xb)\n", "assert output.shape == (16, 20, 3)\n", "output.shape" @@ -260,9 +260,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "/Users/nacho/notebooks/tsai/nbs/080_models.HydraMultiRocketPlus.ipynb saved at 2023-07-03 11:59:30\n", + "/Users/nacho/notebooks/tsai/nbs/080_models.HydraMultiRocketPlus.ipynb saved at 2024-02-11 00:38:41\n", "Correct notebook to script conversion! 😃\n", - "Monday 03/07/23 11:59:33 CEST\n" + "Sunday 11/02/24 00:38:44 CET\n" ] }, { diff --git a/nbs/models/test.pth b/nbs/models/test.pth index 6c6c5ccde..7cd3f29a0 100644 Binary files a/nbs/models/test.pth and b/nbs/models/test.pth differ diff --git a/settings.ini b/settings.ini index eb8be1a40..de67cd5aa 100644 --- a/settings.ini +++ b/settings.ini @@ -15,10 +15,10 @@ status = 4 min_python = 3.8 audience = Developers language = English -requirements = fastai>=2.7.13 pyts>=0.12.0 imbalanced-learn>=0.11.0 psutil>=5.4.8 scikit-learn>=1.2 -pip_requirements = torch>=1.10,<2.2 +requirements = fastai>=2.7.14 pyts>=0.12.0 imbalanced-learn>=0.11.0 psutil>=5.4.8 scikit-learn>=1.2 +pip_requirements = torch>=1.10,<2.3 conda_user = timeseriesAI -conda_requirements = pytorch>=1.10,<2.2 +conda_requirements = pytorch>=1.10,<2.3 extra_requirements = sktime>=0.10.1 tsfresh>=0.18.0 PyWavelets>=1.1.1 nbformat>=5.1.3 dev_requirements = nbdev>2 ipykernel>6 console_scripts = nb2py=tsai.export:nb2py @@ -35,8 +35,8 @@ recursive = True clean_ids = True black_formatting = False readme_nb = index.ipynb -allowed_metadata_keys = -allowed_cell_metadata_keys = +allowed_metadata_keys = +allowed_cell_metadata_keys = jupyter_hooks = True clear_all = False put_version_in_init = True diff --git a/tsai/_modidx.py b/tsai/_modidx.py index c33b9839b..d03728542 100644 --- a/tsai/_modidx.py +++ b/tsai/_modidx.py @@ -1231,7 +1231,9 @@ 'tsai/data/transforms.py'), 'tsai.data.transforms.random_curve_generator': ( 'data.transforms.html#random_curve_generator', 'tsai/data/transforms.py'), - 'tsai.data.transforms.self_mask': ('data.transforms.html#self_mask', 'tsai/data/transforms.py')}, + 'tsai.data.transforms.self_mask': ('data.transforms.html#self_mask', 'tsai/data/transforms.py'), + 'tsai.data.transforms.test_interpolate': ( 'data.transforms.html#test_interpolate', + 'tsai/data/transforms.py')}, 'tsai.data.unwindowed': { 'tsai.data.unwindowed.TSUnwindowedDataset': ( 'data.unwindowed.html#tsunwindoweddataset', 'tsai/data/unwindowed.py'), 'tsai.data.unwindowed.TSUnwindowedDataset.__getitem__': ( 'data.unwindowed.html#tsunwindoweddataset.__getitem__', diff --git a/tsai/callback/noisy_student.py b/tsai/callback/noisy_student.py index fc9af1723..8013c8035 100644 --- a/tsai/callback/noisy_student.py +++ b/tsai/callback/noisy_student.py @@ -17,26 +17,26 @@ # %% ../../nbs/026_callback.noisy_student.ipynb 5 # This is an unofficial implementation of noisy student based on: -# Xie, Q., Luong, M. T., Hovy, E., & Le, Q. V. (2020). Self-training with noisy student improves imagenet classification. +# Xie, Q., Luong, M. T., Hovy, E., & Le, Q. V. (2020). Self-training with noisy student improves imagenet classification. # In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (pp. 10687-10698). # Official tensorflow implementation available in https://github.com/google-research/noisystudent class NoisyStudent(Callback): - """A callback to implement the Noisy Student approach. In the original paper this was used in combination with noise: + """A callback to implement the Noisy Student approach. In the original paper this was used in combination with noise: - stochastic depth: .8 - RandAugment: N=2, M=27 - dropout: .5 - + Steps: 1. Build the dl you will use as a teacher 2. Create dl2 with the pseudolabels (either soft or hard preds) 3. Pass any required batch_tfms to the callback - + """ - - def __init__(self, dl2:DataLoader, bs:Optional[int]=None, l2pl_ratio:int=1, batch_tfms:Optional[list]=None, do_setup:bool=True, - pseudolabel_sample_weight:float=1., verbose=False): + + def __init__(self, dl2:DataLoader, bs:Optional[int]=None, l2pl_ratio:int=1, batch_tfms:Optional[list]=None, do_setup:bool=True, + pseudolabel_sample_weight:float=1., verbose=False): r''' Args: dl2: dataloader with the pseudolabels @@ -46,18 +46,18 @@ def __init__(self, dl2:DataLoader, bs:Optional[int]=None, l2pl_ratio:int=1, batc do_setup: perform a transform setup on the labeled dataset. pseudolabel_sample_weight: weight of each pseudolabel sample relative to the labeled one of the loss. ''' - + self.dl2, self.bs, self.l2pl_ratio, self.batch_tfms, self.do_setup, self.verbose = dl2, bs, l2pl_ratio, batch_tfms, do_setup, verbose self.pl_sw = pseudolabel_sample_weight - + def before_fit(self): if self.batch_tfms is None: self.batch_tfms = self.dls.train.after_batch self.old_bt = self.dls.train.after_batch # Remove and store dl.train.batch_tfms self.old_bs = self.dls.train.bs - self.dls.train.after_batch = noop + self.dls.train.after_batch = noop if self.do_setup and self.batch_tfms: - for bt in self.batch_tfms: + for bt in self.batch_tfms: bt.setup(self.dls.train) if self.bs is None: self.bs = self.dls.train.bs @@ -67,12 +67,12 @@ def before_fit(self): pv(f'labels / pseudolabels per training batch : {self.dls.train.bs} / {self.dl2.bs}', self.verbose) rel_weight = (self.dls.train.bs/self.dl2.bs) * (len(self.dl2.dataset)/len(self.dls.train.dataset)) pv(f'relative labeled/ pseudolabel sample weight in dataset: {rel_weight:.1f}', self.verbose) - + self.dl2iter = iter(self.dl2) - + self.old_loss_func = self.learn.loss_func self.learn.loss_func = self.loss - + def before_batch(self): if self.training: X, y = self.x, self.y @@ -81,26 +81,26 @@ def before_batch(self): self.dl2iter = iter(self.dl2) X2, y2 = next(self.dl2iter) if y.ndim == 1 and y2.ndim == 2: y = torch.eye(self.learn.dls.c, device=y.device)[y] - + X_comb, y_comb = concat(X, X2), concat(y, y2) - - if self.batch_tfms is not None: + + if self.batch_tfms is not None: X_comb = compose_tfms(X_comb, self.batch_tfms, split_idx=0) y_comb = compose_tfms(y_comb, self.batch_tfms, split_idx=0) self.learn.xb = (X_comb,) self.learn.yb = (y_comb,) pv(f'\nX: {X.shape} X2: {X2.shape} X_comb: {X_comb.shape}', self.verbose) pv(f'y: {y.shape} y2: {y2.shape} y_comb: {y_comb.shape}', self.verbose) - - def loss(self, output, target): + + def loss(self, output, target): if target.ndim == 2: _, target = target.max(dim=1) - if self.training and self.pl_sw != 1: + if self.training and self.pl_sw != 1: loss = (1 - self.pl_sw) * self.old_loss_func(output[:self.dls.train.bs], target[:self.dls.train.bs]) loss += self.pl_sw * self.old_loss_func(output[self.dls.train.bs:], target[self.dls.train.bs:]) - return loss - else: + return loss + else: return self.old_loss_func(output, target) - + def after_fit(self): self.dls.train.after_batch = self.old_bt self.learn.loss_func = self.old_loss_func diff --git a/tsai/data/core.py b/tsai/data/core.py index a3abeb53a..69d554c71 100644 --- a/tsai/data/core.py +++ b/tsai/data/core.py @@ -38,14 +38,14 @@ def __new__(cls, o, dtype=None, device=None, copy=None, requires_grad=False, **k res = cast(o, cls) # if the tensor results in a dtype torch.float64 a copy is made as dtype torch.float32 for k,v in kwargs.items(): setattr(res, k, v) return res - + @property def data(self): return cast(self, Tensor) - + def __repr__(self): if self.ndim > 0: return f'NumpyTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})' else: return f'NumpyTensor([{self.data}], device={self.device}, dtype={self.dtype})' - + def show(self, ax=None, ctx=None, title=None, **kwargs): if self.ndim == 0: return str(self.data) @@ -61,7 +61,7 @@ def show(self, ax=None, ctx=None, title=None, **kwargs): ax.set_title(title, weight='bold', color=title_color) plt.tight_layout() return ax - + class ToNumpyTensor(Transform): "Transforms an object into NumpyTensor" @@ -76,10 +76,10 @@ def __new__(cls, o, dtype=None, device=None, copy=None, requires_grad=False, **k res = cast(o, cls) # if the tensor results in a dtype torch.float64 a copy is made as dtype torch.float32 for k,v in kwargs.items(): setattr(res, k, v) return res - + @property def data(self): return cast(self, Tensor) - + def show(self, ax=None, ctx=None, title=None, **kwargs): if self.ndim == 0: return str(self.data) elif self.ndim != 2: self = type(self)(to2d(self)) @@ -94,7 +94,7 @@ def show(self, ax=None, ctx=None, title=None, **kwargs): ax.set_title(title, weight='bold', color=title_color) plt.tight_layout() return ax - + @property def vars(self): return self.shape[-2] @@ -128,12 +128,12 @@ def show_tuple(tup, **kwargs): tup[0].show(title=title, **kwargs) # %% ../../nbs/006_data.core.ipynb 27 -class TSLabelTensor(NumpyTensor): +class TSLabelTensor(NumpyTensor): def __repr__(self): if self.ndim == 0: return f'{self.data}' else: return f'TSLabelTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})' -class TSMaskTensor(NumpyTensor): +class TSMaskTensor(NumpyTensor): def __repr__(self): if self.ndim == 0: return f'{self.data}' else: return f'TSMaskTensor(shape:{tuple(self.shape)}, device={self.device}, dtype={self.dtype})' @@ -145,22 +145,22 @@ class ToFloat(Transform): loss_func=MSELossFlat() def encodes(self, o:torch.Tensor): return o.float() def encodes(self, o): return np.asarray(o, dtype=np.float32) - def decodes(self, o): - if o.ndim==0: return TitledFloat(o) - else: + def decodes(self, o): + if o.ndim==0: return TitledFloat(o) + else: return TitledTuple(o.cpu().numpy().tolist()) - + class ToInt(Transform): "Transforms an object dtype to int" def encodes(self, o:torch.Tensor): return o.long() def encodes(self, o): return np.asarray(o).astype(np.float32).astype(np.int64) - def decodes(self, o): - if o.ndim==0: return TitledFloat(o) - else: + def decodes(self, o): + if o.ndim==0: return TitledFloat(o) + else: return TitledTuple(o.cpu().numpy().tolist()) - - + + class TSClassification(DisplayedTransform): "Vectorized, reversible transform of category string to `vocab` id" loss_func,order,vectorized=CrossEntropyLossFlat(),1,True @@ -193,7 +193,7 @@ def decodes(self, o): else: return stack(MultiCategory(self.vocab[o.flatten()])).reshape(*o.shape) - + TSCategorize = TSClassification TSRegression = ToFloat TSForecasting = ToFloat @@ -202,7 +202,7 @@ def decodes(self, o): class TSMultiLabelClassification(Categorize): "Reversible combined transform of multi-category strings to one-hot encoded `vocab` id" loss_func,order=BCEWithLogitsLossFlat(),1 - def __init__(self, c=None, vocab=None, add_na=False, sort=True): + def __init__(self, c=None, vocab=None, add_na=False, sort=True): super().__init__(vocab=vocab,add_na=add_na,sort=sort) self.c = c @@ -222,7 +222,7 @@ def encodes(self, o): diff_str = "', '".join(diff) raise KeyError(f"Labels '{diff_str}' were not included in the training dataset") return TensorMultiCategory(one_hot([self.vocab.o2i[o_] for o_ in o], self.c).float()) - def decodes(self, o): + def decodes(self, o): if o.ndim == 2: return MultiCategory([self.vocab[o_] for o_ in o]) else: @@ -235,7 +235,7 @@ def __init__(self, type_tfms=None, item_tfms=None, batch_tfms=None, dl_type=None self.item_tfms = ToNumpyTensor + 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) - + class TSTensorBlock(): def __init__(self, type_tfms=None, item_tfms=None, batch_tfms=None, dl_type=None, dls_kwargs=None): self.type_tfms = L(type_tfms) @@ -249,7 +249,7 @@ def __init__(self, X, y=None): self.X, self.y = X, y def __getitem__(self, idx): return (self.X[idx],) if self.y is None else (self.X[idx], self.y[idx]) def __len__(self): return len(self.X) - + class NumpyDataset(): def __init__(self, X, y=None, types=None): self.X, self.y, self.types = X, y, types def __getitem__(self, idx): @@ -295,14 +295,14 @@ def _flatten_list(lst): "Flattens a list of lists with splits" def __flatten_list(lst): - if lst is None: + if lst is None: return L([]) - if not hasattr(lst, "__iter__"): + if not hasattr(lst, "__iter__"): lst = [lst] # clean_up_list if len(lst) > 10: - return lst + return lst else: lst = [l for l in lst if l is not None or (hasattr(l, "__len__") and len(l) == 0)] @@ -325,20 +325,20 @@ def __flatten_list(lst): def _remove_brackets(l): return [li if (not li or not is_listy(li) or len(li) > 1) else li[0] for li in l] - + class NoTfmLists(TfmdLists): def __init__(self, items, tfms=None, splits=None, split_idx=None, types=None, do_setup=False, **kwargs): self.splits = ifnone(splits, L(np.arange(len(items)).tolist(),[])) self._splits = _flatten_list(self.splits) store_attr('items,types,split_idx') self.tfms = Pipeline(split_idx=split_idx) - def subset(self, i, **kwargs): return type(self)(self.items, splits=self.splits[i], split_idx=i, do_setup=False, types=self.types, + def subset(self, i, **kwargs): return type(self)(self.items, splits=self.splits[i], split_idx=i, do_setup=False, types=self.types, **kwargs) def __getitem__(self, it): if hasattr(self.items, 'oindex'): return self.items.oindex[self._splits[it]] else: return self.items[self._splits[it]] def __len__(self): return len(self._splits) - def __repr__(self): + def __repr__(self): if hasattr(self.items, "shape"): return f"{self.__class__.__name__}: {self.items.__class__.__name__}{(len(self), *self.items.shape[1:])}" else: @@ -354,7 +354,7 @@ def new_empty(self): return self._new([]) class TSTfmdLists(TfmdLists): def __getitem__(self, it): # res = self._get(it) - if hasattr(self.items, 'oindex'): res = self.items.oindex[it] + if hasattr(self.items, 'oindex'): res = self.items.oindex[it] else: res = self.items[it] if self._after_item is None: return res else: return self._after_item(res) @@ -397,7 +397,7 @@ def __init__(self, X=None, y=None, items=None, tfms=None, tls=None, n_inp=None, self.n_inp = 1 if kwargs.get('splits', None) is not None: split_idxs = _flatten_list(kwargs['splits']) - else: + else: split_idxs = _flatten_list(np.arange(len(self))) self.split_idxs = split_idxs @@ -416,16 +416,16 @@ def subset(self, i): return type(self)(*self[i], inplace=True, tfms=None, splits=splits, split_idx=ifnone(self.split_idx, 1)) def __len__(self): return len(self.tls[0]) - + def _new(self, X, y=None, **kwargs): return type(self)(X, y=y, tfms=self.tfms, inplace=self.inplace, do_setup=False, **kwargs) def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], n_inp=self.n_inp, inplace=self.inplace) - + def show_at(self, idx, **kwargs): self.show(self[idx], **kwargs) plt.show() - + def __repr__(self): return tscoll_repr(self) @@ -440,37 +440,37 @@ def tscoll_repr(c, max_n=10): class TSDatasets(Datasets): """A dataset that creates tuples from X (and optionally y) and applies `item_tfms`""" typs = TSTensor, torch.as_tensor - def __init__(self, X=None, y=None, items=None, sel_vars=None, sel_steps=None, tfms=None, tls=None, n_inp=None, dl_type=None, + def __init__(self, X=None, y=None, items=None, sel_vars=None, sel_steps=None, tfms=None, tls=None, n_inp=None, dl_type=None, inplace=True, **kwargs): # Prepare X (and y) if X is not None: - if not hasattr(X, '__array__'): + if not hasattr(X, '__array__'): X = np.asarray(X) X = to3d(X) if y is not None: - if not hasattr(y, '__array__'): + if not hasattr(y, '__array__'): y = np.asarray(y) - elif hasattr(y, "iloc"): + elif hasattr(y, "iloc"): y = toarray(y) # Prepare sel_vars and sel_steps self.multi_index = False if sel_vars is None or (type(sel_vars) == slice and sel_vars == slice(None)): self.sel_vars = slice(None) - elif type(sel_vars) == slice: + elif type(sel_vars) == slice: self.sel_vars = sel_vars self.multi_index = True else: self.sel_vars = np.asarray(sel_vars) if sel_steps is not None and type(sel_steps) != slice: self.sel_vars = sel_vars[:, None] self.multi_index = True - if sel_steps is None or (type(sel_steps) == slice and sel_steps == slice(None)): + if sel_steps is None or (type(sel_steps) == slice and sel_steps == slice(None)): self.sel_steps = slice(None) - elif type(sel_steps) == slice: + elif type(sel_steps) == slice: self.sel_steps = sel_steps self.multi_index = True - else: + else: self.sel_steps = np.asarray(sel_steps) self.multi_index = True self.tfms, self.inplace = tfms, inplace @@ -502,11 +502,11 @@ def __init__(self, X=None, y=None, items=None, sel_vars=None, sel_steps=None, tf self.ptls = L([typ(stack(tl[:]))[...,self.sel_vars, self.sel_steps] if (i==0 and self.multi_index) else typ(stack(tl[:])) \ for i,(tl,typ) in enumerate(zip(self.tls,self.typs))]) if inplace and len(tls[0]) != 0 else tls self.no_tfm = False - + self.n_inp = 1 if kwargs.get('splits', None) is not None: split_idxs = _flatten_list(kwargs.get('splits')) - else: + else: split_idxs = np.arange(len(self), dtype=smallest_dtype(len(self))) self.split_idxs = split_idxs @@ -516,41 +516,41 @@ def __getitem__(self, it): else: return tuple([typ(stack(ptl[it]))[...,self.sel_vars, self.sel_steps] if (i==0 and self.multi_index) else typ(stack(ptl[it])) \ for i,(ptl,typ) in enumerate(zip(self.ptls,self.typs))]) - + def subset(self, i): if is_indexer(i): return type(self)(tls=L([tl.subset(i) for tl in self.tls]), inplace=self.inplace, tfms=self.tfms, - sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=None if self.splits is None else self.splits[i], + sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=None if self.splits is None else self.splits[i], split_idx=i) else: if self.splits is None: - splits = None + splits = None else: min_dtype = np.min_scalar_type(len(i)) splits = np.arange(len(i), dtype=min_dtype) - return type(self)(*self[i], inplace=True, tfms=None, + return type(self)(*self[i], inplace=True, tfms=None, sel_vars=self.sel_vars, sel_steps=self.sel_steps, splits=splits, split_idx=ifnone(self.split_idx, 1)) - + def _new(self, X, y=None, **kwargs): - return type(self)(X, y=y, sel_vars=self.sel_vars, sel_steps=self.sel_steps, tfms=self.tfms, inplace=self.inplace, + return type(self)(X, y=y, sel_vars=self.sel_vars, sel_steps=self.sel_steps, tfms=self.tfms, inplace=self.inplace, do_setup=False, **kwargs) - - def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], sel_vars=self.sel_vars, sel_steps=self.sel_steps, + + def new_empty(self): return type(self)(tls=[tl.new_empty() for tl in self.tls], sel_vars=self.sel_vars, sel_steps=self.sel_steps, n_inp=self.n_inp, inplace=self.inplace) def __len__(self): return len(self.tls[0]) - + def show_at(self, idx, **kwargs): self.show(self[idx], **kwargs) plt.show() - + def __repr__(self): return tscoll_repr(self) # %% ../../nbs/006_data.core.ipynb 51 def add_ds(dsets, X, y=None, inplace=True): "Create test datasets from X (and y) using validation transforms of `dsets`" items = tuple((X,)) if y is None else tuple((X, y)) - with_labels = False if y is None else True + with_labels = False if y is None else True if isinstance(dsets, TSDatasets): tls = dsets.tls if with_labels else dsets.tls[:dsets.n_inp] new_tls = L([tl._new(item, split_idx=1) for tl,item in zip(tls, items)]) @@ -566,7 +566,7 @@ def add_ds(dsets, X, y=None, inplace=True): elif isinstance(dsets, TfmdLists): new_tl = dsets._new(items, split_idx=1) return new_tl - else: + else: raise Exception(f"Expected a `Datasets` or a `TfmdLists` but got {dsets.__class__.__name__}") @patch @@ -615,14 +615,14 @@ def __init__(self, dataset, bs=64, shuffle=False, drop_last=False, num_workers=0 if num_workers is None: num_workers = min(16, defaults.cpus) if sampler is not None and shuffle: raise ValueError('sampler option is mutually exclusive with shuffle') - + for nm in _batch_tfms: if nm == 'after_batch' and kwargs.get('batch_tfms',None) is not None: kwargs[nm] = Pipeline(listify(kwargs.get('batch_tfms'))) else: kwargs[nm] = Pipeline(kwargs.get(nm,None)) bs = max(1, min(bs, len(dataset))) # bs cannot be 1 if is_listy(partial_n): partial_n = partial_n[0] if isinstance(partial_n, float): partial_n = int(round(partial_n * len(dataset))) - if partial_n is not None: + if partial_n is not None: partial_n = min(partial_n, len(dataset)) bs = min(bs, partial_n) if weights is not None: weights = weights / weights.sum() @@ -630,10 +630,10 @@ def __init__(self, dataset, bs=64, shuffle=False, drop_last=False, num_workers=0 super().__init__(dataset, bs=bs, shuffle=shuffle, drop_last=drop_last, num_workers=num_workers, verbose=verbose, do_setup=do_setup, **kwargs) if vocab is not None: self.vocab = vocab - + def new_dl(self, X, y=None, bs=64): assert X.ndim == 3, "You must pass an X iterable with 3 dimensions [batch_size x n_vars x seq_len]" - if y is not None: + if y is not None: y = np.asarray(y) assert y.ndim > 0, "You must pass a y iterable with at least 1 dimension" ds = self.dataset.add_dataset(X, y=y) @@ -643,14 +643,14 @@ def create_batch(self, b): if self.shuffle or self.sampler is not None: if self.sort and hasattr(b, 'sort'): b.sort() self.idxs = L(b) - else: + else: if self.n is not None: b = slice(b[0], min(self.n, b[0] + self.bs)) else: b = slice(b[0], b[0] + self.bs) - + self.idxs = b - if hasattr(self, "split_idxs"): + if hasattr(self, "split_idxs"): self.input_idxs = self.split_idxs[b] else: self.input_idxs = self.idxs return self.dataset[b] @@ -659,7 +659,7 @@ def create_item(self, s): if self.indexed: return self.dataset[s or 0] elif s is None: return next(self.it) else: raise IndexError("Cannot index an iterable dataset numerically - must use `None`.") - + def get_idxs(self): if self.n==0: return [] if self.partial_n is not None: n = min(self.partial_n, self.n) @@ -707,12 +707,12 @@ def __len__(self): if self.n == 0: return 0 elif self.partial_n is None: return super().__len__() return self.partial_n//self.bs + (0 if self.drop_last or self.partial_n%self.bs==0 else 1) - + @delegates(plt.subplots) - def show_batch(self, b=None, ctxs=None, max_n=9, nrows=3, ncols=3, figsize=None, unique=False, sharex=True, sharey=False, decode=False, + def show_batch(self, b=None, ctxs=None, max_n=9, nrows=3, ncols=3, figsize=None, unique=False, sharex=True, sharey=False, decode=False, show_title=True, **kwargs): - - old_sort = self.sort + + old_sort = self.sort self.sort = False # disable sorting when showing a batch to ensure varied samples if unique: @@ -732,13 +732,13 @@ def show_batch(self, b=None, ctxs=None, max_n=9, nrows=3, ncols=3, figsize=None, if figsize is None: figsize = (ncols*6, math.ceil(max_n/ncols)*4) if ctxs is None: ctxs = get_grid(max_n, nrows=nrows, ncols=ncols, figsize=figsize, sharex=sharex, sharey=sharey, **kwargs) if show_title: - for i,ctx in enumerate(ctxs): + for i,ctx in enumerate(ctxs): show_tuple(db[i], ctx=ctx) else: db = [x for x,_ in db] - for i,ctx in enumerate(ctxs): + for i,ctx in enumerate(ctxs): db[i].show(ctx=ctx) - + self.sort = old_sort @delegates(plt.subplots) @@ -787,7 +787,7 @@ def show_dist(self, figsize=None, color=None, **kwargs): @property def c(self): - if len(self.dataset) == 0: + if len(self.dataset) == 0: return 0 if hasattr(self, "vocab"): return len(self.vocab) @@ -897,7 +897,7 @@ def from_numpy(cls, X, y=None, splitter=None, valid_pct=0.2, seed=0, item_tfms=N return cls.from_dblock(dblock, source, **kwargs) @classmethod - def from_dsets(cls, *ds, path='.', bs=64, num_workers=0, batch_tfms=None, device=None, shuffle_train=True, drop_last=True, + def from_dsets(cls, *ds, path='.', bs=64, num_workers=0, batch_tfms=None, device=None, shuffle_train=True, drop_last=True, weights=None, partial_n=None, sampler=None, sort=False, vocab=None, **kwargs): device = ifnone(device, default_device()) if batch_tfms is not None and not isinstance(batch_tfms, list): batch_tfms = [batch_tfms] @@ -925,8 +925,8 @@ class TSDataLoaders(NumpyDataLoaders): # %% ../../nbs/006_data.core.ipynb 71 class StratifiedSampler: "Sampler where batches preserve the percentage of samples for each class" - - def __init__(self, + + def __init__(self, y, # The target variable for supervised learning problems. Stratification is done based on the y labels. bs : int = 64, # Batch size shuffle : bool = False, # Flag to shuffle each class’s samples before splitting into batches. @@ -959,14 +959,14 @@ def get_c(dls): return len(vocab) # %% ../../nbs/006_data.core.ipynb 74 -def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], return_best=True, - verbose=True): +def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], return_best=True, + verbose=True): - if not torch.cuda.is_available(): + if not torch.cuda.is_available(): num_workers = 0 n_iters = min(n_iters, len(dl)) if not return_best: verbose = True - + nw = dl.fake_l.num_workers pm = dl.fake_l.pin_memory pf = dl.fake_l.prefetch_factor @@ -975,25 +975,25 @@ def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[ best_nw = nw best_pm = pm best_pf = pf - + # num_workers if not num_workers: best_nw = nw elif isinstance(num_workers, Integral): best_nw = num_workers - else: + else: best_time = np.inf for _nw in num_workers: dl.fake_l.num_workers = _nw timer.start(False) for i, _ in enumerate(dl): - if i == n_iters - 1: + if i == n_iters - 1: t = timer.stop() / (i + 1) pv(f' num_workers: {_nw:2} pin_memory: {pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', verbose) - if t < best_time: + if t < best_time: best_nw = _nw best_time = t break dl.fake_l.num_workers = best_nw - + # pin_memory if not pin_memory: best_pm = pm @@ -1005,11 +1005,11 @@ def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[ dl.fake_l.pin_memory = _pm timer.start(False) for i, _ in enumerate(dl): - if i == n_iters - 1: + if i == n_iters - 1: t = timer.stop() / (i + 1) - pv(f' num_workers: {best_nw:2} pin_memory: {_pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', + pv(f' num_workers: {best_nw:2} pin_memory: {_pm!s:^5} prefetch_factor: {pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', verbose) - if t < best_time: + if t < best_time: best_pm = _pm best_time = t break @@ -1026,27 +1026,27 @@ def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[ dl.fake_l.prefetch_factor = _pf timer.start(False) for i, _ in enumerate(dl): - if i == n_iters - 1: + if i == n_iters - 1: t = timer.stop() / (i + 1) - pv(f' num_workers: {best_nw:2} pin_memory: {best_pm!s:^5} prefetch_factor: {_pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', + pv(f' num_workers: {best_nw:2} pin_memory: {best_pm!s:^5} prefetch_factor: {_pf:2} - time: {1_000 * t/n_iters:8.3f} ms/iter', verbose) - if t < best_time: + if t < best_time: best_pf = _pf best_time = t break dl.fake_l.prefetch_factor = best_pf - - except KeyboardInterrupt: + + except KeyboardInterrupt: dl.fake_l.num_workers = best_nw if return_best else nw dl.fake_l.pin_memory = best_pm if return_best else pm dl.fake_l.prefetch_factor = best_pf if return_best else pf - if not return_best: + if not return_best: dl.fake_l.num_workers = nw dl.fake_l.pin_memory = pm dl.fake_l.prefetch_factor = pf - if verbose: + if verbose: print('\n best dl params:') print(f' best num_workers : {best_nw}') print(f' best pin_memory : {best_pm}') @@ -1056,13 +1056,13 @@ def get_best_dl_params(dl, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[ return dl -def get_best_dls_params(dls, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], - return_best=True, verbose=True): - +def get_best_dls_params(dls, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory=[True, False], prefetch_factor=[2, 4, 8], + return_best=True, verbose=True): + for i in range(len(dls.loaders)): try: pv(f'\nDataloader {i}\n', verbose) - dls.loaders[i] = get_best_dl_params(dls.loaders[i], n_iters=n_iters, num_workers=num_workers, pin_memory=pin_memory, + dls.loaders[i] = get_best_dl_params(dls.loaders[i], n_iters=n_iters, num_workers=num_workers, pin_memory=pin_memory, prefetch_factor=prefetch_factor, return_best=return_best, verbose=verbose) except KeyboardInterrupt: pass return dls @@ -1071,9 +1071,9 @@ def get_best_dls_params(dls, n_iters=10, num_workers=[0, 1, 2, 4, 8], pin_memory def _check_splits(X, splits): if splits is None: _dtype = smallest_dtype(len(X)) - if len(X) < 1e6: + if len(X) < 1e6: splits = (L(np.arange(len(X), dtype=_dtype).tolist()), L()) - else: + else: _dtype = smallest_dtype(len(X)) splits = (np.arange(len(X), dtype=_dtype), L()) elif isinstance(splits, (tuple, list, L, np.ndarray)): @@ -1088,7 +1088,7 @@ def _check_splits(X, splits): return splits def get_ts_dls(X, y=None, splits=None, sel_vars=None, sel_steps=None, tfms=None, inplace=True, - path='.', bs=64, batch_tfms=None, num_workers=0, device=None, shuffle_train=True, drop_last=True, + path='.', bs=64, batch_tfms=None, num_workers=0, device=None, shuffle_train=True, drop_last=True, weights=None, partial_n=None, sampler=None, sort=False, **kwargs): splits = _check_splits(X, splits) create_dir(path, verbose=False) @@ -1098,7 +1098,7 @@ def get_ts_dls(X, y=None, splits=None, sel_vars=None, sel_steps=None, tfms=None, assert len(X) == len(weights), 'len(X) != len(weights)' weights = [weights[split] if i == 0 else None for i,split in enumerate(splits)] # weights only applied to train set dls = TSDataLoaders.from_dsets(*dsets, path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, - device=device, shuffle_train=shuffle_train, drop_last=drop_last, weights=weights, + device=device, shuffle_train=shuffle_train, drop_last=drop_last, weights=weights, partial_n=partial_n, sampler=sampler, sort=sort, **kwargs) return dls @@ -1108,9 +1108,9 @@ def get_ts_dls(X, y=None, splits=None, sel_vars=None, sel_steps=None, tfms=None, def _check_split(X, split): if split is None: _dtype = smallest_dtype(len(X)) - if len(X) < 1e6: + if len(X) < 1e6: split = L(np.arange(len(X), dtype=_dtype).tolist()) - else: + else: _dtype = smallest_dtype(len(X)) split = np.arange(len(X), dtype=_dtype) return (split, L()) @@ -1136,22 +1136,22 @@ def get_time_per_batch(dl, model=None, n_batches=None): try: timer.start(False) pbar = progress_bar(dl, leave=False) - for i, (xb, _) in enumerate(pbar): - if model is not None: + for i, (xb, _) in enumerate(pbar): + if model is not None: _ = model(xb) - if n_batches is not None and i >= n_batches - 1: + if n_batches is not None and i >= n_batches - 1: t = timer.stop() pbar.on_interrupt() break - if n_batches is None or i < n_batches - 1: + if n_batches is None or i < n_batches - 1: t = timer.stop() - + except KeyboardInterrupt: t = timer.stop() pbar.on_interrupt() return t / (i+1) -def get_dl_percent_per_epoch(dl, model, n_batches=None): +def get_dl_percent_per_epoch(dl, model, n_batches=None): dl_time = get_time_per_batch(dl, model=None, n_batches=n_batches) model_time = get_time_per_batch(dl, model=model, n_batches=n_batches) return f'{min(1, dl_time/model_time):.2%}' diff --git a/tsai/data/image.py b/tsai/data/image.py index 7602ce79f..6939a3af1 100644 --- a/tsai/data/image.py +++ b/tsai/data/image.py @@ -67,7 +67,7 @@ def __init__(self, size:Optional[int]=224, dpi:int=default_dpi(), lw=1, **kwargs def encodes(self, o: TSTensor): device = o.device - if o.data.device.type == 'cuda': o = o.cpu() + if o.data.device.type != 'cpu': o = o.cpu() if o.ndim == 2: o = o[None] seq_len = o.shape[-1] fig = self.fig @@ -95,7 +95,7 @@ def __init__(self, size=224, dpi=default_dpi(), cmap=None, **kwargs): def encodes(self, o: TSTensor): device = o.device - if o.data.device.type == 'cuda': o = o.cpu() + if o.data.device.type != 'cpu': o = o.cpu() if o.ndim == 2: o = o[None] nvars, seq_len = o.shape[-2:] aspect = seq_len / nvars @@ -129,7 +129,7 @@ def encodes(self, o: TSTensor): bs, *_, seq_len = o.shape size = ifnone(self.size, seq_len) if size != seq_len: - o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0] + o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0] else: o = o.reshape(-1, seq_len) output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) / 2 + .5 @@ -153,7 +153,7 @@ def encodes(self, o: TSTensor): bs, *_, seq_len = o.shape size = ifnone(self.size, seq_len) if size != seq_len: - o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0] + o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0] else: o = o.reshape(-1, seq_len) output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) / 2 + .5 @@ -177,7 +177,7 @@ def encodes(self, o: TSTensor): bs, *_, seq_len = o.shape size = ifnone(self.size, seq_len) if size != seq_len: - o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0] + o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0] else: o = o.reshape(-1, seq_len) output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) @@ -201,7 +201,7 @@ def encodes(self, o: TSTensor): bs, *_, seq_len = o.shape size = ifnone(self.size, seq_len) if size != seq_len: - o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='linear', align_corners=False)[:, 0] + o = F.interpolate(o.reshape(-1, 1, seq_len), size=size, mode='nearest', align_corners=None)[:, 0] else: o = o.reshape(-1, seq_len) output = self.encoder.fit_transform(o.cpu().numpy()) / 2 @@ -225,7 +225,7 @@ def encodes(self, o: TSTensor): o = to3d(o) bs, *_, seq_len = o.shape size = ifnone(self.size, seq_len) - if size != seq_len: o = F.interpolate(o, size=size, mode='linear', align_corners=False) + if size != seq_len: o = F.interpolate(o, size=size, mode='nearest', align_corners=None) output = self.encoder.fit_transform(o.cpu().numpy()).reshape(bs, -1, size, size) if self.cmap and output.shape[1] == 1: output = TSImage(plt.get_cmap(self.cmap)(output)[..., :3]).squeeze(1).permute(0,3,1,2) diff --git a/tsai/data/transforms.py b/tsai/data/transforms.py index 318432104..ed388c07e 100644 --- a/tsai/data/transforms.py +++ b/tsai/data/transforms.py @@ -5,13 +5,13 @@ 'TSShuffle_HLs', 'TSShuffleSteps', 'TSGaussianNoise', 'TSMagAddNoise', 'TSMagMulNoise', 'random_curve_generator', 'random_cum_curve_generator', 'random_cum_noise_generator', 'random_cum_linear_generator', 'TSTimeNoise', 'TSMagWarp', 'TSTimeWarp', 'TSWindowWarp', 'TSMagScale', - 'TSMagScalePerVar', 'TSRandomResizedCrop', 'TSWindowSlicing', 'TSRandomZoomOut', 'TSRandomTimeScale', - 'TSRandomTimeStep', 'TSResampleSteps', 'TSBlur', 'TSSmooth', 'maddest', 'TSFreqDenoise', 'TSRandomFreqNoise', - 'TSRandomResizedLookBack', 'TSRandomLookBackOut', 'TSVarOut', 'TSCutOut', 'TSTimeStepOut', 'TSRandomCropPad', - 'TSMaskOut', 'TSInputDropout', 'TSTranslateX', 'TSRandomShift', 'TSHorizontalFlip', 'TSRandomTrend', - 'TSVerticalFlip', 'TSResize', 'TSRandomSize', 'TSRandomLowRes', 'TSDownUpScale', 'TSRandomDownUpScale', - 'TSRandomConv', 'TSRandom2Value', 'TSMask2Value', 'self_mask', 'TSSelfDropout', 'RandAugment', 'TestTfm', - 'get_tfm_name'] + 'TSMagScalePerVar', 'test_interpolate', 'TSRandomResizedCrop', 'TSWindowSlicing', 'TSRandomZoomOut', + 'TSRandomTimeScale', 'TSRandomTimeStep', 'TSResampleSteps', 'TSBlur', 'TSSmooth', 'maddest', 'TSFreqDenoise', + 'TSRandomFreqNoise', 'TSRandomResizedLookBack', 'TSRandomLookBackOut', 'TSVarOut', 'TSCutOut', + 'TSTimeStepOut', 'TSRandomCropPad', 'TSMaskOut', 'TSInputDropout', 'TSTranslateX', 'TSRandomShift', + 'TSHorizontalFlip', 'TSRandomTrend', 'TSVerticalFlip', 'TSResize', 'TSRandomSize', 'TSRandomLowRes', + 'TSDownUpScale', 'TSRandomDownUpScale', 'TSRandomConv', 'TSRandom2Value', 'TSMask2Value', 'self_mask', + 'TSSelfDropout', 'RandAugment', 'TestTfm', 'get_tfm_name'] # %% ../../nbs/010_data.transforms.ipynb 3 from ..imports import * @@ -26,17 +26,17 @@ class TSIdentity(RandTransform): "Applies the identity tfm to a `TSTensor` batch" order = 90 - def __init__(self, magnitude=None, **kwargs): - self.magnitude = magnitude + def __init__(self, magnitude=None, **kwargs): + self.magnitude = magnitude super().__init__(**kwargs) def encodes(self, o: TSTensor): return o # %% ../../nbs/010_data.transforms.ipynb 8 -# partial(TSShuffle_HLs, ex=0), +# partial(TSShuffle_HLs, ex=0), class TSShuffle_HLs(RandTransform): "Randomly shuffles HIs/LOs of an OHLC `TSTensor` batch" order = 90 - def __init__(self, magnitude=1., ex=None, **kwargs): + def __init__(self, magnitude=1., ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -54,11 +54,11 @@ def encodes(self, o: TSTensor): return output # %% ../../nbs/010_data.transforms.ipynb 10 -# partial(TSShuffleSteps, ex=0), +# partial(TSShuffleSteps, ex=0), class TSShuffleSteps(RandTransform): "Randomly shuffles consecutive sequence datapoints in batch" order = 90 - def __init__(self, magnitude=1., ex=None, **kwargs): + def __init__(self, magnitude=1., ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -107,10 +107,10 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -class TSMagMulNoise(RandTransform): +class TSMagMulNoise(RandTransform): "Applies multiplicative noise on the y-axis for each step of a `TSTensor` batch" order = 90 - def __init__(self, magnitude=1, ex=None, **kwargs): + def __init__(self, magnitude=1, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -123,7 +123,7 @@ def encodes(self, o: TSTensor): # %% ../../nbs/010_data.transforms.ipynb 16 def random_curve_generator(o, magnitude=0.1, order=4, noise=None): seq_len = o.shape[-1] - f = CubicSpline(np.linspace(-seq_len, 2 * seq_len - 1, 3 * (order - 1) + 1, dtype=int), + f = CubicSpline(np.linspace(-seq_len, 2 * seq_len - 1, 3 * (order - 1) + 1, dtype=int), np.random.normal(loc=1.0, scale=magnitude, size=3 * (order - 1) + 1), axis=-1) return f(np.arange(seq_len)) @@ -161,7 +161,7 @@ def random_cum_linear_generator(o, magnitude=0.1): class TSTimeNoise(RandTransform): "Applies noise to each step in the x-axis of a `TSTensor` batch based on smooth random curve" order = 90 - def __init__(self, magnitude=0.1, ex=None, **kwargs): + def __init__(self, magnitude=0.1, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -175,7 +175,7 @@ def encodes(self, o: TSTensor): class TSMagWarp(RandTransform): "Applies warping to the y-axis of a `TSTensor` batch based on a smooth random curve" order = 90 - def __init__(self, magnitude=0.02, ord=4, ex=None, **kwargs): + def __init__(self, magnitude=0.02, ord=4, ex=None, **kwargs): self.magnitude, self.ord, self.ex = magnitude, ord, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -204,7 +204,7 @@ class TSWindowWarp(RandTransform): """Applies window slicing to the x-axis of a `TSTensor` batch based on a random linear curve based on https://halshs.archives-ouvertes.fr/halshs-01357973/document""" order = 90 - def __init__(self, magnitude=0.1, ex=None, **kwargs): + def __init__(self, magnitude=0.1, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -218,7 +218,7 @@ def encodes(self, o: TSTensor): class TSMagScale(RandTransform): "Applies scaling to the y-axis of a `TSTensor` batch based on a scalar" order = 90 - def __init__(self, magnitude=0.5, ex=None, **kwargs): + def __init__(self, magnitude=0.5, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -228,11 +228,11 @@ def encodes(self, o: TSTensor): output = o * scale if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output - + class TSMagScalePerVar(RandTransform): "Applies per_var scaling to the y-axis of a `TSTensor` batch based on a scalar" order = 90 - def __init__(self, magnitude=0.5, ex=None, **kwargs): + def __init__(self, magnitude=0.5, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -244,55 +244,82 @@ def encodes(self, o: TSTensor): output = o * scale if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output - + TSMagScaleByVar = TSMagScalePerVar # %% ../../nbs/010_data.transforms.ipynb 27 +def test_interpolate(mode="linear"): + + assert mode in ["nearest", "linear", "area"], "Mode must be 'nearest', 'linear' or 'area'." + + # Create a 1D tensor + tensor = torch.randn(1, 1, 8, device=default_device()) + + try: + # Try to interpolate using linear mode + result = F.interpolate(tensor, scale_factor=2, mode=mode) + return True + except NotImplementedError as e: + print(f"{mode} interpolation is not supported by {default_device()}. You can try a different mode") + print("Error:", e) + return False + +# %% ../../nbs/010_data.transforms.ipynb 30 class TSRandomResizedCrop(RandTransform): "Randomly amplifies a sequence focusing on a random section of the steps" order = 90 - def __init__(self, magnitude=0.1, size=None, scale=None, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, size=None, scale=None, ex=None, mode='nearest', **kwargs): """ Args: size: None, int or float scale: None or tuple of 2 floats 0 < float <= 1 mode: 'nearest' | 'linear' | 'area' - + """ + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode - if scale is not None: + if scale is not None: assert is_listy(scale) and len(scale) == 2 and min(scale) > 0 and min(scale) <= 1, "scale must be a tuple with 2 floats 0 < float <= 1" self.size,self.scale = size,scale super().__init__(**kwargs) def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o seq_len = o.shape[-1] - if self.size is not None: + if self.size is not None: size = self.size if isinstance(self.size, Integral) else int(round(self.size * seq_len)) else: size = seq_len - if self.scale is not None: + if self.scale is not None: lambd = np.random.uniform(self.scale[0], self.scale[1]) - else: + else: lambd = np.random.beta(self.magnitude, self.magnitude) lambd = max(lambd, 1 - lambd) win_len = int(round(seq_len * lambd)) - if win_len == seq_len: + if win_len == seq_len: if size == seq_len: return o - _slice = slice(None) + _slice = slice(None) else: start = np.random.randint(0, seq_len - win_len) _slice = slice(start, start + win_len) return F.interpolate(o[..., _slice], size=size, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) - + TSRandomZoomIn = TSRandomResizedCrop -# %% ../../nbs/010_data.transforms.ipynb 29 +# %% ../../nbs/010_data.transforms.ipynb 32 class TSWindowSlicing(RandTransform): "Randomly extracts an resize a ts slice based on https://halshs.archives-ouvertes.fr/halshs-01357973/document" order = 90 - def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -303,12 +330,17 @@ def encodes(self, o: TSTensor): start = np.random.randint(0, seq_len - win_len) return F.interpolate(o[..., start : start + win_len], size=seq_len, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) -# %% ../../nbs/010_data.transforms.ipynb 31 +# %% ../../nbs/010_data.transforms.ipynb 34 class TSRandomZoomOut(RandTransform): "Randomly compresses a sequence on the x-axis" order = 90 - def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -324,12 +356,17 @@ def encodes(self, o: TSTensor): output[..., start:start + win_len] = o.new(interp) return output -# %% ../../nbs/010_data.transforms.ipynb 33 +# %% ../../nbs/010_data.transforms.ipynb 36 class TSRandomTimeScale(RandTransform): "Randomly amplifies/ compresses a sequence on the x-axis keeping the same length" order = 90 - def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -337,12 +374,17 @@ def encodes(self, o: TSTensor): if np.random.rand() <= 0.5: return TSRandomZoomIn(magnitude=self.magnitude, ex=self.ex, mode=self.mode)(o, split_idx=0) else: return TSRandomZoomOut(magnitude=self.magnitude, ex=self.ex, mode=self.mode)(o, split_idx=0) -# %% ../../nbs/010_data.transforms.ipynb 35 +# %% ../../nbs/010_data.transforms.ipynb 38 class TSRandomTimeStep(RandTransform): "Compresses a sequence on the x-axis by randomly selecting sequence steps and interpolating to previous size" order = 90 - def __init__(self, magnitude=0.02, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.02, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -355,7 +397,7 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 37 +# %% ../../nbs/010_data.transforms.ipynb 40 class TSResampleSteps(RandTransform): "Transform that randomly selects and sorts sequence steps (with replacement) maintaining the sequence length" @@ -369,27 +411,27 @@ def encodes(self, o: TSTensor): S = o.shape[-1] if isinstance(self.step_pct, tuple): step_pct = np.random.rand() * (self.step_pct[1] - self.step_pct[0]) + self.step_pct[0] - else: + else: step_pct = self.step_pct if step_pct != 1 and self.same_seq_len: idxs = np.sort(np.tile(random_choice(S, round(S * step_pct), True), math.ceil(1 / step_pct))[:S]) else: idxs = np.sort(random_choice(S, round(S * step_pct), True)) return o[..., idxs] - + TSSubsampleSteps = TSResampleSteps -# %% ../../nbs/010_data.transforms.ipynb 39 +# %% ../../nbs/010_data.transforms.ipynb 42 class TSBlur(RandTransform): "Blurs a sequence applying a filter of type [1, 0, 1]" order = 90 - def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): + def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): self.magnitude, self.ex = magnitude, ex - if filt_len is None: - filterargs = [1, 0, 1] - else: + if filt_len is None: + filterargs = [1, 0, 1] + else: filterargs = ([1] * max(1, filt_len // 2) + [0] + [1] * max(1, filt_len // 2)) - self.filterargs = np.array(filterargs) + self.filterargs = np.array(filterargs) self.filterargs = self.filterargs/self.filterargs.sum() super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -398,18 +440,18 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 41 +# %% ../../nbs/010_data.transforms.ipynb 44 class TSSmooth(RandTransform): "Smoothens a sequence applying a filter of type [1, 5, 1]" order = 90 - def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): + def __init__(self, magnitude=1., ex=None, filt_len=None, **kwargs): self.magnitude, self.ex = magnitude, ex self.filterargs = np.array([1, 5, 1]) - if filt_len is None: - filterargs = [1, 5, 1] - else: + if filt_len is None: + filterargs = [1, 5, 1] + else: filterargs = ([1] * max(1, filt_len // 2) + [5] + [1] * max(1, filt_len // 2)) - self.filterargs = np.array(filterargs) + self.filterargs = np.array(filterargs) self.filterargs = self.filterargs/self.filterargs.sum() super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -418,21 +460,21 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 43 -def maddest(d, axis=None): +# %% ../../nbs/010_data.transforms.ipynb 46 +def maddest(d, axis=None): #Mean Absolute Deviation return np.mean(np.absolute(d - np.mean(d, axis=axis)), axis=axis) class TSFreqDenoise(RandTransform): "Denoises a sequence applying a wavelet decomposition method" order = 90 - def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, thr=None, thr_mode='hard', pad_mode='per', **kwargs): + def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, thr=None, thr_mode='hard', pad_mode='per', **kwargs): self.magnitude, self.ex = magnitude, ex self.wavelet, self.level, self.thr, self.thr_mode, self.pad_mode = wavelet, level, thr, thr_mode, pad_mode super().__init__(**kwargs) - try: + try: import pywt - except ImportError: + except ImportError: raise ImportError('You need to install pywt to run TSFreqDenoise') def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o @@ -457,17 +499,17 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 46 +# %% ../../nbs/010_data.transforms.ipynb 49 class TSRandomFreqNoise(RandTransform): "Applys random noise using a wavelet decomposition method" order = 90 - def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, mode='constant', **kwargs): + def __init__(self, magnitude=0.1, ex=None, wavelet='db4', level=2, mode='constant', **kwargs): self.magnitude, self.ex = magnitude, ex self.wavelet, self.level, self.mode = wavelet, level, mode super().__init__(**kwargs) - try: + try: import pywt - except ImportError: + except ImportError: raise ImportError('You need to install pywt to run TSRandomFreqNoise') def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o @@ -478,12 +520,17 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 48 +# %% ../../nbs/010_data.transforms.ipynb 51 class TSRandomResizedLookBack(RandTransform): "Selects a random number of sequence steps starting from the end and return an output of the same shape" order = 90 - def __init__(self, magnitude=0.1, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.mode = magnitude, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -494,11 +541,11 @@ def encodes(self, o: TSTensor): output = o.clone()[..., int(round(lambd * seq_len)):] return F.interpolate(output, size=seq_len, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) -# %% ../../nbs/010_data.transforms.ipynb 50 +# %% ../../nbs/010_data.transforms.ipynb 53 class TSRandomLookBackOut(RandTransform): "Selects a random number of sequence steps starting from the end and set them to zero" order = 90 - def __init__(self, magnitude=0.1, **kwargs): + def __init__(self, magnitude=0.1, **kwargs): self.magnitude = magnitude super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -507,14 +554,14 @@ def encodes(self, o: TSTensor): lambd = np.random.beta(self.magnitude, self.magnitude) lambd = min(lambd, 1 - lambd) output = o.clone() - output[..., :int(round(lambd * seq_len))] = 0 + output[..., :int(round(lambd * seq_len))] = 0 return output -# %% ../../nbs/010_data.transforms.ipynb 52 +# %% ../../nbs/010_data.transforms.ipynb 55 class TSVarOut(RandTransform): "Set the value of a random number of variables to zero" order = 90 - def __init__(self, magnitude=0.05, ex=None, **kwargs): + def __init__(self, magnitude=0.05, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -534,11 +581,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 54 +# %% ../../nbs/010_data.transforms.ipynb 57 class TSCutOut(RandTransform): "Sets a random section of the sequence to zero" order = 90 - def __init__(self, magnitude=0.05, ex=None, **kwargs): + def __init__(self, magnitude=0.05, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -556,11 +603,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 56 +# %% ../../nbs/010_data.transforms.ipynb 59 class TSTimeStepOut(RandTransform): "Sets random sequence steps to zero" order = 90 - def __init__(self, magnitude=0.05, ex=None, **kwargs): + def __init__(self, magnitude=0.05, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -573,11 +620,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 58 +# %% ../../nbs/010_data.transforms.ipynb 61 class TSRandomCropPad(RandTransform): "Crops a section of the sequence of a random length" order = 90 - def __init__(self, magnitude=0.05, ex=None, **kwargs): + def __init__(self, magnitude=0.05, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -593,7 +640,7 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 60 +# %% ../../nbs/010_data.transforms.ipynb 63 class TSMaskOut(RandTransform): """Applies a random mask""" order = 90 @@ -611,7 +658,7 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 62 +# %% ../../nbs/010_data.transforms.ipynb 65 class TSInputDropout(RandTransform): """Applies input dropout with required_grad=False""" order = 90 @@ -619,7 +666,7 @@ def __init__(self, magnitude=0., ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex self.dropout = nn.Dropout(magnitude) super().__init__(**kwargs) - + @torch.no_grad() def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o @@ -627,11 +674,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 64 +# %% ../../nbs/010_data.transforms.ipynb 67 class TSTranslateX(RandTransform): "Moves a selected sequence window a random number of steps" order = 90 - def __init__(self, magnitude=0.1, ex=None, **kwargs): + def __init__(self, magnitude=0.1, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -651,11 +698,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 66 +# %% ../../nbs/010_data.transforms.ipynb 69 class TSRandomShift(RandTransform): "Shifts and splits a sequence" order = 90 - def __init__(self, magnitude=0.02, ex=None, **kwargs): + def __init__(self, magnitude=0.02, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -665,11 +712,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 68 +# %% ../../nbs/010_data.transforms.ipynb 71 class TSHorizontalFlip(RandTransform): "Flips the sequence along the x-axis" order = 90 - def __init__(self, magnitude=1., ex=None, **kwargs): + def __init__(self, magnitude=1., ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -678,11 +725,11 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 70 +# %% ../../nbs/010_data.transforms.ipynb 73 class TSRandomTrend(RandTransform): "Randomly rotates the sequence along the z-axis" order = 90 - def __init__(self, magnitude=0.1, ex=None, **kwargs): + def __init__(self, magnitude=0.1, ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -696,40 +743,50 @@ def encodes(self, o: TSTensor): output = o + t if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output - + TSRandomRotate = TSRandomTrend -# %% ../../nbs/010_data.transforms.ipynb 72 +# %% ../../nbs/010_data.transforms.ipynb 75 class TSVerticalFlip(RandTransform): "Applies a negative value to the time sequence" order = 90 - def __init__(self, magnitude=1., ex=None, **kwargs): + def __init__(self, magnitude=1., ex=None, **kwargs): self.magnitude, self.ex = magnitude, ex super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o return - o -# %% ../../nbs/010_data.transforms.ipynb 74 +# %% ../../nbs/010_data.transforms.ipynb 77 class TSResize(RandTransform): "Resizes the sequence length of a time series" order = 90 - def __init__(self, magnitude=-0.5, size=None, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=-0.5, size=None, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.size, self.ex, self.mode = magnitude, size, ex, mode super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if self.magnitude == 0: return o size = ifnone(self.size, int(round((1 + self.magnitude) * o.shape[-1]))) output = F.interpolate(o, size=size, mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) return output -# %% ../../nbs/010_data.transforms.ipynb 76 +# %% ../../nbs/010_data.transforms.ipynb 79 class TSRandomSize(RandTransform): "Randomly resizes the sequence length of a time series" order = 90 - def __init__(self, magnitude=0.1, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.1, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) def encodes(self, o: TSTensor): @@ -737,51 +794,66 @@ def encodes(self, o: TSTensor): size_perc = 1 + random_half_normal() * self.magnitude * (-1 if random.random() > .5 else 1) return F.interpolate(o, size=int(size_perc * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) -# %% ../../nbs/010_data.transforms.ipynb 78 +# %% ../../nbs/010_data.transforms.ipynb 81 class TSRandomLowRes(RandTransform): "Randomly resizes the sequence length of a time series to a lower resolution" order = 90 - def __init__(self, magnitude=.5, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=.5, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o size_perc = 1 - (np.random.rand() * (1 - self.magnitude)) return F.interpolate(o, size=int(size_perc * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) -# %% ../../nbs/010_data.transforms.ipynb 79 +# %% ../../nbs/010_data.transforms.ipynb 82 class TSDownUpScale(RandTransform): "Downscales a time series and upscales it again to previous sequence length" order = 90 - def __init__(self, magnitude=0.5, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=0.5, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0 or self.magnitude >= 1: return o output = F.interpolate(o, size=int((1 - self.magnitude) * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) output = F.interpolate(output, size=o.shape[-1], mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 81 +# %% ../../nbs/010_data.transforms.ipynb 84 class TSRandomDownUpScale(RandTransform): "Randomly downscales a time series and upscales it again to previous sequence length" order = 90 - def __init__(self, magnitude=.5, ex=None, mode='linear', **kwargs): + def __init__(self, magnitude=.5, ex=None, mode='nearest', **kwargs): "mode: 'nearest' | 'linear' | 'area'" + + if not test_interpolate(mode): + print(f"self.__name__ will not be applied because {mode} interpolation is not supported by {default_device()}. You can try a different mode") + magnitude = 0 + self.magnitude, self.ex, self.mode = magnitude, ex, mode super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0 or self.magnitude >= 1: return o - scale_factor = 0.5 + 0.5 * np.random.rand() + scale_factor = 0.5 + 0.5 * np.random.rand() output = F.interpolate(o, size=int(scale_factor * o.shape[-1]), mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) output = F.interpolate(output, size=o.shape[-1], mode=self.mode, align_corners=None if self.mode in ['nearest', 'area'] else False) if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 83 +# %% ../../nbs/010_data.transforms.ipynb 86 class TSRandomConv(RandTransform): """Applies a convolution with a random kernel and random weights with required_grad=False""" order = 90 @@ -801,7 +873,7 @@ def encodes(self, o: TSTensor): if self.ex is not None: output[...,self.ex,:] = o[...,self.ex,:] return output -# %% ../../nbs/010_data.transforms.ipynb 85 +# %% ../../nbs/010_data.transforms.ipynb 88 class TSRandom2Value(RandTransform): "Randomly sets selected variables of type `TSTensor` to predefined value (default: np.nan)" order = 90 @@ -833,7 +905,7 @@ def encodes(self, o:TSTensor): vals[:, self._sel_vars] = torch.rand(*vals[:, self._sel_vars, 0].shape, device=o.device).unsqueeze(-1) else: if self.magnitude == 1: - return o.fill_(self.value) + return o.fill_(self.value) else: vals = torch.rand(*o.shape[:-1], device=o.device).unsqueeze(-1) elif self.sel_vars is not None or self.sel_steps is not None: @@ -845,13 +917,13 @@ def encodes(self, o:TSTensor): vals[:, self._sel_vars, self._sel_steps] = torch.rand(*vals[:, self._sel_vars, self._sel_steps].shape, device=o.device) else: if self.magnitude == 1: - return o.fill_(self.value) + return o.fill_(self.value) else: vals = torch.rand_like(o) mask = vals > (1 - self.magnitude) return o.masked_fill(mask, self.value) -# %% ../../nbs/010_data.transforms.ipynb 96 +# %% ../../nbs/010_data.transforms.ipynb 99 class TSMask2Value(RandTransform): "Randomly sets selected variables of type `TSTensor` to predefined value (default: np.nan)" order = 90 @@ -867,8 +939,8 @@ def encodes(self, o:TSTensor): mask[:, self.sel_vars] = False return o.masked_fill(mask, self.value) -# %% ../../nbs/010_data.transforms.ipynb 98 -def self_mask(o): +# %% ../../nbs/010_data.transforms.ipynb 101 +def self_mask(o): mask1 = torch.isnan(o) mask2 = rotate_axis0(mask1) return torch.logical_and(mask2, ~mask1) @@ -882,11 +954,11 @@ def encodes(self, o: TSTensor): o[mask] = np.nan return o -# %% ../../nbs/010_data.transforms.ipynb 100 +# %% ../../nbs/010_data.transforms.ipynb 103 all_TS_randaugs = [ - - TSIdentity, - + + TSIdentity, + # Noise (TSMagAddNoise, 0.1, 1.), (TSGaussianNoise, .01, 1.), @@ -894,12 +966,12 @@ def encodes(self, o: TSTensor): (partial(TSTimeNoise, ex=0), 0.1, 1.), (partial(TSRandomFreqNoise, ex=0), 0.1, 1.), partial(TSShuffleSteps, ex=0), - (TSRandomTimeScale, 0.05, 0.5), - (TSRandomTimeStep, 0.05, 0.5), + (TSRandomTimeScale, 0.05, 0.5), + (TSRandomTimeStep, 0.05, 0.5), (partial(TSFreqDenoise, ex=0), 0.1, 1.), (TSRandomLowRes, 0.05, 0.5), (TSInputDropout, 0.05, .5), - + # Magnitude (partial(TSMagWarp, ex=0), 0.02, 0.2), (TSMagScale, 0.2, 1.), @@ -908,31 +980,31 @@ def encodes(self, o: TSTensor): partial(TSBlur, ex=0), partial(TSSmooth, ex=0), partial(TSDownUpScale, ex=0), - partial(TSRandomDownUpScale, ex=0), - (TSRandomTrend, 0.1, 0.5), - TSVerticalFlip, - (TSVarOut, 0.05, 0.5), - (TSCutOut, 0.05, 0.5), - + partial(TSRandomDownUpScale, ex=0), + (TSRandomTrend, 0.1, 0.5), + TSVerticalFlip, + (TSVarOut, 0.05, 0.5), + (TSCutOut, 0.05, 0.5), + # Time (partial(TSTimeWarp, ex=0), 0.02, 0.2), (TSWindowWarp, 0.05, 0.5), (TSRandomSize, 0.05, 1.), - TSHorizontalFlip, + TSHorizontalFlip, (TSTranslateX, 0.1, 0.5), - (TSRandomShift, 0.02, 0.2), - (TSRandomZoomIn, 0.05, 0.5), + (TSRandomShift, 0.02, 0.2), + (TSRandomZoomIn, 0.05, 0.5), (TSWindowSlicing, 0.05, 0.2), (TSRandomZoomOut, 0.05, 0.5), (TSRandomLookBackOut, 0.1, 1.), (TSRandomResizedLookBack, 0.1, 1.), (TSTimeStepOut, 0.01, 0.2), - (TSRandomCropPad, 0.05, 0.5), + (TSRandomCropPad, 0.05, 0.5), (TSRandomResizedCrop, 0.05, 0.5), (TSMaskOut, 0.01, 0.2), ] -# %% ../../nbs/010_data.transforms.ipynb 101 +# %% ../../nbs/010_data.transforms.ipynb 104 class RandAugment(RandTransform): order = 90 def __init__(self, tfms:list, N:int=1, M:int=3, **kwargs): @@ -959,21 +1031,21 @@ def encodes(self, o:(NumpyTensor, TSTensor)): output = compose_tfms(o, tfms_, split_idx=self.split_idx) return output -# %% ../../nbs/010_data.transforms.ipynb 103 +# %% ../../nbs/010_data.transforms.ipynb 106 class TestTfm(RandTransform): "Utility class to test the output of selected tfms during training" - def __init__(self, tfm, magnitude=1., ex=None, **kwargs): + def __init__(self, tfm, magnitude=1., ex=None, **kwargs): self.tfm, self.magnitude, self.ex = tfm, magnitude, ex self.tfmd, self.shape = [], [] super().__init__(**kwargs) - def encodes(self, o: TSTensor): + def encodes(self, o: TSTensor): if not self.magnitude or self.magnitude <= 0: return o output = self.tfm(o, split_idx=self.split_idx) self.tfmd.append(torch.equal(o, output)) self.shape.append(o.shape) return output -# %% ../../nbs/010_data.transforms.ipynb 104 +# %% ../../nbs/010_data.transforms.ipynb 107 def get_tfm_name(tfm): if isinstance(tfm, tuple): tfm = tfm[0] if hasattr(tfm, "func"): tfm = tfm.func diff --git a/tsai/models/HydraMultiRocketPlus.py b/tsai/models/HydraMultiRocketPlus.py index 72f0ae563..38ccddcfc 100644 --- a/tsai/models/HydraMultiRocketPlus.py +++ b/tsai/models/HydraMultiRocketPlus.py @@ -19,7 +19,7 @@ # %% ../../nbs/080_models.HydraMultiRocketPlus.ipynb 4 class HydraMultiRocketBackbonePlus(nn.Module): - def __init__(self, c_in, c_out, seq_len, d=None, + def __init__(self, c_in, c_out, seq_len, d=None, k = 8, g = 64, max_c_in = 8, clip=True, num_features=50_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=None, max_num_kernels=84, use_bn=True, fc_dropout=0, custom_head=None, zero_init=True, use_diff=True, device=default_device()): @@ -28,12 +28,12 @@ def __init__(self, c_in, c_out, seq_len, d=None, self.hydra = HydraBackbonePlus(c_in, c_out, seq_len, k=k, g=g, max_c_in=max_c_in, clip=clip, device=device, zero_init=zero_init) self.multirocket = MultiRocketBackbonePlus(c_in, seq_len, num_features=num_features, max_dilations_per_kernel=max_dilations_per_kernel, - kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels, + kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels, use_diff=use_diff) self.num_features = self.hydra.num_features + self.multirocket.num_features - - + + # transform in batches of *batch_size* def batch(self, X, split=None, batch_size=256): bs = X.shape[0] @@ -50,8 +50,8 @@ def batch(self, X, split=None, batch_size=256): for i, batch in enumerate(batches): Z.append(self(X[batch])) return torch.cat(Z) - - + + def forward(self, x): x = torch.cat([self.hydra(x), self.multirocket(x)], -1) return x @@ -59,7 +59,7 @@ def forward(self, x): # %% ../../nbs/080_models.HydraMultiRocketPlus.ipynb 5 class HydraMultiRocketPlus(nn.Sequential): - def __init__(self, + def __init__(self, c_in:int, # num of channels in input c_out:int, # num of channels in output seq_len:int, # sequence length @@ -84,13 +84,13 @@ def __init__(self, backbone = HydraMultiRocketBackbonePlus(c_in, c_out, seq_len, k=k, g=g, max_c_in=max_c_in, clip=clip, device=device, zero_init=zero_init, num_features=num_features, max_dilations_per_kernel=max_dilations_per_kernel, kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels, use_diff=use_diff) - + num_features = backbone.num_features # Head self.head_nf = num_features - if custom_head is not None: + if custom_head is not None: if isinstance(custom_head, nn.Module): head = custom_head else: head = custom_head(self.head_nf, c_out, 1) elif d is not None: diff --git a/tsai/models/HydraPlus.py b/tsai/models/HydraPlus.py index 813dd701e..8507311dc 100644 --- a/tsai/models/HydraPlus.py +++ b/tsai/models/HydraPlus.py @@ -27,7 +27,7 @@ def __init__(self, c_in, c_out, seq_len, k = 8, g = 64, max_c_in = 8, clip=True, max_exponent = np.log2((seq_len - 1) / (9 - 1)) # kernel length = 9 - self.dilations = 2 ** torch.arange(int(max_exponent) + 1) + self.dilations = 2 ** torch.arange(int(max_exponent) + 1, device=device) self.num_dilations = len(self.dilations) self.paddings = torch.div((9 - 1) * self.dilations, 2, rounding_mode = "floor").int() @@ -36,14 +36,14 @@ def __init__(self, c_in, c_out, seq_len, k = 8, g = 64, max_c_in = 8, clip=True, divisor = 2 if self.g > 1 else 1 _g = g // divisor self._g = _g - self.W = [self.normalize(torch.randn(divisor, k * _g, 1, 9).to(device=device)) for _ in range(self.num_dilations)] + self.W = [self.normalize(torch.randn(divisor, k * _g, 1, 9)).to(device=device) for _ in range(self.num_dilations)] + - # combine c_in // 2 channels (2 < n < max_c_in) c_in_per = np.clip(c_in // 2, 2, max_c_in) - self.I = [torch.randint(0, c_in, (divisor, _g, c_in_per)).to(device=device) for _ in range(self.num_dilations)] + self.I = [torch.randint(0, c_in, (divisor, _g, c_in_per), device=device) for _ in range(self.num_dilations)] - # clip values + # clip values self.clip = clip self.device = device @@ -89,7 +89,6 @@ def forward(self, X): # diff_index == 0 -> X # diff_index == 1 -> diff(X) for diff_index in range(min(2, self.g)): - _Z = F.conv1d(X[:, self.I[dilation_index][diff_index]].sum(2) if diff_index == 0 else diff_X[:, self.I[dilation_index][diff_index]].sum(2), self.W[dilation_index][diff_index], dilation = d, padding = p, groups = self._g).view(bs, self._g, self.k, -1) @@ -115,7 +114,7 @@ def forward(self, X): # %% ../../nbs/079_models.HydraPlus.ipynb 5 class HydraPlus(nn.Sequential): - def __init__(self, + def __init__(self, c_in:int, # num of channels in input c_out:int, # num of channels in output seq_len:int, # sequence length @@ -123,7 +122,7 @@ def __init__(self, k:int=8, # number of kernels per group g:int=64, # number of groups max_c_in:int=8, # max number of channels per group - clip:bool=True, # clip values >= 0 + clip:bool=True, # clip values >= 0 use_bn:bool=True, # use batch norm fc_dropout:float=0., # dropout probability custom_head:Any=None, # optional custom head as a torch.nn.Module or Callable @@ -139,7 +138,7 @@ def __init__(self, # Head self.head_nf = num_features - if custom_head is not None: + if custom_head is not None: if isinstance(custom_head, nn.Module): head = custom_head else: head = custom_head(self.head_nf, c_out, 1) elif d is not None: diff --git a/tsai/models/MultiRocketPlus.py b/tsai/models/MultiRocketPlus.py index 0179e26f2..e0adc21a0 100644 --- a/tsai/models/MultiRocketPlus.py +++ b/tsai/models/MultiRocketPlus.py @@ -18,17 +18,26 @@ class Flatten(nn.Module): def forward(self, x): return x.view(x.size(0), -1) # %% ../../nbs/076_models.MultiRocketPlus.ipynb 5 -def _LPVV(o_pos, dim=2): - "Longest stretch of positive values (-1, 1)" - shape = list(o_pos.shape) - shape[dim] = 1 - o_pos = torch.cat([torch.zeros(shape, device=o_pos.device), o_pos], dim) - o_arange_shape = [1] * o_pos.ndim - o_arange_shape[dim] = -1 - o_arange = torch.arange(o_pos.shape[dim], device=o_pos.device).reshape(o_arange_shape) - o_pos = torch.where(o_pos == 1, 0, o_arange) - o_pos = o_pos.cummax(dim).values - return ((o_arange - o_pos).max(dim).values / (o_pos.shape[dim] - 1)) * 2 - 1 +def _LPVV(o, dim=2): + "Longest stretch of positive values along a dimension(-1, 1)" + + seq_len = o.shape[dim] + binary_tensor = (o > 0).float() + + diff = torch.cat([torch.ones_like(binary_tensor.narrow(dim, 0, 1)), + binary_tensor.narrow(dim, 1, seq_len-1) - binary_tensor.narrow(dim, 0, seq_len-1)], dim=dim) + + groups = (diff > 0).cumsum(dim) + + # Ensure groups are within valid index bounds + groups = groups * binary_tensor.long() + valid_groups = groups.where(groups < binary_tensor.size(dim), torch.tensor(0, device=groups.device)) + + counts = torch.zeros_like(binary_tensor).scatter_add_(dim, valid_groups, binary_tensor) + + longest_stretch = counts.max(dim)[0] + + return torch.nan_to_num(2 * (longest_stretch / seq_len) - 1) def _MPV(o, dim=2): "Mean of Positive Values (any positive value)" @@ -56,13 +65,13 @@ def _PPV(o_pos, dim=2): "Proportion of Positive Values (-1, 1)" return (o_pos).float().mean(dim) * 2 - 1 -# %% ../../nbs/076_models.MultiRocketPlus.ipynb 6 +# %% ../../nbs/076_models.MultiRocketPlus.ipynb 11 class MultiRocketFeaturesPlus(nn.Module): fitting = False def __init__(self, c_in, seq_len, num_features=10_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=9, max_num_kernels=84, diff=False): super(MultiRocketFeaturesPlus, self).__init__() - + self.c_in, self.seq_len = c_in, seq_len self.kernel_size, self.max_num_channels = kernel_size, max_num_channels @@ -90,7 +99,7 @@ def __init__(self, c_in, seq_len, num_features=10_000, max_dilations_per_kernel= self.register_buffer('prefit', torch.BoolTensor([False])) def forward(self, x): - + _features = [] for i, (dilation, padding) in enumerate(zip(self.dilations, self.padding)): _padding1 = i % 2 @@ -134,11 +143,11 @@ def fit(self, X, chunksize=None): num_samples = X.shape[0] if chunksize is None: chunksize = min(num_samples, self.num_dilations * self.num_kernels) - else: + else: chunksize = min(num_samples, chunksize) idxs = np.random.choice(num_samples, chunksize, False) self.fitting = True - if isinstance(X, np.ndarray): + if isinstance(X, np.ndarray): self(torch.from_numpy(X[idxs]).to(self.kernels.device)) else: self(X[idxs].to(self.kernels.device)) @@ -228,12 +237,12 @@ def get_indices(self, kernel_size, max_num_kernels): len(indices), max_num_kernels, False))] return indices, pos_values -# %% ../../nbs/076_models.MultiRocketPlus.ipynb 7 +# %% ../../nbs/076_models.MultiRocketPlus.ipynb 12 class MultiRocketBackbonePlus(nn.Module): def __init__(self, c_in, seq_len, num_features=50_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=None, max_num_kernels=84, use_diff=True): super(MultiRocketBackbonePlus, self).__init__() - - num_features_per_branch = num_features // (1 + use_diff) + + num_features_per_branch = num_features // (1 + use_diff) self.branch_x = MultiRocketFeaturesPlus(c_in, seq_len, num_features=num_features_per_branch, max_dilations_per_kernel=max_dilations_per_kernel, kernel_size=kernel_size, max_num_channels=max_num_channels, max_num_kernels=max_num_kernels) if use_diff: @@ -244,7 +253,7 @@ def __init__(self, c_in, seq_len, num_features=50_000, max_dilations_per_kernel= else: self.num_features = self.branch_x.num_features * 4 self.use_diff = use_diff - + def forward(self, x): if self.use_diff: x_features = self.branch_x(x) @@ -255,7 +264,7 @@ def forward(self, x): output = self.branch_x(x) return output -# %% ../../nbs/076_models.MultiRocketPlus.ipynb 8 +# %% ../../nbs/076_models.MultiRocketPlus.ipynb 13 class MultiRocketPlus(nn.Sequential): def __init__(self, c_in, c_out, seq_len, d=None, num_features=50_000, max_dilations_per_kernel=32, kernel_size=9, max_num_channels=None, max_num_kernels=84, @@ -268,7 +277,7 @@ def __init__(self, c_in, c_out, seq_len, d=None, num_features=50_000, max_dilati # Head self.head_nf = num_features - if custom_head is not None: + if custom_head is not None: if isinstance(custom_head, nn.Module): head = custom_head else: head = custom_head(self.head_nf, c_out, 1) elif d is not None: diff --git a/tsai/models/multimodal.py b/tsai/models/multimodal.py index 861da95a1..1a04af155 100644 --- a/tsai/models/multimodal.py +++ b/tsai/models/multimodal.py @@ -28,7 +28,7 @@ def _to_list(idx): return [idx] elif isinstance(idx, list): return idx - + def get_o_cont_idxs(c_in, s_cat_idxs=None, s_cont_idxs=None, o_cat_idxs=None): "Calculate the indices of the observed continuous features." @@ -52,7 +52,7 @@ def get_feat_idxs(c_in, s_cat_idxs=None, s_cont_idxs=None, o_cat_idxs=None, o_co # %% ../../nbs/077_models.multimodal.ipynb 6 class TensorSplitter(nn.Module): - def __init__(self, + def __init__(self, s_cat_idxs:list=None, # list of indices for static categorical variables s_cont_idxs:list=None, # list of indices for static continuous variables o_cat_idxs:list=None, # list of indices for observed categorical variables @@ -119,7 +119,7 @@ def forward(self, input_tensor): # %% ../../nbs/077_models.multimodal.ipynb 9 class Embeddings(nn.Module): "Embedding layers for each categorical variable in a 2D or 3D tensor" - def __init__(self, + def __init__(self, n_embeddings:list, # List of num_embeddings for each categorical variable embedding_dims:list=None, # List of embedding dimensions for each categorical variable padding_idx:int=0, # Embedding padding_idx @@ -134,9 +134,9 @@ def __init__(self, embedding_dims = [emb_sz_rule(s) if s is None else s for s in n_embeddings] assert len(n_embeddings) == len(embedding_dims) self.embedding_dims = sum(embedding_dims) - self.embedding_layers = nn.ModuleList([nn.Sequential(nn.Embedding(n,d,padding_idx=padding_idx, **kwargs), + self.embedding_layers = nn.ModuleList([nn.Sequential(nn.Embedding(n,d,padding_idx=padding_idx, **kwargs), nn.Dropout(embed_dropout)) for n,d in zip(n_embeddings, embedding_dims)]) - + def forward(self, x): if x.ndim == 2: return torch.cat([e(x[:,i].long()) for i,e in enumerate(self.embedding_layers)],1) @@ -216,7 +216,7 @@ def __init__(self, **kwargs ): super().__init__() - + # attributes c_in = c_in or dls.vars seq_len = seq_len or dls.len @@ -229,7 +229,7 @@ def __init__(self, self.splitter = TensorSplitter(s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs) s_cat_idxs, s_cont_idxs, o_cat_idxs, o_cont_idxs = self.splitter.s_cat_idxs, self.splitter.s_cont_idxs, self.splitter.o_cat_idxs, self.splitter.o_cont_idxs assert c_in == sum([len(s_cat_idxs), len(s_cont_idxs), len(o_cat_idxs), len(o_cont_idxs)]) - + # embeddings self.s_embeddings = Embeddings(s_cat_embeddings, s_cat_embedding_dims) if s_cat_idxs else nn.Identity() self.o_embeddings = Embeddings(o_cat_embeddings, o_cat_embedding_dims) if o_cat_idxs else nn.Identity() @@ -243,7 +243,7 @@ def __init__(self, else: self.patch_encoder = nn.Identity() c_mult = 1 - + # backbone n_s_features = len(s_cont_idxs) + (self.s_embeddings.embedding_dims if s_cat_idxs else 0) n_o_features = (len(o_cont_idxs) + (self.o_embeddings.embedding_dims if o_cat_idxs else 0)) * c_mult @@ -274,10 +274,10 @@ def forward(self, x): # contatenate observed features o_x = torch.cat([o_cat, o_cont], 1) - + # patch encoder o_x = self.patch_encoder(o_x) - + # pass static and observed features through their respective backbones o_x = self.o_backbone(o_x) @@ -312,12 +312,12 @@ def __init__(self, custom_head=None, # custom head to replace the default head **kwargs ): - + # create backbone - backbone = MultInputBackboneWrapper(arch, c_in=c_in, seq_len=seq_len, d=d, dls=dls, s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, - s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, + backbone = MultInputBackboneWrapper(arch, c_in=c_in, seq_len=seq_len, d=d, dls=dls, s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, + s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, patch_len=patch_len, patch_stride=patch_stride, fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, **kwargs) - + # create head self.head_nf = backbone.head_nf self.c_out = c_out @@ -328,4 +328,4 @@ def __init__(self, else: head = nn.Linear(self.head_nf, c_out) super().__init__(OrderedDict([('backbone', backbone), ('head', head)])) - + diff --git a/tsai/tslearner.py b/tsai/tslearner.py index 1b2554091..e22802ecb 100644 --- a/tsai/tslearner.py +++ b/tsai/tslearner.py @@ -18,10 +18,10 @@ # %% ../nbs/022_tslearner.ipynb 5 class TSClassifier(Learner): - def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, - s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, + def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, + s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None, - patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, + patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, weights=None, partial_n=None, vocab=None, train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None, shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None, @@ -32,28 +32,28 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # Seed if seed is not None: set_seed(seed, reproducible=True) - + # Batch size if batch_size is not None: bs = batch_size # DataLoaders dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, vocab=vocab, - path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, + path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, device=device, shuffle_train=shuffle_train, drop_last=drop_last) - + if loss_func is None: if hasattr(dls, 'loss_func'): loss_func = dls.loss_func elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat() elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func else: loss_func = CrossEntropyLossFlat() - + # Model - if isinstance(arch, nn.Module): + if isinstance(arch, nn.Module): model = arch - if arch_config: + if arch_config: warnings.warn("You have passed arch_config to a model that is already intantiated. It will not have any effect.", UserWarning) - if init is not None: + if init is not None: warnings.warn("You have passed init to a model that is already intantiated. It will not have any effect.", UserWarning) else: if init is True: @@ -68,43 +68,43 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # else: # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) - model = build_ts_model(arch, dls=dls, - s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, + model = build_ts_model(arch, dls=dls, + s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, - patch_len=patch_len, patch_stride=patch_stride, - fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, + patch_len=patch_len, patch_stride=patch_stride, + fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) try: setattr(model, "__name__", arch.__name__) except: setattr(model, "__name__", arch.__class__.__name__) - + if hasattr(model, "backbone") and hasattr(model, "head"): splitter = ts_splitter - + if pipelines is not None: pipelines = listify(pipelines) setattr(self, "pipelines", pipelines) - + super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter, model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms) if hasattr(self, "recorder"): self.recorder.train_metrics = train_metrics if splits is None or not hasattr(splits[0], "__len__") or len(splits) == 1 or \ - (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): + (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): self.recorder.valid_metrics = False else: self.recorder.valid_metrics = valid_metrics # %% ../nbs/022_tslearner.ipynb 11 class TSRegressor(Learner): - def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, - s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, + def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, + s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None, - patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, - weights=None, partial_n=None, + patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, + weights=None, partial_n=None, train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None, shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None, arch=None, arch_config={}, pretrained=False, weights_path=None, exclude_head=True, cut=-1, init=None, @@ -114,15 +114,15 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # Seed if seed is not None: set_seed(seed, reproducible=True) - - + + # Batch size if batch_size is not None: bs = batch_size # DataLoaders - dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, - path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, + dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, + path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, device=device, shuffle_train=shuffle_train, drop_last=drop_last) if loss_func is None: @@ -130,13 +130,13 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat() elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func else: loss_func = MSELossFlat() - + # Model - if isinstance(arch, nn.Module): + if isinstance(arch, nn.Module): model = arch - if arch_config: + if arch_config: warnings.warn("You have passed arch_config to a model that is already intantiated. It will not have any effect.", UserWarning) - if init is not None: + if init is not None: warnings.warn("You have passed init to a model that is already intantiated. It will not have any effect.", UserWarning) else: if init is True: @@ -151,10 +151,10 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # else: # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) - model = build_ts_model(arch, dls=dls, - s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, + model = build_ts_model(arch, dls=dls, + s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, - patch_len=patch_len, patch_stride=patch_stride, + patch_len=patch_len, patch_stride=patch_stride, fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) @@ -162,32 +162,32 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non setattr(model, "__name__", arch.__name__) except: setattr(model, "__name__", arch.__class__.__name__) - + if hasattr(model, "backbone") and hasattr(model, "head"): splitter = ts_splitter - + if pipelines is not None: pipelines = listify(pipelines) setattr(self, "pipelines", pipelines) super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter, - model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms) - + model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms) + if hasattr(self, "recorder"): self.recorder.train_metrics = train_metrics if splits is None or not hasattr(splits[0], "__len__") or len(splits) == 1 or \ - (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): + (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): self.recorder.valid_metrics = False else: self.recorder.valid_metrics = valid_metrics # %% ../nbs/022_tslearner.ipynb 14 class TSForecaster(Learner): - def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, - s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, + def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=None, sel_steps=None, + s_cat_idxs=None, s_cat_embeddings=None, s_cat_embedding_dims=None, s_cont_idxs=None, o_cat_idxs=None, o_cat_embeddings=None, o_cat_embedding_dims=None, o_cont_idxs=None, - patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, - weights=None, partial_n=None, + patch_len=None, patch_stride=None, fusion_layers=128, fusion_act='relu', fusion_dropout=0., fusion_use_bn=True, + weights=None, partial_n=None, train_metrics=False, valid_metrics=True, bs=[64, 128], batch_size=None, batch_tfms=None, pipelines=None, shuffle_train=True, drop_last=True, num_workers=0, do_setup=True, device=None, seed=None, arch=None, arch_config={}, pretrained=False, weights_path=None, exclude_head=True, cut=-1, init=None, @@ -197,28 +197,28 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # Seed if seed is not None: set_seed(seed, reproducible=True) - + # Batch size if batch_size is not None: bs = batch_size # DataLoaders - dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, - path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, + dls = get_ts_dls(X, y=y, splits=splits, sel_vars=sel_vars, sel_steps=sel_steps, tfms=tfms, inplace=inplace, + path=path, bs=bs, batch_tfms=batch_tfms, num_workers=num_workers, weights=weights, partial_n=partial_n, device=device, shuffle_train=shuffle_train, drop_last=drop_last) - + if loss_func is None: if hasattr(dls, 'loss_func'): loss_func = dls.loss_func elif hasattr(dls, 'cat') and not dls.cat: loss_func = MSELossFlat() elif hasattr(dls, 'train_ds') and hasattr(dls.train_ds, 'loss_func'): loss_func = dls.train_ds.loss_func else: loss_func = MSELossFlat() - + # Model - if isinstance(arch, nn.Module): + if isinstance(arch, nn.Module): model = arch - if arch_config: + if arch_config: warnings.warn("You have passed arch_config to a model that is already intantiated. It will not have any effect.", UserWarning) - if init is not None: + if init is not None: warnings.warn("You have passed init to a model that is already intantiated. It will not have any effect.", UserWarning) else: if init is True: @@ -233,10 +233,10 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non # else: # model = build_ts_model(arch, dls=dls, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, # exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) - model = build_ts_model(arch, dls=dls, - s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, + model = build_ts_model(arch, dls=dls, + s_cat_idxs=s_cat_idxs, s_cat_embeddings=s_cat_embeddings, s_cat_embedding_dims=s_cat_embedding_dims, s_cont_idxs=s_cont_idxs, o_cat_idxs=o_cat_idxs, o_cat_embeddings=o_cat_embeddings, o_cat_embedding_dims=o_cat_embedding_dims, o_cont_idxs=o_cont_idxs, - patch_len=patch_len, patch_stride=patch_stride, + patch_len=patch_len, patch_stride=patch_stride, fusion_layers=fusion_layers, fusion_act=fusion_act, fusion_dropout=fusion_dropout, fusion_use_bn=fusion_use_bn, device=device, verbose=verbose, pretrained=pretrained, weights_path=weights_path, exclude_head=exclude_head, cut=cut, init=init, arch_config=arch_config) @@ -244,21 +244,21 @@ def __init__(self, X, y=None, splits=None, tfms=None, inplace=True, sel_vars=Non setattr(model, "__name__", arch.__name__) except: setattr(model, "__name__", arch.__class__.__name__) - + if hasattr(model, "backbone") and hasattr(model, "head"): splitter = ts_splitter - + if pipelines is not None: pipelines = listify(pipelines) setattr(self, "pipelines", pipelines) super().__init__(dls, model, loss_func=loss_func, opt_func=opt_func, lr=lr, cbs=cbs, metrics=metrics, path=path, splitter=splitter, model_dir=model_dir, wd=wd, wd_bn_bias=wd_bn_bias, train_bn=train_bn, moms=moms) - + if hasattr(self, "recorder"): self.recorder.train_metrics = train_metrics if splits is None or not hasattr(splits[0], "__len__") or len(splits) == 1 or \ - (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): + (len(splits) >= 2 and (splits[1] is None or not hasattr(splits[1], "__len__"))): self.recorder.valid_metrics = False else: self.recorder.valid_metrics = valid_metrics