PyTorch 构建和训练神经网络(二)

用 PyTorch 构建和训练一个基本的神经网络(二)

在用 PyTorch 构建和训练一个基本的神经网络(一)中,我们展示了如何快速构建和训练一个简单的神经网络。其中有很多概念对于初学者来说没见过,这篇文章就来具体解释一下。

torch.randn 和 数据生成

X = torch.randn(100, 3)
y = torch.randn(100, 1)

torch.randn 函数用于生成具有标准正态分布(均值为0,方差为1)的随机数张量。在这里,我们生成了 100 个样本,每个样本有 3 个特征。目标值 y 同样是 100 个样本,但每个样本只有 1 个输出。

举个例子:假如你想做个模型来对图片进行分类。那么需要一些数据来训练模型(不训练就会,那是神仙,不是神经网络)。你得告诉你的模型,这个是猫,那个是狗,等等。。。

注意,这个是猫中的这个,是什么? 你可能指着一只猫,或者一只狗,此时“这个”就代表这个具体的生物,是你的眼睛看到的一幅图像。

对于计算机来说,你得告诉它你看到的图像。这可以通过摄像头,照相机等拍摄的图片,传递给计算机来达成。

再往深一步想,计算机是怎样看到图片的?图片在计算机的眼里,只是一堆数据而已。那么你想训练他,就得给它这些数据。

Pytorch接收到图片后(这货其实只接收 tensor, 图片要以特定方式转换为 tensor),会通过一系列的算法进行对图像进行特征提取,然后根据提取出来的特征进行分析判断,最后得出一个结论:这货有 90% 的可能性是条狗!

那么问题来了,它怎么能有这个结论呢,答案就是它经过训练了。我们给了它一个图像,它说:这是猫吧?我们告诉它,错,这是条狗。它说:哦,原来这是狗,学习了学习了。。。把此类特征加到“狗”类别。

我们再给它一个图像,它说:这是狗,我们告诉它,这是猫啊!它说:哦,原来是猫,学习了学习了。。。把此类特征加到 “猫”类别。

经过不断的训练,它见识到了很多的猫狗,并在内心中总结了大量特征,终于它成熟起来,能辨别猫狗了。但是注意:它并不能保证准确率为100%。这也是目前神经网络的一大缺憾,它不是神,是神经(网络)。训练数据总是有限的,而这个宇宙却有无限可能。如果一只狗穿上西装坐在椅子上,它很可能觉得不是狗。

扯远了。我们需要训练数据来进行训练。那么 X 代表100个样本,每个样本有3个特征,就好比: X 是一百张动物的图片,每张图片都有三个特征:脑袋形状,尾巴形状,嘴巴形状。 这三个特征,对应 y 中的一个数据->结论, 比如: “猫” 或者 “狗”。但是这些数据都是以数字的形式表示的,而不是文字形式。

训练就是让模型通过三个特征,计算之后,得出一个结论: “猫”或者“狗”. 如果计算结论和 y 中对应的答案不匹配,就是错了,损失函数就要进行修正(大概就是这个意思)

刚开始训练时,模型肯定是瞎猜。但是随着训练次数的增加,它会总结出一些特征,慢慢的变得聪明,最终可以非常准确的识别。

TensorDatasetDataLoader

dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)

TensorDataset: 将输入 X 和标签 y 打包成一个数据集,方便之后通过 DataLoader 进行批次(batch)加载。
DataLoader: 用于加载数据集,可以设置 batch_size 来定义每次加载多少数据,并且通过 shuffle=True 参数来随机打乱数据。这样做是为了避免模型学习到数据的顺序性,从而提高泛化能力。

定义简单的神经网络

class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(3, 5)
        self.fc2 = nn.Linear(5, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x
  • nn.Module: nn.Module 是所有神经网络模块的基类。你自己定义的每一个神经网络模块都应继承这个类,并实现 __init__forward 方法。
  • nn.Linear: 这是一个全连接层,也叫做线性层。fc1 将输入维度从 3 转换为 5,fc2 将 5 转换为 1。
  • forward 方法: 在这个方法中定义了网络的前向传播过程。每次传入数据 x,先经过第一层 fc1,然后通过 ReLU 激活函数,再传递到第二层 fc2
  • ReLU 激活函数什么鬼?目前咱只要知道:它把负数变成0,正数不变。这有什么用?你以后再操心好吧,路漫漫其修远兮。。。

损失函数和优化器

criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
  • nn.MSELoss: 这是一个均方误差损失函数,用于回归问题。在训练中,我们会计算预测值和真实值之间的均方误差,并使用这个误差来指导模型参数的调整。
  • optim.SGD: 这是一个优化器,使用随机梯度下降法更新模型参数。model.parameters() 获取了模型中所有可训练的参数。

这个法那个法的,你了解一下便好,随便上网一查,知道各种意味即可。日后可慢慢研究。。。

训练模型

for epoch in range(100):
    for batch_X, batch_y in dataloader:
        optimizer.zero_grad()
        output = model(batch_X)
        loss = criterion(output, batch_y)
        loss.backward()
        optimizer.step()
  • optimizer.zero_grad(): 每次训练前都需要将梯度清零,否则梯度会累积。
  • model(batch_X): 调用模型的 forward 方法,进行前向传播,得到预测输出。
  • loss.backward(): 反向传播,计算梯度。这一步将基于损失值计算每个参数的梯度。
  • optimizer.step(): 使用优化器更新模型参数,进行一次梯度下降。

测试模型

with torch.no_grad():
    test_X = torch.tensor([[0.5, -0.2, 0.1]])
    test_output = model(test_X)
    print(f'Test Output: {test_output.item()}')
  • torch.no_grad(): 在测试或验证模型时,不需要计算梯度,所以使用 torch.no_grad() 上下文管理器来关闭梯度计算。这不仅节省内存,还加快了计算速度。
  • model(test_X): 对测试数据进行预测。
  • test_output.item(): item() 方法将张量中的值提取出来,作为一个标准 Python 数值。

不要想一口气吃个胖子,一下子什么都搞懂。相对来说,每天只问两个问题,一个月下来,你就懂了60个问题。岂不轻松哉…

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值