What is the difference of `call_function` and `call_method`?

From the FX documentation, I learned that there are several node types:

  • placeholder
  • getattr
  • output
  • call_method
  • call_function
  • call_module

I have difficulty to tell the last three concepts apart. Could someone explain them using more examples?

Here is an example:

import torch
import torch.fx as fx
import torch.nn as nn

def myadd(x, y):
    return x + y

class Adder(nn.Module):
    def forward(self, x, y):
        return x + y
    
class M(nn.Module):
    def __init__(self):
        super(M, self).__init__()
        self.adder = Adder()
    
    def forward(self, x, y):
        return x + y, myadd(x, y), torch.add(x, y), x.add(y), self.adder(x, y)

fx.symbolic_trace(M()).graph.print_tabular()

#### output
opcode         name    target                                               args                                  kwargs
-------------  ------  ---------------------------------------------------  ------------------------------------  --------
placeholder    x       x                                                    ()                                    {}
placeholder    y       y                                                    ()                                    {}
call_function  add     <built-in function add>                              (x, y)                                {}
call_function  add_1   <built-in function add>                              (x, y)                                {}
call_function  add_2   <built-in method add of type object at 0x10310d390>  (x, y)                                {}
call_method    add_3   add                                                  (x, y)                                {}
call_function  add_4   <built-in function add>                              (x, y)                                {}
output         output  output                                               ((add, add_1, add_2, add_3, add_4),)  {}

Why the Adder module not traced as call_module

What is the difference between Tensor.add and myadd? Because Tensor.add is bound with a Tensor object and thus it is not free?