Fastai v2 daily code walk-thrus

Thanks for the response! I understand the motivation behind the design now. Very elegant!

1 Like

Yes the metaclass system in Python is such a nice design! :slight_smile: It’s simple and elegant and powerful.

@jeremy

Hello Jeremy :slight_smile:
What will we be looking at today? It will help me if I look at the code before walk through

I believe Jeremy said he had a prior engagement today and we wouldn’t be having a code walkthrough today but somebody should definitely confirm that.

1 Like

I seem to recall he was giving a talk :slight_smile:

Yes, there is no code walk-thru today.

2 Likes

going through the first code walk-through noticed 07_vision_core, there seems to be some import statement differences between my recent git clone of fastai/fastai_dev (from local.torch_basics import *) is different from what is on the Jeremy’s video. Any reason?

1 Like

Its still under heavy development so expect changes everyday.

1 Like

Will there be a code walk-thru today?

Yes should be.

3 Likes

Thanks! The reason why I am asking is not to bother you but that I need to stay up late if there is (I’m from Germany).

3 Likes

Today’s live stream: https://youtu.be/GcMGchBJeXk

Walk-thru 5 video added: https://youtu.be/GcMGchBJeXk

2 Likes

A post was merged into an existing topic: Fastai v2 code walk-thru 5

I figured as to how @Transform works out for a function defined with this decorator. Let us take the example of the normalisation function that was used in code walkthrough 4.

def _norm(x,m,s): return (x-m)/s
norm_t = Transform(_norm)

I did a %%debug on norm_t = Transform(_norm). I found that the first thing the code was doing was calling __call__ of _TfmMeta as Transform uses the meta class _TfmMeta.

def __call__(cls, *args, **kwargs):
        f = args[0] if args else None
        n = getattr(f,'__name__',None)
        if not hasattr(cls,'encodes'): cls.encodes=TypeDispatch()
        if not hasattr(cls,'decodes'): cls.decodes=TypeDispatch()
        if isinstance(f,Callable) and n in ('decodes','encodes','_'):
            getattr(cls,'encodes' if n=='_' else n).add(f)
            return f
        return super().__call__(*args, **kwargs)

Here the cls is the Transform class and the function _norm is in args. f becomes _norm as args[0] is _norm. There are no encodes and decodes set here and neither is n in _ or encodes or decodes. So the last line of the function super().call(*args, **kwargs) gets called.

I was surprised to see that super is Transform class and call is calling init of Transform. But here on the behaviour was predictable. If you follow the debugger snapshot pasted below it will be clear that the flow of events is as follows:

  1. enc is set to _norm.

  2. init_enc is set to enc (which is now _norm)

  3. The existing encodes and decodes of the Transform are deleted

  4. encodes and decodes now become TypeDispatch()

  5. The enc is added to encodes. Therefore _norm is now a part of self.encodes which allows to use _norm as an encodes function call.

  6. The final output is Transform: False {'object': '_norm'} {}

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(140)init()
    138 filt,init_enc,as_item_force,as_item,order = None,False,None,True,0
    139 def init(self, enc=None, dec=None, filt=None, as_item=False):
    –> 140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
    141 self.init_enc = enc or dec
    142 if not self.init_enc: return

    ipdb> enc
    <function _norm at 0x12ceef830>
    ipdb> dec
    ipdb> filt
    ipdb> as_item
    False
    ipdb> init_enc
    *** NameError: name ‘init_enc’ is not defined
    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(141)init()
    139 def init(self, enc=None, dec=None, filt=None, as_item=False):
    140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
    –> 141 self.init_enc = enc or dec
    142 if not self.init_enc: return
    143

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(142)init()
    140 self.filt,self.as_item = ifnone(filt, self.filt),as_item
    141 self.init_enc = enc or dec
    –> 142 if not self.init_enc: return
    143
    144 # Passing enc/dec, so need to remove (base) class level enc/dec

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(145)init()
    143
    144 # Passing enc/dec, so need to remove (base) class level enc/dec
    –> 145 del(self.class.encodes,self.class.decodes)
    146 self.encodes,self.decodes = (TypeDispatch(),TypeDispatch())
    147 if enc:

    ipdb> self.class
    <class ‘local.data.transform.Transform’>
    ipdb> self.class.encodes
    {}
    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(146)init()
    144 # Passing enc/dec, so need to remove (base) class level enc/dec
    145 del(self.class.encodes,self.class.decodes)
    –> 146 self.encodes,self.decodes = (TypeDispatch(),TypeDispatch())
    147 if enc:
    148 self.encodes.add(enc)

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(147)init()
    145 del(self.class.encodes,self.class.decodes)
    146 self.encodes,self.decodes = (TypeDispatch(),TypeDispatch())
    –> 147 if enc:
    148 self.encodes.add(enc)
    149 self.order = getattr(self.encodes,‘order’,self.order)

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(148)init()
    146 self.encodes,self.decodes = (TypeDispatch(),TypeDispatch())
    147 if enc:
    –> 148 self.encodes.add(enc)
    149 self.order = getattr(self.encodes,‘order’,self.order)
    150 if dec: self.decodes.add(dec)

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(149)init()
    147 if enc:
    148 self.encodes.add(enc)
    –> 149 self.order = getattr(self.encodes,‘order’,self.order)
    150 if dec: self.decodes.add(dec)
    151

    ipdb> n

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(150)init()
    148 self.encodes.add(enc)
    149 self.order = getattr(self.encodes,‘order’,self.order)
    –> 150 if dec: self.decodes.add(dec)
    151
    152 @property

    ipdb> n
    –Return–
    None

    /Users/i077725/Documents/GitHub/fastai_dev/dev/local/data/transform.py(150)init()
    148 self.encodes.add(enc)
    149 self.order = getattr(self.encodes,‘order’,self.order)
    –> 150 if dec: self.decodes.add(dec)
    151
    152 @property

    ipdb> n
    –Return–
    Transform: Fa…’: ‘_norm’} {}

I am surprised as to how the super().call() delegates to init() of Transform and how the super() of a call inside _TfmMeta refers to Transform class. Any thoughts?

@jeremy and others, Is there sort of a playlist on youtube for these walkthroughs which I can watch in sequence. I missed a couple and want to catch up on them. Thanks in advance (and thanks so much for doing these! )

Hi, all the youtube links are right here in this same thread/forum. Please scroll up and you can see them for all the walkthroughs.

Not a playlist but they’re all on youtube:

https://www.youtube.com/results?search_query=fastai+v2

1 Like

@pnvijay @sairam6087 and anyone else wanting a playlist:

https://www.youtube.com/playlist?list=PLZqTTicEKsnG_DvtXKGp8iWHfECmivi7U

Jeremy’s playlist is on his channel :slight_smile:

2 Likes

Note that it’s not a subclass of _TfmMeta - but it uses _TfmMeta as its metaclass. Not the same thing! :slight_smile:

1 Like