近期人肉学PyTorch源码的人肉总结(2)
PyTorch 是一种用于构建深度学习模型的功能完备框架,是一种通常用于图像识别和语言处理等应用程序的机器学习。使用 Python 编写,因此对于大多数机器学习开发者而言,学习和使用起来相对简单。PyTorch 的独特之处在于,它完全支持 GPU,并且使用反向模式自动微分技术,因此可以动态修改计算图形。这使其成为快速实验和原型设计的常用选择。
https://www.nvidia.cn/glossary/pytorch/
1 import torch2 import torch.nn as nn3 import torch.optim as optim45 # ----------------------------6 # 1. Create training data7 # ----------------------------8 # Input: [x, y]9 # Target: z = x^2 + y^310 torch.manual_seed(0)1112 X = torch.randn(10000, 2) # 1000 samples, (x, y)13 y = X[:, 0]**2 + X[:, 1]**3 # true function
在以上的PyTorch例程中,第 10 行通过 torch.manual_seed(0) 设置随机种子为 0,以确保生成的随机数可复现;
第 12 行用 torch.randn(10000, 2) 生成一个 10000×2 的张量 X,每行是一个样本的输入特征 (x, y),元素服从标准正态分布;
第 13 行通过 y = X[:, 0]**2 + X[:, 1]**3 计算每个样本的目标值 z,即第一个特征平方加上第二个特征立方,从而得到训练数据的输入 X 和输出 y,为后续模型训练提供基础。
继续跟踪第13行张量乘法的C++实现
1. 把断点设置在pytorch/aten/src/ATen/native/cpu/PowKernel.cpp

67行是Y的3次幂实现的地方
2. 用gdb跟到断点后,回溯到第51层调用栈
(gdb) f 51
#51 0x0000555555812674 in _PyEval_Vector (tstate=0x555555bd5cc0 <_PyRuntime+299040>, func=0x7fffd4847050, locals=0x0, args=0x7fffffffb550, argcount=2,
kwnames=0x0) at ../Python/ceval.c:1814
1814 return _PyEval_EvalFrame(tstate, frame, 0);
(gdb) p frame
$4 = (_PyInterpreterFrame *) 0x7ffff7e49088
(gdb) p func
$5 = (PyFunctionObject *) 0x7fffd4847050
这里的func是第55层调用栈,通过名字查找得来的指针:
2612 static PyObject *
2613 vectorcall_maybe(PyThreadState *tstate, PyObject *name,
2614 PyObject *const *args, Py_ssize_t nargs)
2615 {
2616 assert(nargs >= 1);
2617
2618 int unbound;
2619 PyObject *self = args[0];
2620 PyObject *func = lookup_maybe_method(self, name, &unbound);
2621 if (func == NULL) {
2622 if (!PyErr_Occurred())
2623 Py_RETURN_NOTIMPLEMENTED;
2624 return NULL;
2625 }
2626 PyObject *retval = vectorcall_unbound(tstate, unbound, func, args, nargs);
2627 Py_DECREF(func);
2628 return retval;
2629 }
第2620行从字典中查找”__pow__”对应的函数,而加入字典的时机是对__tensor.py的1107行的解释执行:

第51层调用栈取出与func指针对应的字节码序列(存放在frame的结构中,然后解释执行)
3. 跟踪第51层调用栈的字节码执行过程
使用gdb跟踪第51层调用栈的字节码执行过程,我跟到了最后存放C++函数指针的地方:

4. 通过gdb跟踪这个MAKE_CELL字节码的产生过程
我跟到了对函数
_handle_torch_function_and_wrap_type_error_to_not_implemented的编译:


最后用大白话总结一下
在_tensor.py文件中:
1107 __pow__ = cast(1108 Callable[1109 ["torch._C.TensorBase", Union["Tensor", int, float, bool, complex]],1110 "Tensor",1111 ],1112 _handle_torch_function_and_wrap_type_error_to_not_implemented(1113 _C.TensorBase.pow1114 ),1115 )
1113行把_C.TensorBase.pow传给函数
_handle_torch_function_and_wrap_type_error_to_not_implemented
最后执行的时候,执行的是存放在_handle_torch_function_and_wrap_type_error_to_not_implemented函数里的CELL的函数指针

Now we have an idea, it takes no time to code, now the whole company is waiting for your next idea.
https://www.youtube.com/watch?v=tofBqR5N1RI

”计“山有路勤为径,”算“海无涯苦作舟 
夜雨聆风