pytorch 学习笔记(一)

本文介绍PyTorch的基础知识及实战应用,包括张量操作、自动求导、神经网络构建等核心内容。通过实例演示PyTorch在深度学习任务中的灵活运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pytorch是一个动态的建图的工具。不像Tensorflow那样,先建图,然后通过feedrun重复执行建好的图。相对来说,pytorch具有更好的灵活性。

编写一个深度网络需要关注的地方是:

  1. 网络的参数应该由什么对象保存
  2. 如何构建网络
  3. 如何计算梯度和更新参数

数据放在什么对象中

pytorch新版本(0.4之后)中只有一种变量类型,Tensor。

  • Tensor: 就像ndarray一样,一维TensorVector,二维TensorMatrix,三维及以上称为Tensor
  • 有两种Tensor,一个是requires_grad=False的,即:不需要计算其梯度的参数。一个是requires_grad=True,即:需要计算梯度的参数
import torch
x  = torch.tensor([2,3,4], dtype=torch.float) # 创建一个Tensor,值为[2.,3.,4.],类型为 float

# 创建一个需要求 梯度的 tensor。
x2 = torch.tensor([2,3,4], dtype=torch.float, requires_grad=True)
x.size()
torch.Size([3])

tensor的一些操作

a.add_(b) # 所有带 _ 的operation,都会更改调用对象的值,
#例如 a=1;b=2; a.add_(b); a就是3了,没有 _ 的operation就没有这种效果,只会返回运算结果
torch.cuda.is_available()
True

自动求导

使用pytorch的自动求导∂y/∂x\partial y/\partial xy/x功能需要满足两个条件:

  • y.requires_grad==Truex.requires_grad==True
  • x 到 y的计算图不能在 torch.no_grad() 的 with block下

两个条件都很容易满足,只要将 x.requires_grad=True ,那么根据pytorch的运算规则(一op的两个输入进行运算,只要有一个的 requires_grad=True,那么输出结果Tensor的requires_grad一定为True)得到的 y 的 requires_grad为True

import torch
x = torch.tensor([1,1,1,1,1], dtype=torch.float, requires_grad=True)
y = x * 2
grads = torch.FloatTensor([1,2,3,4,5])
y.backward(grads)#如果y是scalar的话,那么直接y.backward(),然后通过x.grad方式,就可以得到var的梯度
x.grad           #如果y不是scalar,那么只能通过传参的方式给x指定梯度
Variable containing:
  2
  4
  6
  8
 10
[torch.FloatTensor of size 5]

neural networks

使用torch.nn包中的工具来构建神经网络
构建一个神经网络需要以下几步:

  • 定义神经网络的权重,搭建网络结构
  • 遍历整个数据集进行训练
    • 将数据输入神经网络
    • 计算loss
    • 计算网络权重的梯度
    • 更新网络权重
      • weight = weight + learning_rate * gradient
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):#需要继承这个类
    def __init__(self):
        super(Net, self).__init__()
        #建立了两个卷积层,self.conv1, self.conv2,注意,这些层都是不包含激活函数的
        self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 square convolution kernel
        self.conv2 = nn.Conv2d(6, 16, 5)
        #三个全连接层
        self.fc1   = nn.Linear(16*5*5, 120) # an affine operation: y = Wx + b
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)

    def forward(self, x): #注意,2D卷积层的输入data维数是 batchsize*channel*height*width
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) # If the size is a square you can only specify a single number
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:] # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()
net
Net (
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear (400 -> 120)
  (fc2): Linear (120 -> 84)
  (fc3): Linear (84 -> 10)
)
len(list(net.parameters())) #为什么是10呢? 因为不仅有weights,还有bias, 10=5*2。
                            #list(net.parameters())返回的learnable variables 是按照创建的顺序来的
                            #list(net.parameters())返回 a list of torch.FloatTensor objects
10
input = Variable(torch.randn(1, 1, 32, 32))
out = net(input) #这个地方就神奇了,明明没有定义__call__()函数啊,所以只能猜测是父类实现了,并且里面还调用了forward函数
out              #查看源码之后,果真如此。那么,forward()是必须要声明的了,不然会报错
out.backward(torch.randn(1, 10))

使用loss criterion 和 optimizer训练网络

torch.nn包下有很多loss标准。同时torch.optimizer帮助完成更新权重的工作。这样就不需要手动更新参数了

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)  # 有了optimizer就不用写这些了
import torch.optim as optim
# create your optimizer
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# in your training loop:
optimizer.zero_grad() # 如果不置零,Variable 的梯度在每次 backward 的时候都会累加。

output = net(input) # 这里就体现出来动态建图了,你还可以传入其他的参数来改变网络的结构

loss = criterion(output, target)
loss.backward()
optimizer.step() # Does the update

整体NN结构

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

class Net(nn.Module):#需要继承这个类
    def __init__(self):
        super(Net, self).__init__()
        #建立了两个卷积层,self.conv1, self.conv2,注意,这些层都是不包含激活函数的
        self.conv1 = nn.Conv2d(1, 6, 5) # 1 input image channel, 6 output channels, 5x5 square convolution kernel
        self.conv2 = nn.Conv2d(6, 16, 5)
        #三个全连接层
        self.fc1   = nn.Linear(16*5*5, 120) # an affine operation: y = Wx + b
        self.fc2   = nn.Linear(120, 84)
        self.fc3   = nn.Linear(84, 10)

    def forward(self, x): #注意,2D卷积层的输入data维数是 batchsize*channel*height*width
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) # If the size is a square you can only specify a single number
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    
    def num_flat_features(self, x):
        size = x.size()[1:] # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features

net = Net()

# create your optimizer
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# in your training loop:
for i in range(num_iteations):
    optimizer.zero_grad() # zero the gradient buffers,如果不归0的话,gradients会累加

    output = net(input) # 这里就体现出来动态建图了,你还可以传入其他的参数来改变网络的结构

    loss = criterion(output, target)
    loss.backward() # 得到grad,i.e.给Variable.grad赋值
    optimizer.step() # Does the update,i.e. Variable.data -= learning_rate*Variable.grad

其它

  1. 关于求梯度,只有requires_grad=Trueleaf tensor 的梯度会被放在 .grad 属性中,其余 tensor 的梯度不会被保存在 .grad 属性中(可以用retain_grad使得requires_grad=True非leaf tensor的.grad属性存储其梯度)
# numpy to Tensor
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a) # 如果a 变的话, b也会跟着变,说明b只是保存了一个地址而已,并没有深拷贝
print(b) # 
a = np.ones(5)
b = torch.from_numpy(a)# ndarray --> Tensor
a_ = b.numpy() # Tensor --> ndarray
np.add(a_, 1, out=a_) # 会影响 b 的值
# 将Tensor放到Cuda上
if torch.cuda.is_available():
    x = x.to('cuda:0')
    y = y.to('cuda:0')
    x + y
# tensor 与 numpy
import torch
import numpy as np
n1 = np.array([1., 2.]).astype(np.float32)
t1 = torch.FloatTensor(n1)
print(t1)
# 使用 torch.FloatTensor(n1) 创建tensor,是深拷贝
### PyTorch 学习笔记概述 李毅编写的《PyTorch学习笔记》是份详尽的学习指南,旨在帮助读者掌握深度学习框架PyTorch的核心概念和技术。这份笔记不仅涵盖了基础理论知识,还提供了大量实践案例和代码实现。 #### 主要内容结构 1. **环境搭建** 安装配置PyTorch运行所需的软件环境,包括Python版本的选择、CUDA支持以及Anaconda的使用方法[^2]。 2. **张量操作** 解释了如何创建、转换和处理多维数组(即张量),这是构建神经网络模型的基础构件之[^3]. 3. **自动求导机制** 描述了Autograd模块的工作原理及其在反向传播算法中的应用,使用户能够轻松定义复杂的计算图并高效训练模型[^4]. 4. **优化器与损失函数** 探讨了几种常用的梯度下降变体(SGD, Adam等)及相应的损失衡量标准(MSE Loss, CrossEntropyLoss等),这些组件对于调整权重参数至关重要[^5]. 5. **数据加载与预处理** 展示了Dataset类和DataLoader类的功能特性,它们可以简化大规模图像分类任务的数据读取流程;同时也介绍了常见的图片增强技术来扩充样本集规模[^6]. 6. **卷积神经网络(CNN)** 结合具体实例深入剖析CNN架构设计思路,如LeNet,VGG,resnet系列,并给出完整的项目源码供参考学习[^7]. 7. **循环神经网络(RNN/LSTM/GRU)** 阐述时间序列预测场景下RNN家族成员的特点优势,通过手写字符识别实验验证其有效性[^8]. 8. **迁移学习实战演练** 利用预训练好的大型模型作为特征提取器,在新领域内快速建立高性能的应用程序,减少重复劳动成本的同时提高了泛化能力[^9]. 9. **分布式训练入门指导** 当面对超大数据集时,单机难以满足需求,此时可借助于torch.distributed包来进行集群式的协同工作模式探索[^10]. ```python import torch from torchvision import datasets, transforms transform = transforms.Compose([transforms.ToTensor()]) train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform) train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True) for images, labels in train_loader: print(images.shape) break ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值