%load_ext autoreload %autoreload 2 %matplotlib inline #export from exp.nb_07a import * datasets.URLs.IMAGENETTE_160 path = datasets.untar_data(datasets.URLs.IMAGENETTE_160) path #export import PIL,os,mimetypes Path.ls = lambda x: list(x.iterdir()) path.ls() (path/'val').ls() path_tench = path/'val'/'n01440764' img_fn = path_tench.ls()[0] img_fn img = PIL.Image.open(img_fn) img plt.imshow(img) import numpy imga = numpy.array(img) imga.shape imga[:10,:10,0] #export image_extensions = set(k for k,v in mimetypes.types_map.items() if v.startswith('image/')) ' '.join(image_extensions) #export def setify(o): return o if isinstance(o,set) else set(listify(o)) test_eq(setify('aa'), {'aa'}) test_eq(setify(['aa',1]), {'aa',1}) test_eq(setify(None), set()) test_eq(setify(1), {1}) test_eq(setify({1}), {1}) #export def _get_files(p, fs, extensions=None): p = Path(p) res = [p/f for f in fs if not f.startswith('.') and ((not extensions) or f'.{f.split(".")[-1].lower()}' in extensions)] return res t = [o.name for o in os.scandir(path_tench)] t = _get_files(path, t, extensions=image_extensions) t[:3] #export def get_files(path, extensions=None, recurse=False, include=None): path = Path(path) extensions = setify(extensions) extensions = {e.lower() for e in extensions} if recurse: res = [] for i,(p,d,f) in enumerate(os.walk(path)): # returns (dirpath, dirnames, filenames) if include is not None and i==0: d[:] = [o for o in d if o in include] else: d[:] = [o for o in d if not o.startswith('.')] res += _get_files(p, f, extensions) return res else: f = [o.name for o in os.scandir(path) if o.is_file()] return _get_files(path, f, extensions) get_files(path_tench, image_extensions)[:3] get_files(path, image_extensions, recurse=True)[:3] all_fns = get_files(path, image_extensions, recurse=True) len(all_fns) %timeit -n 10 get_files(path, image_extensions, recurse=True) #export def compose(x, funcs, *args, order_key='_order', **kwargs): key = lambda o: getattr(o, order_key, 0) for f in sorted(listify(funcs), key=key): x = f(x, **kwargs) return x class ItemList(ListContainer): def __init__(self, items, path='.', tfms=None): super().__init__(items) self.path,self.tfms = Path(path),tfms def __repr__(self): return f'{super().__repr__()}\nPath: {self.path}' def new(self, items, cls=None): if cls is None: cls=self.__class__ return cls(items, self.path, tfms=self.tfms) def get(self, i): return i def _get(self, i): return compose(self.get(i), self.tfms) def __getitem__(self, idx): res = super().__getitem__(idx) if isinstance(res,list): return [self._get(o) for o in res] return self._get(res) class ImageList(ItemList): @classmethod def from_files(cls, path, extensions=None, recurse=True, include=None, **kwargs): if extensions is None: extensions = image_extensions return cls(get_files(path, extensions, recurse=recurse, include=include), path, **kwargs) def get(self, fn): return PIL.Image.open(fn) #export class Transform(): _order=0 class MakeRGB(Transform): def __call__(self, item): return item.convert('RGB') def make_rgb(item): return item.convert('RGB') il = ImageList.from_files(path, tfms=make_rgb) il img = il[0]; img il[:1] fn = il.items[0]; fn fn.parent.parent.name #export def grandparent_splitter(fn, valid_name='valid', train_name='train'): gp = fn.parent.parent.name return True if gp==valid_name else False if gp==train_name else None def split_by_func(items, f): mask = [f(o) for o in items] # `None` values will be filtered out f = [o for o,m in zip(items,mask) if m==False] t = [o for o,m in zip(items,mask) if m==True ] return f,t splitter = partial(grandparent_splitter, valid_name='val') %time train,valid = split_by_func(il, splitter) len(train),len(valid) #export class SplitData(): def __init__(self, train, valid): self.train,self.valid = train,valid def __getattr__(self,k): return getattr(self.train,k) #This is needed if we want to pickle SplitData and be able to load it back without recursion errors def __setstate__(self,data:Any): self.__dict__.update(data) @classmethod def split_by_func(cls, il, f): lists = map(il.new, split_by_func(il.items, f)) return cls(*lists) def __repr__(self): return f'{self.__class__.__name__}\nTrain: {self.train}\nValid: {self.valid}\n' sd = SplitData.split_by_func(il, splitter); sd #export from collections import OrderedDict def uniqueify(x, sort=False): res = list(OrderedDict.fromkeys(x).keys()) if sort: res.sort() return res #export class Processor(): def process(self, items): return items class CategoryProcessor(Processor): def __init__(self): self.vocab=None def __call__(self, items): #The vocab is defined on the first use. if self.vocab is None: self.vocab = uniqueify(items) self.otoi = {v:k for k,v in enumerate(self.vocab)} return [self.proc1(o) for o in items] def proc1(self, item): return self.otoi[item] def deprocess(self, idxs): assert self.vocab is not None return [self.deproc1(idx) for idx in idxs] def deproc1(self, idx): return self.vocab[idx] #export def parent_labeler(fn): return fn.parent.name def _label_by_func(ds, f, cls=ItemList): return cls([f(o) for o in ds.items], path=ds.path) #This is a slightly different from what was seen during the lesson, # we'll discuss the changes in lesson 11 class LabeledData(): def process(self, il, proc): return il.new(compose(il.items, proc)) def __init__(self, x, y, proc_x=None, proc_y=None): self.x,self.y = self.process(x, proc_x),self.process(y, proc_y) self.proc_x,self.proc_y = proc_x,proc_y def __repr__(self): return f'{self.__class__.__name__}\nx: {self.x}\ny: {self.y}\n' def __getitem__(self,idx): return self.x[idx],self.y[idx] def __len__(self): return len(self.x) def x_obj(self, idx): return self.obj(self.x, idx, self.proc_x) def y_obj(self, idx): return self.obj(self.y, idx, self.proc_y) def obj(self, items, idx, procs): isint = isinstance(idx, int) or (isinstance(idx,torch.LongTensor) and not idx.ndim) item = items[idx] for proc in reversed(listify(procs)): item = proc.deproc1(item) if isint else proc.deprocess(item) return item @classmethod def label_by_func(cls, il, f, proc_x=None, proc_y=None): return cls(il, _label_by_func(il, f), proc_x=proc_x, proc_y=proc_y) def label_by_func(sd, f, proc_x=None, proc_y=None): train = LabeledData.label_by_func(sd.train, f, proc_x=proc_x, proc_y=proc_y) valid = LabeledData.label_by_func(sd.valid, f, proc_x=proc_x, proc_y=proc_y) return SplitData(train,valid) ll = label_by_func(sd, parent_labeler, proc_y=CategoryProcessor()) assert ll.train.proc_y is ll.valid.proc_y ll.train.y ll.train.y.items[0], ll.train.y_obj(0), ll.train.y_obj(slice(2)) ll ll.train[0] ll.train[0][0] ll.train[0][0].resize((128,128)) #export class ResizeFixed(Transform): _order=10 def __init__(self,size): if isinstance(size,int): size=(size,size) self.size = size def __call__(self, item): return item.resize(self.size, PIL.Image.BILINEAR) def to_byte_tensor(item): res = torch.ByteTensor(torch.ByteStorage.from_buffer(item.tobytes())) w,h = item.size return res.view(h,w,-1).permute(2,0,1) to_byte_tensor._order=20 def to_float_tensor(item): return item.float().div_(255.) to_float_tensor._order=30 tfms = [make_rgb, ResizeFixed(128), to_byte_tensor, to_float_tensor] il = ImageList.from_files(path, tfms=tfms) sd = SplitData.split_by_func(il, splitter) ll = label_by_func(sd, parent_labeler, proc_y=CategoryProcessor()) #export def show_image(im, figsize=(3,3)): plt.figure(figsize=figsize) plt.axis('off') plt.imshow(im.permute(1,2,0)) x,y = ll.train[0] x.shape show_image(x) bs=64 train_dl,valid_dl = get_dls(ll.train,ll.valid,bs, num_workers=4) x,y = next(iter(train_dl)) x.shape show_image(x[0]) ll.train.proc_y.vocab[y[0]] y #export class DataBunch(): def __init__(self, train_dl, valid_dl, c_in=None, c_out=None): self.train_dl,self.valid_dl,self.c_in,self.c_out = train_dl,valid_dl,c_in,c_out @property def train_ds(self): return self.train_dl.dataset @property def valid_ds(self): return self.valid_dl.dataset #export def databunchify(sd, bs, c_in=None, c_out=None, **kwargs): dls = get_dls(sd.train, sd.valid, bs, **kwargs) return DataBunch(*dls, c_in=c_in, c_out=c_out) SplitData.to_databunch = databunchify path = datasets.untar_data(datasets.URLs.IMAGENETTE_160) tfms = [make_rgb, ResizeFixed(128), to_byte_tensor, to_float_tensor] il = ImageList.from_files(path, tfms=tfms) sd = SplitData.split_by_func(il, partial(grandparent_splitter, valid_name='val')) ll = label_by_func(sd, parent_labeler, proc_y=CategoryProcessor()) data = ll.to_databunch(bs, c_in=3, c_out=10, num_workers=4) cbfs = [partial(AvgStatsCallback,accuracy), CudaCallback] m,s = x.mean((0,2,3)).cuda(),x.std((0,2,3)).cuda() m,s #export def normalize_chan(x, mean, std): return (x-mean[...,None,None]) / std[...,None,None] _m = tensor([0.47, 0.48, 0.45]) _s = tensor([0.29, 0.28, 0.30]) norm_imagenette = partial(normalize_chan, mean=_m.cuda(), std=_s.cuda()) cbfs.append(partial(BatchTransformXCallback, norm_imagenette)) nfs = [64,64,128,256] #export import math def prev_pow_2(x): return 2**math.floor(math.log2(x)) def get_cnn_layers(data, nfs, layer, **kwargs): def f(ni, nf, stride=2): return layer(ni, nf, 3, stride=stride, **kwargs) l1 = data.c_in l2 = prev_pow_2(l1*3*3) layers = [f(l1 , l2 , stride=1), f(l2 , l2*2, stride=2), f(l2*2, l2*4, stride=2)] nfs = [l2*4] + nfs layers += [f(nfs[i], nfs[i+1]) for i in range(len(nfs)-1)] layers += [nn.AdaptiveAvgPool2d(1), Lambda(flatten), nn.Linear(nfs[-1], data.c_out)] return layers def get_cnn_model(data, nfs, layer, **kwargs): return nn.Sequential(*get_cnn_layers(data, nfs, layer, **kwargs)) def get_learn_run(nfs, data, lr, layer, cbs=None, opt_func=None, **kwargs): model = get_cnn_model(data, nfs, layer, **kwargs) init_cnn(model) return get_runner(model, data, lr=lr, cbs=cbs, opt_func=opt_func) sched = combine_scheds([0.3,0.7], cos_1cycle_anneal(0.1,0.3,0.05)) learn,run = get_learn_run(nfs, data, 0.2, conv_layer, cbs=cbfs+[ partial(ParamScheduler, 'lr', sched) ]) #export def model_summary(run, learn, data, find_all=False): xb,yb = get_batch(data.valid_dl, run) device = next(learn.model.parameters()).device#Model may not be on the GPU yet xb,yb = xb.to(device),yb.to(device) mods = find_modules(learn.model, is_lin_layer) if find_all else learn.model.children() f = lambda hook,mod,inp,out: print(f"{mod}\n{out.shape}\n") with Hooks(mods, f) as hooks: learn.model(xb) model_summary(run, learn, data) %time run.fit(5, learn) !python notebook2script.py 08_data_block.ipynb