深度学习笔记 —— PyTorch 神经网络基础

本文详细介绍了如何使用PyTorch进行深度学习模型的构建,包括使用nn.Sequential、自定义模块、参数管理和初始化方法。此外,还展示了如何读写文件保存和加载模型参数,以及自定义层的实现,是PyTorch初学者的实用教程。
摘要由CSDN通过智能技术生成
import torch
from torch import nn
from torch.nn import functional as F


'''
模型构造
'''


# nn.Sequential定义了一种特殊的Module
net = nn.Sequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
X = torch.rand(2, 20)
print(net(X))


# 自定义块
# 任何一个层或者一个神经网络都应该是Module的一个子类
# 相较于nn.Sequential可以在init和forward中做更为灵活的处理
class MLP(nn.Module):
    # 该函数包括了所有的层
    def __init__(self):
        # 调用父类(Module)的init函数
        super().__init__()
        self.hidden = nn.Linear(20, 256)
        self.out = nn.Linear(256, 10)

    # 定义前向函数怎么运算
    def forward(self, X):
        return self.out(F.relu(self.hidden(X)))


net = MLP()
print(net(X))


class MySequential(nn.Module):
    # *args: list of input arguments
    def __init__(self, *args):
        super().__init__()
        for block in args:
            self._modules[block] = block

    def forward(self, X):
        for block in self._modules.values():
            X = block(X)
        return X


net = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
print(net(X))
import torch
from torch import nn


'''
参数管理
'''


# 单隐藏层的多层感知机
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
net(X)

# 参数访问
print(net[2].state_dict())  # net是一个nn.Sequential,可以简单认为是python的一个list

print(type(net[2].bias))  # Parameter定义的是一个可以优化的参数
print(net[2].bias)
print(net[2].bias.data)  # 通过.data可以访问参数本身
print(net[2].weight.grad == None)  # 通过.grad访问梯度

# 一次性访问所有参数
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
print(*[(name, param.shape) for name, param in net.named_parameters()])
# 通过名字获取参数
print(net.state_dict()['2.bias'].data)


# 从嵌套块收集参数
def block1():
    return nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 4), nn.ReLU())


def block2():
    net = nn.Sequential()
    for i in range(4):
        net.add_module(f'block {i}', block1())
    return net


rgnet = nn.Sequential(block2(), nn.Linear(4, 1))
rgnet(X)
print(rgnet)


# 内置初始化
def init_normal(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, mean=0, std=0.01)  # 一般表示这是一个替换函数
        nn.init.zeros_(m.bias)


net.apply(init_normal)  # apply对net里的所有layer调用init_normal这个函数(遍历一遍)
print(net[0].weight.data[0], net[0].bias.data[0])


# 对某些块应用不同的初始化方法
def xavier(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)  # 用uniform distribution来做xavier的初始化


def init_42(m):
    if type(m) == nn.Linear:
        nn.init.constant_(m.weight, 42)


net[0].apply(xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)


# 自定义初始化
def my_init(m):
    if type(m) == nn.Linear:
        print(
            "Init",
            *[(name, param.shape) for name, param in m.named_parameters()][0]
        )
        nn.init.uniform_(m.weight, -10, 10)
        m.weight.data *= m.weight.data.abs() >= 5


net.apply(my_init)
print(net[0].weight[:2])


# 更为简单暴力的方法:直接替换
net[0].weight.data[:] += 1
net[0].weight.data[0, 0] = 42
net[0].weight.data[0]


# 参数绑定(共享权重)
shared = nn.Linear(8, 8)
# 不管如何更新network,这两个shared层都是一样的
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), shared, nn.ReLU(), shared, 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])
import torch
import torch.nn.functional as F
from torch import nn


'''
自定义层
'''


# 自定义层与自定义网络没有本质区别,因为层也是nn.Module的一个子类
class CenteredLayer(nn.Module):
    def __init__(self):
        super().__init__()  # 调用父类的init

    def forward(self, X):
        return X - X.mean()


layer = CenteredLayer()
print(layer(torch.FloatTensor([1, 2, 3, 4, 5])))


# 将层作为组件合并到构建更复杂的模型中
net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())
Y = net(torch.rand(4, 8))
print(Y.mean())


# 带参数的层
class MyLinear(nn.Module):
    def __init__(self, in_units, units):
        super().__init__()
        # 参数都是nn.Parameter类的实例
        self.weight = nn.Parameter(torch.randn(in_units, units))
        self.bias = nn.Parameter(torch.randn(units,))

    def forward(self, X):
        linear = torch.matmul(X, self.weight.data) + self.bias.data
        return F.relu(linear)


dense = MyLinear(5, 3)
print(dense.weight)
# 使用自定义层直接执行正向传播计算
print(dense(torch.rand(2, 5)))
# 使用自定义层构建模型
net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
print(net(torch.rand(2, 64)))
import torch
from torch import nn
from torch.nn import functional as F


'''
读写文件
'''


# 加载和保存张量
x = torch.arange(4)
print(x)
torch.save(x, 'x-file')
x2 = torch.load("x-file")
print(x2)


# 存储一个张量列表,然后把它们读回内存
y = torch.zeros(4)
torch.save([x, y], 'x-files')
x2, y2 = torch.load('x-files')
print(x2, y2)


# 写入或读取从字符串映射到张量的字典
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
print(mydict2)


# 加载和保存模型参数
class MLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(20, 256)
        self.output = nn.Linear(256, 10)

    def forward(self, x):
        return self.output(F.relu(self.hidden(x)))


net = MLP()
X = torch.randn(size=(2, 20))
Y = net(X)
print(Y)


# 将模型的参数存储为一个叫做"mlp.params"的文件
torch.save(net.state_dict(), 'mlp.params')


# 实例化了原始多层感知机模型的一个备份,直接读取文件中存储的参数
clone = MLP()  # MLP的定义
clone.load_state_dict(torch.load("mlp.params"))
print(clone.eval())


Y_clone = clone(X)
print(Y_clone == Y)  # 说明clone和之前网络的参数是一样的

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值