IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Pytorch 学习 -> 正文阅读

[人工智能]Pytorch 学习

一、简介

PyTorch 是一个基于 Torch 的 Python 开源机器学习库(Python+Torch(深度学习框架)),由Facebook的人工智能研究小组开发。
Pytorch类似于Numpy,可以使用GPU,运行在CUDA上;内置动态图,可以定义深度学习模型,可灵活的进行训练和应用。

(1)PyTorch 基于Python的科学计算包,服务于以下两种场景:

● 作为NumPy的替代品,可以使用GPU的强大计算能力
● 提供最大的灵活性和高速的深度学习研究平台

(2)PyTorch 是一个 Python 包,提供两个高级功能:

● 具有强大的GPU加速的张量计算(如NumPy)
包含自动求导系统的的深度神经网络

二、pytorch 的基石——Tensor 张量

Tensors 与 Numpy 中的 ndarrays 类似,但是在 PyTorch中 Tensors 可以使用 GPU 进行计算。

要介绍 Tensor 这个数据类型,我觉得有必要扯一下数学。我们都知道:标量(Scalar)是只有大小,没有方向的量,如1,2,3等;向量(Vector)是有大小和方向的量,其实就是一串数字,如(1,2);矩阵(Matrix)是好几个向量拍成一排合并而成的一堆数字,如 [1,2;3,4]。

标量,向量,矩阵它们三个都是张量,标量是零维的张量,向量是一维的张量,矩阵是二维的张量。除此之外,张量还可以是四维的、五维的等等。
在这里插入图片描述
张量就是按照任意维排列的一堆数字的推广。如图所示,矩阵不过是三维张量下的一个二维切面。要找到三维张量下的一个标量,需要三个维度的坐标来定位。

1、创建 tensor

可以通过 torch.tensor() 将普通数组转化为 tensor,torch.empty() 或r and() 可以创建随机 tensor,torch.zeros()、ones() 创建数据都是 0 或 1 的 tensor。

import torch x = torch.tensor([5.5, 3])  # 创建一维张量 
print(x) 
x = torch.rand(5, 3)  # 随机生成5*3的矩阵 print(x)

在这里插入图片描述

2、tensor 运算

(1) 算术操作

result = torch.empty(5, 3) 
x = torch.rand(5, 3) 
y = torch.rand(5, 3) 
torch.add(x, y, out=result) 
print(x) 
print(y)
print(result) 

在这里插入图片描述

(2)索引

我们还可以使?类似NumPy的索引操作来访问 Tensor 的一部分,需要注意的是:索引出来的结果与原数据共享内存,也即修改?个,另?个会跟着修改

x = torch.rand(5, 3) 
print(x)

y = x[0,:] 
y += 1 
print(y) 
print(x) 
print(x[0,:]) 

在这里插入图片描述

(3)改变形状

注意 view() 返回的新 tensor 与源 tensor 没有共享内存(其实是 tensor 的副本),也即更改其中的?个,另外?个不会跟着改变。(顾名思义,view仅是改变了对这个张量的观察角度)

x = torch.rand(5, 3) 
print(x) 
z = x.view(-1,5) 
print(z)
print(x) 

在这里插入图片描述

3、张量和 Numpy 的相互转换

张量和Numpy数组之间的转换十分容易。

(1)Tensor 到 Numpy,在使用 Cpu 的情况下,张量和 array 将共享他们的物理位置,改变其中一个的值,另一个也会随之变化。

a = torch.ones(5)
print(a)
"""
tensor([1., 1., 1., 1., 1.])
"""
b = a.numpy()
print(b)
"""
[1. 1. 1. 1. 1.]
"""
a.add_(1)
print(a)
print(b)
"""
tensor([2., 2., 2., 2., 2.])
[2. 2. 2. 2. 2.]
"""

(2)Numpy 到 Tensor ,在使用 Cpu 的情况下,张量和 array 将共享他们的物理位置,改变其中一个的值,另一个也会随之变化。

import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
"""
[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
"""

(3)Gpu下的转换

# let us run this cell only if CUDA is available
# We will use ``torch.device`` objects to move tensors in and out of GPU
if torch.cuda.is_available():
    device = torch.device("cuda")          // a CUDA device object
    y = torch.ones_like(x, device=device)  //  直接在GPU上创建tensor
    x = x.to(device)                       // 或者使用.to("cuda"),将tensor移入GPU
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       // 将tensor移出GPU,也能在移动时改变dtype
"""
tensor([-0.4743], device='cuda:0')
tensor([-0.4743], dtype=torch.float64)
"""

三、自动求导机制

在pytorch中,神经网络的核心是自动微分。自动微分包会提供自动微分的操作,它是一个取决于每一轮的运行的库,你的下一次的结果会和你上一轮运行的代码有关,因此,每一轮的结果,有可能都不一样。

PyTorch 中,所有神经网络的核心是 autograd 包,它为张量上的所有操作提供了自动求导机制。Pytorch 通过 Tensor 来储存数据,我们可以把它看作一个节点,通过 Function 实现数据操作,即节点之间转换的路径。

autograd 包为张量上的所有操作提供了自动求导。

它是一个在运行时定义的框架,这意味着反向传播是根据你的代码来确定如何运行,并且每次迭代可以是不同的。

torch.Tensor 是这个包的核心类。如果设置.requires_grad 为 True,那么将会追踪所有对于该张量的操作

当完成计算后通过调用 .backward(),自动计算所有的梯度,这个张量的所有梯度将会自动积累到 .grad 属性
这里是引用

在自动梯度计算中还有另外一个重要的类 Function。Tensor 和 Function 互相连接并生成一个非循环图,它表示和存储了完整的计算历史。

每个张量都有一个 .grad_fn 属性,这个属性引用了一个创建了 Tensor 的 Function(除非这个张量是用户手动创建的,即这个张量的 grad_fn 是 None)。

import torch
x=torch.ones(2,2,requires_grad=True)
print(x) 
print(x.grad_fn) 

在这里插入图片描述
由于x是被直接创建的,也就是说它是一个叶子节点,所以它的grad_fn属性的值为None

如果需要计算导数,你可以在 Tensor 上调用.backward()获取求得的导数用 .grad 方法

如果 Tensor 是一个标量(即它包含一个元素数据)则不需要为 backward() 指定任何参数,但是如果它有更多的元素,你需要指定一个 gradient 参数来匹配张量的形状。

1、标量对张量的求导

原则上,pytorch 不支持张量对张量的求导,它只支持标量对张量的求导。

先看标量对张量求导的情况:

如下所示为一个训练过程,输入张量x,经过一系列操作之后得到输出y。
在这里插入图片描述
如下所示为实现上面过程的代码,首先通过 tensor 定义张量,通过属性 requires_grad 指定是否需要自动求导。之后执行正向操作 *w1、+b、*w2,最后求平均得到输出 y。接着通过 backward() 执行反向传播,就可以得到张量的 grad 值了。

// 定义张量
x = torch.ones(5, requires_grad=True)
w1 = torch.tensor(2.0, requires_grad=True)
w2 = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(4.0, requires_grad=False)

// 执行正向操作
l1 = x * w1
l2 = l1 + b
l3 = l2 * w2
y = l3.mean()

// 反向传播
y.backward()

print(l1.data, l1.grad, l1.grad_fn)
// tensor([2., 2., 2., 2., 2.]) None <MulBackward0 object at 0x0000024D8E921BE0>
print(l2.data, l2.grad, l2.grad_fn)
// tensor([6., 6., 6., 6., 6.]) None <AddBackward0 object at 0x000001B960FC0F98>
print(y)
// tensor(18., grad_fn=<MeanBackward0>)
print(w1.grad, w2.grad)
// tensor(3.) tensor(6.)
print(x.grad)
// tensor([1.2000, 1.2000, 1.2000, 1.2000, 1.2000])

从上面的输出可以看到 x 一开始为 [1,1,1,1,1],乘以 w1 后为 [2., 2., 2., 2., 2.],+b 之后为 [6., 6., 6., 6., 6.],再乘以 3 为 [18., 18., 18., 18., 18.],求均值得到 y 为 18。

在这里插入图片描述

Tensor 的 grad_fn 属性用于记录上一步是经过怎样的操作得到自己的,用于反向传播时进行求导。例如 l1.grad_fn 为 MulBackward0 代表其反向传播操作为乘法。

反向传播后通过 grade 属性可以获得最后输出对本张量的导数值
例如上面的操作中输出为 y,反向传播后,w2.grad 获得的就是 dy/dw2。由链式求导法则可得 dy/dw2=dy/dl3 × dl3/dw2。由于 y 由 l3 求均值得到,即 y=1/5(Σl3),所以 dy/dl3=1/5,又 l3=l2 * w2,所以 dl3/dw2=l2,所以 dy/dw2=1/5*l2=1/5(6., 6., 6., 6., 6.)=6。同理通过反向链式求导得到 w1、x 的 grad。

注意到 l1、l2 的 grade 值为 None,这是由于张量 l1、l2、l3 都是中间计算结果,它们被称为非叶张量,相对地由用户创建的 x、w1、w2 被称为叶张量(leaf tensor)。pytorch为了节约内存并不会保存中间张量的导数值,只会用grad_fn来记录是通过什么操作产生的。如果我们希望查看的话,可以通过retain_grad()来保存非叶张量的导数值

在这里插入图片描述

2、张量对张量求导的求导

默认情况下 pytorch 不允许张量对张量求导,所以在使用张量对张量求导的时候,必须要传入一个与被求导张量同形的张量,然后pytorch根据传入的张量与被求导张量作加权求和将其转化为标量
张量的梯度是一个与原张量同形的张量

首先创建一个叶子节点 x

x = torch.tensor([[1.0,2.0],[3.0,4.0]],requires_grad=True)
print(x)

// tensor([[1., 2.], [3., 4.]], requires_grad=True)

接下来计算 y=3*x

y = 3*x
print(y)

// tensor([[ 3., 6.], [ 9., 12.]], grad_fn=<MulBackward0>)

接下来我们直接用 y 求导 y.backward()。毫无意外,直接报错,这就印证了前面说过的pytorch不支持张量对张量直接求导。
我们必须构建一个与 y 同形的张量 z,把 z 作为 y.backward() 的参数求 y 对 x 的导

z = torch.tensor([[1.0,0.1],[0.01,0.001]],dtype=torch.float)
y.backward(z)
print(x.grad)

输出结果:tensor([[3.0000, 0.3000], [0.0300, 0.0030]]) (张量的梯度是一个与原张量同形的张量)

对于表达式 y.backward(z) (y、z为同形张量)的计算过程,实际上将 y 与 z 加权求和得到标量 m,然后用 m 对 x 求导得到结果,也就是说实际上有这样一步计算 m=torch.sum(y*z)

四、神经网络包 nn 和优化器 optm

使用 torch.nn 包来构建神经网络。nn 包依赖 autograd 包来定义模型并求导。 一个 nn.Module 包含各个层和一个 forward(input) 方法,该方法返回 output。

1、nn.Module(模组)

在 Pytorch 中编写神经网络,所有的层结构和损失结构都来自 torch.nn , 所有模型构建都是从基类 nn.Module 继承的。

2、torch.optim(优化)

(1)一阶优化算法:使用各个参数的梯度值来更新参数,最常用的是梯度下降
在这里插入图片描述
(2)二阶优化算法:使用二阶导数 ( Hessian方法 ) 来最大化或者最小化代价函数,主要基于牛顿法。下面举一个例子
在这里插入图片描述
这样,我们就得到了学习速率为0.01,动量是0.9的随机梯度下降,在优化之前 要将梯度归零,optimizer.zeros(),然后通过
loss.backward() 反向传播,自动求导得到每个参数的梯度,然后通过 optimizer.step() 进行参数的更新。

3、模型的保存和加载

在 Pytorch 中使用 torch.save 来保存模型的结构和参数,有两种方式:

(1)保存整个模型的结构信息和参数信息, 保存的对象是模型 model
(2)保存模型的参数, 保存的对象是模型的状态 model.state_dict()
save 的第一个参数是保存的对象, 第二个是保存的路径

加载模型对应两种保存方式也有两种

(1) 加载完整的模型结构和参数信息,使用 load_model = torch.load(‘model.pth’) 在网络较大的时候记载时间教程,存储空间较大
(2)加载模型参数信息,需要先导入模型的结构,然后通过 model.load_state_dict(torch.load(‘model_state.pth’)) 来导入。

4、神经网络的典型训练过程

● 定义包含一些可学习的参数(或者叫权重)神经网络模型;
● 在数据集上迭代;
● 通过神经网络处理输入;
● 计算损失(输出结果和正确值的差值大小);
● 将梯度反向传播回网络的参数;
● 更新网络的参数,主要使用如下简单的更新原则:weight = weight - learning_rate * gradient
在这里插入图片描述

(1)定义神经网络模型

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


# 汉字均为我个人理解,英文为原文标注。
class Net(nn.Module):

    def __init__(self):
        // 继承原有模型
        super(Net, self).__init__()
        // 1 input image channel, 6 output channels, 5x5 square convolution
        // kernel
        // 定义了两个卷积层
        // 第一层是输入1维的(说明是单通道,灰色的图片)图片,输出6维的的卷积层(说明用到了6个卷积核,而每个卷积核是5*5的)。
        self.conv1 = nn.Conv2d(1, 6, 5)
        // 第一层是输入1维的(说明是单通道,灰色的图片)图片,输出6维的的卷积层(说明用到了6个卷积核,而每个卷积核是5*5的)。
        self.conv2 = nn.Conv2d(6, 16, 5)
        // an affine operation: y = Wx + b
        // 定义了三个全连接层,即 fc1 与 conv2 相连,将 16 张 5*5 的卷积网络一维化,并输出 120 个节点。
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        // 将 120 个节点转化为 84 个。
        self.fc2 = nn.Linear(120, 84)
        // 将 84 个节点输出为 10 个,即有 10 个分类结果。
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        // Max pooling over a (2, 2) window
        // 用 relu 激活函数作为一个池化层,池化的窗口大小是 2*2,这个也与上文的 16*5*5 的计算结果相符(一开始我没弄懂为什么 fc1 的输入点数是 16*5*5 ,后来发现,这个例子是建立在 lenet5 上的)。
        // 这句整体的意思是,先用 conv1 卷积,然后激活,激活的窗口是 2*2 。
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        // If the size is a square you can only specify a single number
        // 作用同上,然后有个需要注意的地方是在窗口是正方形的时候,2的写法等同于(2,2)。
        // 这句整体的意思是,先用 conv2 卷积,然后激活,激活的窗口是 2*2。
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        // 这句整体的意思是,调用下面的定义好的查看特征数量的函数,将我们高维的向量转化为一维。
        x = x.view(-1, self.num_flat_features(x))
        // 用一下全连接层fc1,然后做一个激活。
        x = F.relu(self.fc1(x))
        // 用一下全连接层fc2,然后做一个激活。
        x = F.relu(self.fc2(x))
        // 用一下全连接层fc3。
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        // 承接上文的引用,这里需要注意的是,由于pytorch只接受图片集的输入方式(原文的单词是batch),所以第一个代表个数的维度被忽略。
        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()
print(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(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
"""

// 现在我们已经构建好模型了,但是还没有开始用bp呢,如果你对前面的内容有一些印象的话,你就会想起来不需要我们自己去搭建,我们只需要用某一个属性就可以了,autograd。

// 现在我们需要来看一看我们的模型,下列语句可以帮助你看一下这个模型的一些具体情况。

params = list(net.parameters())
print(len(params))
print(params[0].size())  // conv1's .weight

"""
10
torch.Size([6, 1, 5, 5])
"""

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

"""
tensor([[ 0.0114,  0.0476, -0.0647,  0.0381,  0.0088, -0.1024, -0.0354,  0.0220,
         -0.0471,  0.0586]], grad_fn=<AddmmBackward>)
"""

//最后让我们清空缓存,准备下一阶段的任务。
net.zero_grad()
out.backward(torch.randn(1, 10))

(2)损失函数

选用nn.MSELoss来计算误差

# 这个框架是来弄明白我们现在做了什么,这个网络张什么样子。
"""
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss
"""
# 到目前为止我们学习了Tensor(张量),autograd.Function(自动微分),Parameter(参数),Module(如何定义,各个层的结构,传播过程)
# 现在我们还要学习损失函数和更新权值。

# 这一部分是来搞定损失函数
output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

# 看一看我们的各个点的结果。
print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU

"""
<MseLossBackward object at 0x7efbcad51a58>
<AddmmBackward object at 0x7efbcad51b38>
<AccumulateGrad object at 0x7efbcad51b38>
"""

# 重点来了,反向传播计算梯度。
net.zero_grad()     # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

"""
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([ 0.0087, -0.0073,  0.0013,  0.0006, -0.0107, -0.0042])
"""

(3)更新权值

在反向传播计算完所有参数的梯度后,还需要使用优化方法来更新网络的权重和参数,权值更新采用的方法是随机梯度下降法(SGD, Stochastic Gradient Descent )。
在这里插入图片描述

import torch.optim as optim

# 新建一个优化器,SGD只需要要调整的参数和学习率
optimizer = optim.SGD(net.parameters(), lr=0.01)

# 先梯度清零(与net.zero_grad()效果一样)
optimizer.zero_grad()   
output = net(input)
loss = criterion(output, target)
loss.backward()

#更新参数
optimizer.step()    

以上步骤我们实现了网络的数据完整传播步骤。

五、数据的加载与预处理

要想有一个好的模型你必须有一些好的数据,并将他们转化为模型可以理解的语言,这个工作非常重要。
??
当我们需要处理图像,文本,音频或者视频数据的时候,你可以使用标准的 python 库来将这些数据就转化为 numpy array,然后再转化为 Tensor。下面列出一些相应的python库:
在这里插入图片描述
特别是对于视觉领域,我们写了一个叫做 torchvision 的包,他可以将很多知名数据的数据即涵盖在内。并且,通过 torchvision.datasets 和 torch.utils.data.DataLoader 进行数据的转化。在本里中我们将会使用 CIFAR10 数据集,它有以下各类: ‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。

PyTorch 通过 torch.utils.data 对一般常用的数据加载进行了封装,可以很容易地实现多线程数据预读和批量加载。

torchvision 是 PyTorch 中专门用来处理图像的库,torchvision 已经预先实现了常用图像数据集,包括前面使用过的 CIFAR-10,ImageNet、COCO、MNIST、LSUN 等数据集,可通过 torchvision.datasets 方便的调用。

1、Dataset

(1)Torchvision.datasets

Torchvision.datasets 可以理解为 PyTorch 团队自定义的 dataset, 这些 dataset 帮我们提前处理好了很多的图片数据集,我们拿来就可以直接使用:
在这里插入图片描述
(2)自定义 Dataset

Dataset 是一个抽象类,为了能够方便的读取,需要将要使用的数据包装为Dataset类。
自定义的 Dataset 需要继承它并且实现两个成员方法:
在这里插入图片描述
定义好数据集类之后使用 dataloader 加载数据。

2、torchvision.models

Torchvision 不仅提供了常用图片数据集,还提供了训练好的模型,可以加载之后,直接使用,或者在进行迁移学习 torchvision.models 模块的子模块中包含以下子模型结构。
在这里插入图片描述
在这里插入图片描述

3、torchvision.transforms

transforms 模块提供了一般的图像转换操作类,用作数据处理和数据增强。

data_transforms = transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])

(1)transforms.Compose(transforms) 方法是将多种变换组合在一起。
上述对data_transforms进行了四种变换,前两个是对PILImage进行的,分别对其进行随机大小和随机宽高比的裁剪,之后resize到指定大小224,以及对原始图像进行随机的水平翻转;第三个transforms.ToTensor() 将PILImage转变为torch.FloatTensor的数据形式;最后一个Normalize则是对tensor进行的。

(2)多种组合变换有一定的先后顺序,处理 PILImage 的变换方法(大多数方法)都需要放在 ToTensor 方法之前,而处理tensor的方法(比如Normalize方法)就要放在ToTensor方法之后。

transforms中的函数

 torchvision.transforms.Normalize(mean, std) 

用给定的均值和标准差分别对每个通道的数据进行正则化。具体来说,给定均值(M1,…,Mn),给定标准差(S1,…,Sn),其中n是通道数(一般是3),对每个通道进行如下操作: output[channel] = (input[channel] - mean[channel]) / std[channel]

比如:原来的tensor是三个维度的,值在[0,1]之间,经过变换之后就到了[-1,1], 计算如下:((0,1)-0.5)/0.5=(-1,1)

torchvision.transforms.ToTensor

把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloadTensor

torchvision.transforms.ToPILImage

将shape为(C,H,W)的Tensor或shape为(H,W,C)的numpy.ndarray转换成PIL.Image,值不变。

torchvision.transforms.CenterCrop(size)

将给定的PIL.Image进行中心切割,得到给定的size,size可以是tuple,(target_height, target_width)。size也可以是一个Integer,在这种情况下,切出来的图片的形状是正方形。

torchvision.transforms.RandomCrop(size, padding=0)

切割中心点的位置随机选取。size可以是tuple也可以是Integer。

torchvision.transforms.RandomHorizontalFlip

随机水平翻转给定的PIL.Image,概率为0.5。即:一半的概率翻转,一半的概率不翻转。

torchvision.transforms.RandomSizedCrop(size, interpolation=2)

先将给定的PIL.Image随机切,然后再resize成给定的size大小。

torchvision.transforms.Pad(padding, fill=0) 

将给定的PIL.Image的所有边用给定的pad value填充。 padding:要填充多少像素 fill:用什么值填充

4、处理数据和训练模型的技巧

数据预处理

(1)中心化
每个特征维度都减去相应的均值来实现中心化,这样可以使数据变成0均值。
(2)标准化
在数据都变成0均值后,采用标准化的做法是数据不同的特征维度都有相同的规模。有两种常用的方法。一种是除以数据标准差,是数据的分布接近标准高斯分布。二是让每个维度特征的最大值和最小值按比例缩放到-1~1之间。
(3)PCA
在用PCA处理数据前,通常将数据中心化,并计算数据的协方差矩阵。该协方差矩阵是对称半正定的,可以通过矩阵来进行奇异值分解(SVD), 然后对数据进行去相关性,再将其投影到一个特征空间,选取较大的、主要的向量来降低数据的维度,这种方法叫做PCA,主成分分析
(4)白噪声
与PCA相似,首先将数据投影到一个特征空间,然后每个维度除以特征值来标准化这些数据。直观上就是将一个多元高斯分布转化到了一个0均值、协方差为1的多元高斯分布。白噪声的处理增强数据中的噪声,因为其增强了数据中的所有维度。
在实际处理中,中心化和标准化都特别重要,但是白噪声和PCA在卷积神经网络中几乎不使用,因为网络可以自动学些如何提取这些特征。

权重初始化

(1)全0初始化
直观但是不应采取的策略就是全0初始化。在神经网络中如果每个权重都被初始化为相同的值,那个每个神经元都会计算出相同的结果,在反向传播时计算出相同的梯度,最后权重都会有相同的更新。
(2)随机初始化
我们希望权重初始化时能够尽量靠近0,但不都是0。一般随机化策略有高斯随机化和均匀随机化,值得注意的是并不是越小的随机化产生的结果越好。
(3)稀疏初始化
将权重全部初始化为0,然后挑选一些参数赋随机值,这种方法在实际中使用较少。
(4)初始化偏置
对于偏置(bias),通常初始化为0。
(5)批标准化(Batch Normalization)
核心思想是标准化这个过程是可微的,批标准化通常应用在全连接层后面,非线性层前面。批标准化还可以理解为在网络中的每一层前面都会做数据的预处理。

防止过拟合

(1)正则化
L2正则化是正则化中比较常用的手段,其思想是对权重过大的部分进行惩罚,也就是直接在损失函数中加入权重的二范数量级。
(2)Dropout
核心思想是在训练网络的时候依概率P保留每个神经元,也就是每次训练的时候有些神经元会被置为0。

六、训练分类器

● 首先装载数据,并将其统一化;
● 定义CNN;
● 定义损失函数;
● 训练神经网络;
● 测试网络;

1、CPU 版本

import torch
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

import matplotlib.pyplot as plt
import numpy as np

# functions to show an image


def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()

# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

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


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


net = Net()

for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs
        inputs, labels = data

        # zero the parameter gradients
        criterion = nn.CrossEntropyLoss()
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

dataiter = iter(testloader)
images, labels = dataiter.next()

# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

outputs = net(images)

_, predicted = torch.max(outputs, 1)

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

2、GPU 版本

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Assuming that we are on a CUDA machine, this should print a CUDA device:

print(device)

net.to(device)

inputs, labels = inputs.to(device), labels.to(device)
import torch.optim as optim
import torch
import torchvision
import torchvision.transforms as transforms

transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                         shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

import matplotlib.pyplot as plt
import numpy as np

# functions to show an image


def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.cpu().numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()

# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

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


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


net = Net()

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

# Assuming that we are on a CUDA machine, this should print a CUDA device:

print(device)

net.to(device)



for epoch in range(2):  # loop over the dataset multiple times

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        # zero the parameter gradients
        criterion = nn.CrossEntropyLoss()
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.item()
        if i % 2000 == 1999:    # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

dataiter = iter(testloader)
images, labels = dataiter.next()
images, labels = inputs.to(device), labels.to(device)

# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

outputs = net(images)

_, predicted = torch.max(outputs, 1)

print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = inputs.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        images, labels = inputs.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1


for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:10:46  更:2021-07-15 16:11:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/28 9:18:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码