D2L-五-深度学习计算

深度学习计算

5.1 层和块

自定义块:由类(class)表示,继承nn.Module这个类

class MLP(nn.Module):
    # 用模型参数声明层。这里,我们声明两个全连接的层
    def __init__(self):
        # 调用MLP的父类Module的构造函数来执行必要的初始化。
        # 这样,在类实例化时也可以指定其他函数参数,例如模型参数params(稍后将介绍)
        super().__init__()
        self.hidden = nn.Linear(20, 256)  # 隐藏层
        self.out = nn.Linear(256, 10)  # 输出层

    # 定义模型的前向传播,即如何根据输入X返回所需的模型输出
    def forward(self, X):
        # 注意,这里我们使用ReLU的函数版本,其在nn.functional模块中定义。
        return self.out(F.relu(self.hidden(X)))
#进行类实例化
net = MLP()
net(X)

顺序块

Sequential的设计是为了把其他模块串起来。 为了构建我们自己的简化的MySequential, 我们只需要定义两个关键函数:

  • 一种将块逐个追加到列表中的函数;
  • 一种前向传播函数,用于将输入按追加块的顺序传递给块组成的“链条”。
class MySequential(nn.Module):
    def __init__(self, *args):
        super().__init__()
        for idx, module in enumerate(args):
            # 这里,module是Module子类的一个实例。我们把它保存在'Module'类的成员
            # 变量_modules中。_module的类型是OrderedDict
            #self._modules 是nn.module自带的特殊字典,
            #把层放进去就能自动知道是子模块
            #str(idx),因为_modules的key要求是字符串
            self._modules[str(idx)] = module

    def forward(self, X):
        # OrderedDict保证了按照成员添加的顺序遍历它们
        for block in self._modules.values():
            X = block(X)
        return X
net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
net(X)

image-20260924015752921

5.2 参数管理

参数访问

通过Sequential类定义模型时,可以通过索引访问模型任意层

print(net[2].state_dict())
OrderedDict([('weight', tensor([[-0.0427, -0.2939, -0.1894,  0.0220, -0.1709, -0.1522, -0.0334, -0.2263]])), ('bias', tensor([0.0887]))])

​ 从层中访问数值方法(每个参数表示为参数类的实例)

​ 参数是复合的对象,包含值、梯度和额外信息

print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)
<class 'torch.nn.parameter.Parameter'>
Parameter containing:
tensor([0.0887], requires_grad=True)
tensor([0.0887])

https://zh.d2l.ai/chapter_deep-learning-computation/parameters.html

参数初始化

​ 调用内置初始化器,权重参数初始化为标准差为0.01的高斯随机变量且偏置参数设为零

def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)
        #注意,此处“_“结尾,表示直接改变后面的输入,不会返回值
		#即in_place原地修改
        nn.init.zeros_(m.bias)
net.apply(init_normal)
#对net所有module调用此函数,即遍历
#Apply fn recursively to every submodule (as returned by 
#.children()) as well as self.
#例如net[0].apply(),即对特定层进行初始化
net[0].weight.data[0], net[0].bias.data[0]

参数绑定

​ 有时我们希望在多个层间共享参数: 我们可以定义一个稠密层,然后使用它的参数来设置另一个层的参数。

# 我们需要给共享层一个名称,以便可以引用它的参数
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),
                    shared, nn.ReLU(),
                    shared, nn.ReLU(),
                    nn.Linear(8, 1))
net(X)
# 检查参数是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 确保它们实际上是同一个对象,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])

自定义层

继承基础层类(nn.module)然后实现向前传播功能

import torch
import torch.nn.functional as F
from torch import nn


class CenteredLayer(nn.Module):
    def __init__(self):
        super().__init__()
        #_init_创建的时候调用

    def forward(self, X):
        return X - X.mean()
    #forward在用数据调用层的时候传入X

文件读写

​ 对于单个向量,调用load和save读写

import torch
from torch import nn
from torch.nn import functional as F
x = torch.arange(4)
#用save保存
torch.save(x, 'x-file')
#用load读取
x2 = torch.load('x-file')

​ 加载和保存模型

此处介绍的方法保存模型的参数而不是保存整个模型

torch.save(net.state_dict(), 'mlp.params')

为了恢复模型,我们实例化了原始多层感知机模型的一个备份。 这里我们不需要随机初始化模型参数,而是直接读取文件中存储的参数。

clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()

GPU

​ pytorch中 ,每个数组都有一个device

x = torch.tensor([1, 2, 3])
x.device
device(type='cpu')

​ 可以在创建张量时指定存储设备

X = torch.ones(2, 3, device="cuda:0")
X

​ 神经网络与GPU

def try_gpu(i=0):  #@save
    """如果存在,则返回gpu(i),否则返回cpu()"""
    if torch.cuda.device_count() >= i + 1:
        return torch.device(f'cuda:{i}')
    return torch.device('cpu')
#将神经网络指定设备
net = nn.Sequential(nn.Linear(3, 1))
net = net.to(device=try_gpu())
posted @ 2026-09-28 23:19  EmoT1on  阅读(3)  评论(0)    收藏  举报