question with fast.ai course lesson 8 g attribute
In the course fast.ai 2019 lesson 8, there is a weird g attribute used in back propagation, which i check for torch.Tensor this attribute doesn't exist. I tried to print the value of inp.g/out.g in call method but i got AttributeError: 'Tensor' object has no attribute 'g', but i am able to obtain the inp.g/out.g value before the assignment in backward, how does this g attribute works?

class Linear():
    def __init__(self, w, b):
        self.w, self.b = w, b

    def __call__(self, inp):
        print('in lin call')
        self.inp = inp
        self.out = inp@self.w + self.b
        try:
            print('out.g', self.out.g)
        except Exception as e:
            print('out.g dne yet')
        return self.out

    def backward(self):
        print('out.g', self.out.g)
        self.inp.g = self.out.g @ self.w.t()
        self.w.g = (self.inp.unsqueeze(-1) * self.out.g.unsqueeze(1)).sum(0)
        self.b.g = self.out.g.sum(0)


link to full code from the course

-update-

i am able to figure out the self.out.g value is exact same as the cost function MSE self.inp.g but still unable to figure out how the value is passed into the last linear layer.

class MSE():
    def __call__(self, inp, targ):
        self.inp = inp
        self.targ = targ
        self.out = (inp.squeeze() - targ).pow(2).mean()
        return self.out

    def backward(self):
        self.inp.g = 2. * (self.inp.squeeze() - self.targ).unsqueeze(-1) \
                        / self.targ.shape[0]
        print('in mse backward', self.inp.g)

class Model():
    def __init__(self, w1, b1, w2, b2):
        self.layers = [Lin(w1, b1), Relu(), Lin(w2, b2)]
        self.loss = Mse()

    def __call__(self, x, targ):
        for l in self.layers:
            x = l(x)
        return self.loss(x, targ)

    def backward(self):
        self.loss.backward()
        for l in reversed(self.layers):
            l.backward()


basically this has to deal with how python assignments works (pointers, similar to how C pointers works). after tracing the variables with id(variable name) i am able to figure out how things the g attribute comeby.

# ... in model (forward pass)...
    x = layer(x) # from linear layer &gt;&gt; return self.out and is assigned to x

# ...
    return self.loss(x, targ) # x is the same x (id) obtained from the model

# ========

# ... in model (backward pass) ...
    self.loss.backward() # this is how the self.inp.g came by 

# ... in linear ...
    self.inp.g = self.out.g @ self.w.t() 
    # this self.out.g is the same instance as self.inp.g from loss 

