torch.nn到底是什么?(精简版)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

此文为《torch.nn到底是什么?》的总结版。

首先创建基本的神经网络,然后逐步添加torch.nntorch.optimDatesetDataLoader的功能,以显示每一部分的具体作用。

1、设置MNIST数据

使用经典的 MNIST 数据集,该数据集由手写数字(0-9)的黑白图像组成。

使用 pathlib 来处理路径(Python3标准库的一部分),用 requests 下载数据。

from pathlib import Path
import requests

DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"

PATH.mkdir(parents=True, exist_ok=True)

URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"

if not (PATH / FILENAME).exists():
        content = requests.get(URL + FILENAME).content
        (PATH / FILENAME).open("wb").write(content)

该数据集的格式为NumPy array,使用 pickle 存储。

import pickle
import gzip

with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
        ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

每个图片大小为28x28,并存储为长度为784(=28x28)的扁平行。

查看其中的一个图片:

from matplotlib import pyplot
import numpy as np

pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

输出为:
在这里插入图片描述

(50000, 784)

PyTorch使用 tensor 而不是 NumPy array,所以我们需要将其转换。

import torch

x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())

输出:

tensor([[0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]]) tensor([5, 0, 4,  ..., 8, 4, 8])
torch.Size([50000, 784])
tensor(0) tensor(9)

2、从头构建神经网络(不使用 torch.nn

首先只使用PyTorch tensor 操作创建一个模型。

#initializing the weights with Xavier initialisation (by multiplying with 1/sqrt(n)).

import math

weights = torch.randn(784, 10) / math.sqrt(784)
weights.requires_grad_()
bias = torch.zeros(10, requires_grad=True)

def log_softmax(x):
    return x - x.exp().sum(-1).log().unsqueeze(-1)

def model(xb):
    return log_softmax(xb @ weights + bias)

def nll(input, target):
    return -input[range(target.shape[0]), target].mean()

def accuracy(out, yb):
    preds = torch.argmax(out, dim=1)
    return (preds == yb).float().mean()
    
loss_func = nll

bs = 64  # batch size

xb = x_train[0:bs]  # a mini-batch from x
yb = y_train[0:bs]

preds = model(xb)  # predictions

print(preds[0], preds.shape)
print(loss_func(preds, yb))
print(accuracy(preds, yb))

输出:

tensor([-1.7022, -3.0342, -2.4138, -2.6452, -2.7764, -2.0892, -2.2945, -2.5480,
        -2.3732, -1.8915], grad_fn=<SelectBackward>) torch.Size([64, 10])

tensor(2.3783, grad_fn=<NegBackward>)
tensor(0.0938)

现在我们可以进行训练。对于每次迭代,将会做以下几件事:

  • 选择一批数据(mini-batch)
  • 使用模型进行预测
  • 计算损失
  • loss.backward() 更新模型的梯度,即权重和偏置
from IPython.core.debugger import set_trace

lr = 0.5  # learning rate
epochs = 2  # how many epochs to train for

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
       #set_trace()
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        with torch.no_grad():
            weights -= weights.grad * lr
            bias -= bias.grad * lr
            weights.grad.zero_()
            bias.grad.zero_()

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

输出:

tensor(0.0806, grad_fn=<NegBackward>) tensor(1.)

3、使用 torch.nn.functional

如果使用了负对数似然损失函数和 log softnax 激活函数,那么Pytorch提供的F.cross_entropy 结合了两者。所以我们甚至可以从我们的模型中移除激活函数。

import torch.nn.functional as F

loss_func = F.cross_entropy

def model(xb):
    return xb @ weights + bias

注意,在 model 函数中我们不再需要调用 log_softmax。让我们确认一下,损失和精确度与前边计算的一样:

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

输出:

tensor(0.0806, grad_fn=<NllLossBackward>) tensor(1.)

4、使用 nn.Module 重构

继承 nn.Module(它本身是一个类并且能够跟踪状态)建立子类,并实例化模型:

from torch import nn

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.weights = nn.Parameter(torch.randn(784, 10) / math.sqrt(784))
        self.bias = nn.Parameter(torch.zeros(10))

    def forward(self, xb):
        return xb @ self.weights + self.bias
        
model = Mnist_Logistic()

print(loss_func(model(xb), yb))

输出:

tensor(2.3558, grad_fn=<NllLossBackward>)

将训练循环包装到一个 fit 函数中,以便我们以后运行。

def fit():
    for epoch in range(epochs):
        for i in range((n - 1) // bs + 1):
            start_i = i * bs
            end_i = start_i + bs
            xb = x_train[start_i:end_i]
            yb = y_train[start_i:end_i]
            pred = model(xb)
            loss = loss_func(pred, yb)

            loss.backward()
            with torch.no_grad():
                for p in model.parameters():
                    p -= p.grad * lr
                model.zero_grad()

fit()

print(loss_func(model(xb), yb))

输出:

tensor(0.0826, grad_fn=<NllLossBackward>)

5、使用 nn.Linear 重构

使用PyTorch 的 nn.Linear 类建立一个线性层,以替代手动定义和初始化 self.weightsself.bias、计算 xb @ self.weights + self.bias 等工作。

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin = nn.Linear(784, 10)

    def forward(self, xb):
        return self.lin(xb)

model = Mnist_Logistic()
print(loss_func(model(xb), yb))

输出:

tensor(2.3156, grad_fn=<NllLossBackward>)

我们仍然能够像之前那样使用 fit 方法

fit()

print(loss_func(model(xb), yb))

输出:

tensor(0.0809, grad_fn=<NllLossBackward>)

6、使用 optim 重构

定义一个函数来创建模型和优化器,以便将来可以重用它。

from torch import optim

def get_model():
    model = Mnist_Logistic()
    return model, optim.SGD(model.parameters(), lr=lr)

model, opt = get_model()
print(loss_func(model(xb), yb))

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(2.2861, grad_fn=<NllLossBackward>)
tensor(0.0815, grad_fn=<NllLossBackward>)

7、使用 Dataset 重构

from torch.utils.data import TensorDataset

train_ds = TensorDataset(x_train, y_train)
model, opt = get_model()

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        xb, yb = train_ds[i * bs: i * bs + bs]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(0.0800, grad_fn=<NllLossBackward>)

8、使用 DataLoader 重构

from torch.utils.data import DataLoader

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)

for epoch in range(epochs):
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

输出:

tensor(0.0821, grad_fn=<NllLossBackward>)

9、增加验证

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

我们将在每个epoch结束时计算和打印验证损失。(注意,我们总是在训练之前调用model.train(),在推理之前调用 model.eval(),因为这些由诸如 nn.BatchNorm2dnn.Dropout 等层使用,以确保这些不同阶段的适当行为。)

model, opt = get_model()

for epoch in range(epochs):
    model.train()
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

    model.eval()
    with torch.no_grad():
        valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)

    print(epoch, valid_loss / len(valid_dl))

输出:

0 tensor(0.2981)
1 tensor(0.3033)

10、创建 fit()get_data()

loss_batch 函数计算每个批次的损失。

def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)

    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()

    return loss.item(), len(xb)

fit 运行必要的操作来训练我们的模型并计算每个epoch的训练和验证损失。

import numpy as np

def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
    for epoch in range(epochs):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)

        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)

        print(epoch, val_loss)

get_data 为训练集合验证集返回 DataLoader

def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )

现在,我们获取 DataLoader 和拟合模型的整个过程可以在3行代码中运行:

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)

输出:

0 0.3055081913471222
1 0.31777948439121245

11、总结

我们现在有一个通用数据流水线和训练循环,你可以使用它来训练多种类型PyTorch模型。 各部分的功能总结如下:

  • torch.nn
    • Module:创建一个可调用的对象,其行为类似于一个函数,但也可以包含状态(例如神经网络层权重)。 它知道它包含哪些参数,并且可以将所有梯度归零,循环遍历它们更新权重等。
    • Parametertensor 的包装器(wrapper),它告诉 Module 它具有在反向传播期间需要更新的权重。 只更新具有 requires_grad 属性的 tensor
    • functional:一个模块(通常按惯例导入到F命名空间中),它包含激活函数,损失函数等,以及非状态(non-stateful)版本的层,如卷积层和线性层。
  • torch.optim:包含 SGD 等优化器,可在后向传播步骤中更新 Parameter 的权重。
  • Dataset:带有 __len____getitem__ 的对象的抽象接口,包括 PyTorch 提供的类,如TensorDataset
  • DataLoader:获取任何 Dataset 并创建一个返回批量数据的迭代器。
PyTorch 中神经网络库torch.nn的详细介绍 torch.nn是 PyTorch 深度学习框架中的一个核心模块,它为构建和训练神经网络提供了丰富的类库。通过torch.nn,开发者能够快速构建复杂的深度学习模型,并利用 PyTorch 动态计算图特性进行高效训练和推理。此外,该模块还与torch.optim配合,方便地进行权重优化;以及与DataLoader结合以组织和迭代训练数据。 阅读详情

相关推荐

torch.nn

torch.nn是 PyTorch 提供的一个模块化工具集,专为构建和训练神经网络设计。模块化:通过nn.Module基类,用户可以像搭积木一样组合各种层、激活函数和损失函数,构建复杂模型。动态计算图:PyTorch 的动态计算图(eager execution)允许在运行时定义和修改网络结构,适合研究和快速原型开发。灵活性与控制力:用户可以轻松自定义层、损失函数或前向传播逻辑,同时保留对底层张量操作的访问权限。易用性。

Rhett_Butler0922的博客 1894

常用torch.nn

常用基础pytorch知识

m0_37737957的博客 1675

torch.nn.functional函数和torch.nn.Module层比较

提供了更方便的接口,适合常规的神经网络层,自动管理参数并简化模型的构建。提供了更底层、更灵活的操作,适合在需要完全控制参数和操作的情况下使用。

qq_27390023的博客 2525

pytorch深度学习框架—torch.nn模块(一)

torch.nn模块中包括了pytorch中已经准备好的层,方便使用者调用构建的网络。包括了卷积层,池化层,激活函数层,循环层,全连接层。

xiaoxu的博客 4848

PyTorch基础:神经网络工具箱torch.nn(nn.Module类)

perception.py import torch from torch import nn #首先建立一个全连接的子module,继承nn.Module class Linear(nn.Module): def __init__(self, in_dim, out_dim): super(Linear, self).__init__() #调用nn.Module的构造函数 #使用nn.Parameter来构造需要学习的参数 self.w

weixin_42782833的博客 7305

torch.nn到底是什么?

PyTorch提供了设计优雅的模块和类:torch.nntorch.optim,Dateset和DataLoader,以帮助你创建和训练神经网络。为了充分利用它们的功能并且为你的问题定制它们,你需要正真理解它们在做什么。为了逐渐理解,我们首先在MNIST数据集上训练基本的神经网络,而不使用这些模块的任何特征。最初只会使用最基本的PyTorch tensor功能。然后,我们逐步添加来自torch....

Spring_24的博客 2万+

深入理解 TORCH.NN

原文地址:WHAT IS TORCH.NN REALLY? 本人英语学渣,如有错误请及时指出以便更正 pytorch提供了许多优雅的类和模块帮助我们构建与训练网络,比如 torch.nn, torch.optim,Dataset等。为了充分利用这些模块的功能,灵活操作它们解决各种不同的问题,我们需要更好地理解当我们调用这些模块时它们到底干了些什么,为此,我们首先不调用这些模块实现MNIST手写字...

我的学习笔记 3万+

Pytorch笔记 之 torch.nn 模块简介

参考翻译 [What is torch.nn really?](https://pytorch.org/tutorials/beginner/nn_tutorial.html) 主要是对 PyTorch 框架的各模块进行简要介绍 一定程度上是 PyTorch 的入门笔记 假设已经对神经网络相关基础知识有了一定了解 (或实现过机器学习梯度下降相关代码)

子耶 6万+

torch.nn.Parameter理解

Pytorch官网对torch.nn.Parameter()的解释: torch.nn.Parameter是继承自torch.Tensor的子类,其主要作用是作为nn.Module中的参数使用。它与torch.Tensor的区别就是nn.Parameter会自动被认为是module的可训练参数,即加入到parameter()这个迭代器中去;而module中非nn.Parameter()得普通te...

Stoneplay 4万+

「详解」torch.nn.Fold和torch.nn.Unfold操作

torch.nn.Unfold 提取滑动窗口patches torch.nn.Unfold(kernel_size, dilation=1, padding=0, stride=1) kernel_size:滑动窗口的size stride:空间维度上滑动的步长,Default: 1 padding:在输入的两侧添加的隐式零填充. Default: 0 dilation:空洞卷积的扩充率,Default: 1torch.nn.Unfold按照官方的说法,既从一个batch的样本中,提取出滑动的局部区域块,

绿色羽毛 2万+

PyTorch 笔记(16)— torch.nn.Sequential、torch.nn.Linear、torch.nn.RelU

PyTorch 中的 torch.nn 包提供了很多与实现神经网络中的具体功能相关的类,这些类涵盖了深度神经网络模型在搭建和参数优化过程中的常用内容,比如神经网络中的卷积层、池化层、全连接层这类层次构造的方法、防止过拟合的参数归一化方法、Dropout 方法,还有激活函数部分的线性激活函数、非线性激活函数相关的方法,等等。 下面使用 PyTorchtorch.nn 包来简化我们之前的代码,开始部分的代码变化不大,如下所示: import torch as t batch_n = 100 input_

wohu1104的专栏 1万+

torch.nn.MaxPool1d各参数分析

torch.nn.MaxPool1d各参数(kernel_size、stride、ceil_mode、dilation、padding)的小白文分析:含官方定义和初步翻译、用代码测试并画图举例讲解各参数的作用。 另外讨论了torch.nn.MaxPool1d与torch.max的区别。

yingluo54的博客 3万+

lua,torchnn模块入门笔记

最近看到好多论文的神经网络都是用lua基于torch实现的,于是迫不得已学学lua和torch,才能看懂人家的代码。教程首先看教程: Learn Lua in 15minites! Torch 7,Hello world,neural networks!在上面的教程里没有的,但是在别人的代码里常用的函数,在下面po出来 笔记1.nn.Narrow()这是nn标准库中的提取矩阵中对应子块的函数,官方定

Nicoder的专栏 2万+

torch.nntorch.nn.functional的区别?如何选择?

前言: 在ptorch中,torch.nntorch.nn.functional模块下包含了许多功能相同、用法相似的方法,比如: 1. torch.nn.Softmax(dim=1)(x)torch.nn.functional.softmax(x, dim=1):实现了对x在行维度上进行softmax, 2.torch.nn.Conv2d(3, 6, 5)(x)torch.nn.functional.conv2d(x, weight=torch.rand(6, 3, 5, 5)):实现..

PanYHHH的博客 3256

Pytorch系列1: torch.nn.Sequential()讲解

torch.nn.Sequential是一个Sequential容器,模块将按照构造函数中传递的顺序添加到模块中。通俗的话说,就是根据自己的需求,把不同的函数组合成一个(小的)模块使用或者把组合的模块添加到自己的网络中。主要有两种使用方法: # 第一种方法 conv_module = nn.Sequential( nn.Conv2d(1,20,5), n...

xddwz的博客 2万+

torch.nntorch.nn.functional的区别?

可以在其基础上定义出自己想要的功能参考博文:【pytorchtorch.nntorch.nn.functional 的区别_torch.nntorch.nn.function的区别-CSDN博客文章浏览阅读554次。今天在看pytorch的代码时,看到了torch.nntorch.nn.functional,然后查了两个模块的官方doc,也没有看明白有啥区别,然后就查了一下资料,这里记录一下,方便以后查阅。_torch.nntorch.nn.function的区别。

weixin_56054625的博客 1281

PyTorchtorch.nntorch.nn.functional的区别

torch.nn pytorch中文文档:torch.nn 在__init__()函数里定义,定义的是一个类: torch.nn.functional pytorch中文文档:torch.nn.functional 在__forward()__函数里定义,定义的是一个函数: 两者的区别: nn中是定义的类,以class xx来定义的,可以提取变化的学习参数。nn.functional...

zbzcDZF的博客 6031

torch.nn模块

本文就根据官网文档整理一下torch.nn模块 TORCH.NN非常重要,也是以后用pytorch搭建神经网络的关键模块。所以值得认真学习。 TORCH.NN 第一个关键类: CLASS torch.nn.Parameter A kind of Tensor that is to be considered a module parameter. Parameters are Tensor s...

青山 7157

Pytorch torch.nn库以及nnnn.functional有什么区别?

Pytorch torch.nn库以及nnnn.functional有什么区别?

算法工程师 1080
上一篇: torch.nn到底是什么?
下一篇: 神经网络
Spring_24
博客等级 码龄11年 46粉丝 41原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值