写作动机
第一篇主要从数学建模的角度总结了近期自学神经网络的成果,但纸上得来终觉浅,不通过代码实现一遍很多东西终究只是空中楼阁。所以本篇总结主要从代码角度回顾总结自学成果。
尽量做到每日一次总结。
行文思路
仿照鱼书的风格,先给出计算图,再一步一步根据计算图搭建代码。
使用框架
因为笔者是一名医学生,所以选择现有的框架——pytorch进行代码的实现。
参考书籍
《动手学深度学习2.0》
2024/2/28——块
就像搭积木一样,“块”由许多“层”构成,然后块本身可以被用来搭建更大的模型。
从代码(python)的角度看,“块”可以用“类”来实现。
之前一直在用的nn.Sequential本身就是一个块。
本篇总结就是要亲自实现一个块,从而更好地理解块。
确定模型
- 输入数字:多维
- 输出数字:多维
- 数字映射:多层感知机
计算图
代码实现
首先确定数据的流动:25→256→10
然后搭建块,我们继承已有的nn.Module来构造自己想要的块:
import torch
from torch import nn
from torch.nn import functional
class BLOCK(nn.Module):
def __init__(self):
super().__init__()
self.stage1 = nn.Linear(25, 256)
self.stage2 = nn.Linear(256, 10)
def forward(self, input_numbers):
stage1_2 = self.stage1(input_numbers)
stage1_2 = functional.relu(stage1_2)
output_numbers = self.stage2(stage1_2)
在定义forward函数时,如果有固定的参数(即不会因反向优化而改变的参数),那么可以在初始化处先加上固定的参数,再在forward处加上矩阵乘法:
class BLOCK_special(nn.Module):
def __init__(self):
super().__init__()
self.stage1 = nn.Linear(25, 256)
self.stage2_weight = torch.rand((256,256), requires_grad=False)
self.stage3 = nn.Linear(256, 10)
def forward(self, input_numbers):
stage1_2 = self.stage1(input_numbers)
stage1_2 = functional.relu(stage1_2)
stage2_3 = torch.mm(stage1_2, stage2_weight) + 1
stage2_3 = functional.relu(stage2_3)
output_numbers = self.stage3(stage2_3)
应用
试着调用自定义的块:
block = BLOCK()
block_special = BLOCK_special()
input_numbers = torch.rand(2,25)
block(input_numbers), block_special(input_numbers)
接下来将编写按照顺序连接的块(之前用的nn.Sequential就是这么一回事):
class MySequential(nn.Module):
def __init__(self, *args):
super().__init__()
for idx, block in enumerate(args):
self._blocks[str(idx)] = block
def forward(self, input_numbers):
for block in self._blocks.values():
input_numbers = block(input_numbers)
return input_numbers
net = MySequential(
nn.Linear(25,256),
nn.ReLU(),
nn.Linear(256,10)
)
input_numbers = torch.rand(2,25)
net(input_numbers)
最后“搭积木”,将不同的块搭在一起:
mixed_net = nn.Sequential(
block(),
nn.ReLU(),
nn.Linear(10,256),
block_special()
)
mixed_net(input_numbers)