Fastai v2 daily code walk-thrus

Now here’s an open question:

def some_func2(a, b:bool)->TensorImage: pass
t = TypeDispatch(some_func2); t

>>>{'bool': 'some_func2'}

At this point, we are using the second param mapping inside TypeDispatch but,

def _p1_anno(f):
    "Get the annotation of first param of `f`"
    hints = type_hints(f)
    ann = [o for n,o in hints.items() if n!='return']
    return ann[0] if ann else object

According to docstring of _p1_anno we should be using the annotation of first param of f

Thoughts??

1 Like

Here’s an insight!

So now that we know TypeDispatch is nothing but a pretty cool dict that looks something like:

{
bool: some_func1,
int: some_func2,
Numbers.Integral: some_func3 
}

ie., it is a mapping between type and the function that needs to be called on that specific type.

This is done through __call__ inside TypeDispatch ofcourse!

    def __call__(self, x, *args, **kwargs):
        f = self[type(x)]
        if not f: return x
        if self.inst: f = types.MethodType(f, self.inst)
        return f(x, *args, **kwargs)

f = self[type(x)] Check type of param being called ie., and look it up in TypeDispatch dict and call that function.
ie., foo(2) will return type(2) as int and then we lookup int which is coming from __getitem__ which simply returns the first matching type that is a super-class of type.

So we lookup inside self.cache which is also a mapping like

{
bool: some_func1,
int: some_func2,
Numbers.Integral: some_func3 
}

and we will find a function some_func2 for int. Thus, __getitem__ will return some_func2 as f.

So, f = self[type(x)] sets f as some_func2.

This is the magic! We will call the specific function using __call__ for the specific type based on the parameter being passed!!

Thus when we pass a TensorImage, it will find the function that corresponds to TensorImage from inside dict and call it which is just as simple as return f(x, *args, **kwargs)!

1 Like

In my quest to find more about the behaviour of the metaclass, I went through the Python Data Model docs but could not understand much. But I stumbled upon this article which I believe best explains the behaviour and is very close to the way we have implemented things in fastaiv2.

Let’s start with the basics. Let’s take a look at the relation between Instance, Class and Metaclass.

If we define a class and then create an instance of the class, the python interpreter will start working like this.

If we define a metaclass and then create a class that uses this metaclass, then the python interpreter will start working like this.

So this explains as to why the first call of Transform(_norm) went to the Metaclass call method. The metaclass of Transform is _TfmMeta. From there on it would call the new and the init method of the class which is Transform here. Since the init is defined here in Transform, this call is made. If the init and/or the new was not there in Transform then they would be delegated above to the ancestors of Transform.

Is the understanding correct here?

2 Likes

How Transforms make use of TypeDispatch

Okay, here’s another one! I couldn’t have imagined that I will ever understand this part of V2, but now that I do, it just seems surreal! This is Python at a next level! And when you come to think of it, you can understand why it’s built this way.

But, lets discuss the thought process a little later.

First let’s understand encodes and decodes inside Transform!

So, from _TfmDict

class _TfmDict(dict):
    def __setitem__(self,k,v):
        if k=='_': k='encodes'
        if k not in ('encodes','decodes') or not isinstance(v,Callable): return super().__setitem__(k,v)
        if k not in self: super().__setitem__(k,TypeDispatch())
        res = self[k]
        res.add(v)

As long as something is not of type encodes or decodes the namespace of the cls would be created using dict as per normal behavior. Note, that __setitem__ is responsible for setting k:v inside dict, thus if you update that, you can get custom behavior!

So as long as something is not encodes or decodes, just use dict to set k:v.

BUT, when it is encodes or decodes then k:TypeDispatch()

And as we know - TypeDispatch is nothing but a cool dict of type:function mapping!

So theoretically speaking, the namespace of this special class which is a subclass of TfmMeta will look something like

{....all the usual stuff like __module__:__main__etc AND 
encodes: 
    {
     bool: some_func1,
     int: some_func2, 
     Numbers.Integral: some_func3 
    }, 
decodes: 
    {
     bool: some_reverse_func1,
     int: some_reverse_func2, 
     Numbers.Integral: some_reverse_func3 
    }, 

And finally ! When you call encodes or decodes - it can be done so for different types, which will be called using __call__ inside TypeDispatch which then call the specific corresponding function to type!

It is all making sense now.

Please correct me if I have understood anything wrong :slight_smile:

1 Like

The actual behavior, as you noticed, is that it gets the annotation of the first annotated param of f. However, we don’t rely on that behavior in the library, and it’s not guaranteed to always do that in the future, so we don’t document that quirk in the docstring.

2 Likes

@arora_aman these are really great analyses! It would be great it you could also copy them into here, if you have a chance:

1 Like

There will be a walk-thru today at 2.30p. Details in the top post.

2 Likes

Thank you, Jeremy!

Done :slight_smile:

1 Like

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

Added the walk-thru 6 video: https://youtu.be/8i9bo5wLSE4

2 Likes

This is the most amazing way to motivate the community to help with v2. Thank you!

It would be awesome to have a quick example on how we could merge different types of data into one DataSource. For example Image, Text and Tabular. I watched all videos. Having worked on https://github.com/EtienneT/fastai-petfinder to do that with v1 was a lot of work, can’t wait to adapt it to v2.

I think we are at a point where you showed all the building blocks where we could do this but it would be nice to have a quick high level code example if you can.

4 Likes

Yes we certainly plan to do this - although we haven’t started on it yet.

2 Likes

There won’t be a walk-thru today - we have a sick nanny so I’ll be with my daughter.

7 Likes

Today’s stream: https://youtu.be/H_7bcfaLrdI

1 Like

Are we still live?

image

Not sure if we’re done for today or if Jeremy is getting it back up and running, but that’s his message on youtube.

2 Likes

Thank you @KevinB!
I missed the message

Yup we’re done!

4 Likes

Walk-thru video 7 posted ( https://www.youtube.com/watch?v=H_7bcfaLrdI )

2 Likes

There won’t be a walk-thru today, but there will be one tomorrow

5 Likes