李宏毅机器学习——pytorch

发布时间 2023-04-16 10:27:07作者: dctwan

什么是pytorch

python机器学习框架,Facebook提出,主要有一下两个特点

  1. 使用GPU加速高维矩阵的运算

    torch.cuda.is_available()
    x = x.to('cuda')
    
  2. 可以很方便的实现梯度的计算

    requires_grad=True指定需要对变量x计算梯度

    z是x的函数,调用z.backward()反向传播计算梯度

    x.grad属性存放z对x的梯度

    image-20230416082631816

如何使用pytorch训练和测试神经网络

image-20230416083311462

  1. 加载数据

    训练数据 & 测试数据

    使用pytorch提供的DatasetDataLoader

  2. 定义网络模型

    pytorch提供torch.nn.Model,可以很方便的实现全连接层、卷积层、池化层等

  3. 定义损失函数

    pytorch提供MSELoss(均方误差),CrossEntropyLoss(交叉熵损失)等损失函数

  4. 选择优化器

    选择优化算法,SGD

  5. 开始训练

  6. 测试

Dataset & DataLoader

from torch.utils.data import Dataset, DataLoader
class MyDataset(Dataset):			# 重写Dataset三个函数inti, getitem, len
    def __init__(self, file):		# 读取数据 + 预处理
        self.data = xxx
    
    def __getitem__(self, index):	# 根据索引返回一个样本 
        return self.data[index]
    
    def __len__(self):				# 返回数据集的总量
        return len(self.data)
        
image-20230413071218760

Tensor

高维矩阵 —— 张量(tensor),pytorch中处理数据的类型

通过.shape()检查数据的维度

Define Model

定义网络模型

  1. Linear Layer(Fully-connected Layer)

    线性层/全连接层

    nn.Linear(in_features, out_features)

    image-20230416084307561
  2. Non-Linear Activation Functions

    非线性激活函数

    • nn.Sigmoid()
    • nn.ReLU()
  3. 完整创建神经网络

    • 自定义模型类重写nn.Model
    • 初始化模型,定义各层
    • 重写前向传播方法forward
    import torch.nn as nn
    
    class MyModel(nn.Model):
        def __init__(self):
            super(MyModel, self).__init__()
            self.net = nn.Sequential(		
            	nn.Linear(10, 32),
                nn.Sigmoid(),
                nn.Linear(32, 1)
            )
        def forward(self, x):
            return self.net(x)
        
        
    # 上面使用了nn.Sequential方法,和下方的方式等价
    class MyModel(nn.Model):
        def __init__(self):
            super(MyModel, self).__init__()		
            self.layer1 = nn.Linear(10, 32),
            self.layer2 = nn.Sigmoid(),
            self.layer3 = nn.Linear(32, 1)
        def forward(self, x):
            out = self.layer1(x)
            out = self.layer2(out)
            out = self.layer3(out)
            return out
       
    

Loss Functions

损失函数

  • Mean Square Error

    适用于回归问题的损失函数

    criterion = nn.MSELoss()
    
  • Cross Entropy

    criterion = nn.CrossEntropyLoss()
    
# 计算损失函数
# model_output:模型的预测结果;expected_value:训练数据的真实值
loss = criterion(model_output, expected_value)

torch.optim

优化算法

Stochastic Gradient Descent(SGD)

optimizer = torch.nn.SGD(model.parameters(), lr, momentum=0)

对于每一批训练数据

  1. 调用optimizer.zero_grad(),将上一批计算的梯度归零
  2. 调用loss.backward()反向传播计算梯度
  3. 调用optimizer.step()根据梯度调整模型参数

训练 & 验证 & 测试

# ---------------------------- 准备工作 -----------------------------------
dataset = MyDataset(file)	# 通过MyDataset读取数据
tr_set = DataLoader(dataset, 16, shuffle=True)	# 使用DataLoader给数据分批
model = MyModel.to(device)	# 将模型放在相应的device上进行训练(cpu/cuda)
criterion = nn.MSELoss()	# 定义均方误差损失函数
optimizer = nn.optim.SGD(model.parameters(), lr=0.1)	# 设置优化器

# ---------------------------- 训练过程 -----------------------------------
for epoch in range(n_epochs):				# 训练n_epochs轮
    model.train()							# 将模型设置为训练模式
    for x, y in tr_set:						# 对于一个batch中的所有训练样本
        oprimizer.zero_grad()				# 梯度清零(随机梯度下降)
        x, y = x.to(device), y.to(device)	# 将数据放到相应device上进行运算
        pred = model(x)						# 前向传播,求预测值pred
        loss = criterion(pred, y)			# 计算损失
        loss.backward()						# 反向传播计算梯度
        optimizer.step()					# 根据梯度更新模型参数
        
# ---------------------------- 验证过程 -----------------------------------
model.eval()	# 将模型设置为验证模式
total_loss = 0.0
for x, y in dv_set:
    x, y = x.to(device), y.to(device)
    with torch.no_grad():	# 设置模型不进行梯度的计算
        pred = model(x)
        loss = criterion(pred, y)
    total_loss += loss.cpu().item() * len(x)
    avg_loss = total_loss / len(dv_set.dataset)
    

# ---------------------------- 测试过程 -----------------------------------
model.eval()
preds = []
for x in tt_set:
    x = x.to(device)
    with torch.no_grad():
        pred = model(x)
        preds.append(pred.cpu())

注意:

  1. model.train() & model.eval()

    模型中的一些层在训练和测试的表现并不相同,如:dropout、batch-normalization,在训练时需要指定model.train,在验证和测试时需要指定model.eval(),以确保这样的层分别在训练和测试时按照不同的方式运行

  2. with torch.no_grad()

    在验证和测试时,不应该计算梯度和更新参数,只因该观察训练过的模型在此的表现。如果不关掉这个的话,相当于”泄题“

保存/加载模型参数

  • Save

    torch.save(model.state_dict(), path)
    
  • Load

    ckpt = torch.load(path)
    model.load_state_dick(ckpt)
    

参考:李宏毅机器学习课程