> 文档中心 > 读书笔记-深度学习入门之pytorch-第三章(含全连接方法实现手写数字识别)(详解)

读书笔记-深度学习入门之pytorch-第三章(含全连接方法实现手写数字识别)(详解)

目录

1、张量

2、分类问题

3、激活函数

(1)sigmoid函数

(2)Tanh函数 

(3)ReLU函数

(4)SoftMax函数

(5)Maxout函数 

4、模型表示能力

5、反向传播算法

6、优化算法

(1)torch.optim.SGD 

(2) torch.optim.Adagrad:​

(3)torch.optim.RMSprop

(4)torch.optim.Adadelta

(5)torch.optim.Adam(AMSGrad)(实际中常用)

(6)torch.optim.Adamax

(7)torch.optim.SparseAdam

(8) torch.optim.AdamW

(9) torch.optim.ASGD

(10)torch.optim.LBFGS

(11)torch.optim.Rprop

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

(1)预处理阶段:

(2)权重初始化

(3)防止过拟合:

8、多层全连接层实现手写数字识别


1、张量

参考:pytorch张量(tensor)运算小结_小小鸟要高飞的博客-CSDN博客_pytorch tensor运算

import torcha = torch.Tensor([[2, 3],    [4, 8],    [7, 9]])b = torch.Tensor([[1, 2],    [2, 3],    [3, 4]])c = torch.Tensor([[3, 4],    [2, 3]])print(a.size())  # a为3*2的张量print(torch.mm(a, c))  # 两张量相乘print(torch.cat((a, b), 1))  # 两张量拼接print(torch.mul(a, b))  # 两维度相同的张量对应元素相乘print(torch.inverse(c))  # 张量求逆d = c.numpy()  # 张量转变为数组print(d)print(type(d))e = torch.from_numpy(d)  # 数组转变为张量print(e)print(type(e))

2、分类问题

监督学习分为回归问题与分类问题

Logistic回归:二分类问题中,是希望能找到一个区分度足够好的决策边界将两类分开

3、激活函数

存在必要性:如果没有激活函数的话,神经元的信号处理本质上就是一个线性组合,即使叠加再多层的神经元,整个神经网络也还是线性组合,这样就不能解决非线性的问题,所以激活函数的作用,是为神经网络引入非线性组合的能力,使其可以适用于复杂的应用场景。

正样本让激活函数激活变大,负样本让激活函数激活变小

(1)sigmoid函数

缺点:1>造成梯度消失,对多层网络十分不友好

           2>sigmoid函数输出是非零均值的

           3>收敛速度慢

(2)Tanh函数 

 解决了sigmoid函数中零均值问题,但依旧存在梯度消失问题

(3)ReLU函数

优点:1>简单

           2>解决了梯度消失问题

缺点:1>对于负数,其导数为0,此时会出现神经元的参数永远无法更新的情况称之为神经元死亡,造成这种现象的原因由两个,第一种是在初始化参数时出现负值,第二种是学习率设置较大,导致参数更新幅度太大,出现负值。所以在使用ReLU时,对学习率的设置要注意,需要一个合适的较小的学习率

(4)SoftMax函数

作为输出层的激活函数,专门用于处理多分类问题

(5)Maxout函数 

maxout是由人为设定的K个神经元构成的一层神经元,示意如下

对于maxout层的输出,取k个神经元输出值的最大值作为最终的输出值,这就是maxout的含义。maxout可以看作是分段的线性函数,可以拟合任意的凸函数,提供模型的拟合能力。

引入maxout层,意味着额外增加了一层权重和参数,使得神经网络整体的参数变多,计算量更大。

4、模型表示能力

1>拥有至少一个隐藏层的神经网络可以逼近任何连续函数 

2>过拟合:模型复杂,但忽略了潜在的数据关系,将噪声放大了

5、反向传播算法

能够自动求导,从而根据导数来更新网络参数

6、优化算法

梯度下降:

(1)torch.optim.SGD 

torch.optim.SGD 可实现SGD优化算法,带动量SGD优化算法,带 NAG(Nesterov accelerated gradient) 动量SGD优化算法,并且有 weight_decay 项。

torch.optim.SGD(params,                 lr=,                 momentum=0,                 dampening=0,                 weight_decay=0,                 nesterov=False)

params (iterable):参数组,优化器要管理的那部分参数。
lr (float):初始学习率,可按需随着训练过程不断调整学习率。
momentum (float):动量,通常设置为0.9,0.8。
dampening (float):若采用 nesterov,dampening 必须为 0。
weight_decay (float):权值衰减系数,即L2正则项的系数。
nesterov (bool):bool,是否使用 NAG(Nesterov accelerated gradient)。

(2) torch.optim.Adagrad:

torch.optim.Adagrad(params,                     lr=0.01,                     lr_decay=0,                     weight_decay=0,                     initial_accumulator_value=0,                     eps=1e-10)

(3)torch.optim.RMSprop

 

torch.optim.RMSprop(params,                     lr=0.01,                     alpha=0.99,                     eps=1e-08,                     weight_decay=0,                     momentum=0,                     centered=False)

(4)torch.optim.Adadelta

torch.optim.Adadelta(params,                      lr=1.0,                      rho=0.9,                      eps=1e-06,                      weight_decay=0)

(5)torch.optim.Adam(AMSGrad)(实际中常用)

Adam是一种自适应学习率的优化方法,Adam利用梯度的一阶矩估计和二阶矩估计动态的调整学习率。Adam 结合了 RMSprop 和 Momentum,并进行了偏差修正,是非常常用的优化算法。

torch.optim.Adam(params,                  lr=0.001,                  betas=(0.9, 0.999),                  eps=1e-08,                  weight_decay=0,                  amsgrad=False)

(6)torch.optim.Adamax

torch.optim.Adamax(params,                    lr=0.002,                    betas=(0.9, 0.999),                    eps=1e-08,                    weight_decay=0)

(7)torch.optim.SparseAdam

torch.optim.SparseAdam(params,                        lr=0.001,                        betas=(0.9, 0.999),                        eps=1e-08)

(8) torch.optim.AdamW

torch.optim.AdamW(params,                   lr=0.001,                   betas=(0.9, 0.999),                   eps=1e-08,                   weight_decay=0.01,                   amsgrad=False)

(9) torch.optim.ASGD

torch.optim.ASGD(params,                  lr=0.01,                  lambd=0.0001,                  alpha=0.75,                  t0=1000000.0,                  weight_decay=0)

(10)torch.optim.LBFGS

torch.optim.LBFGS(params, lr=1,                   max_iter=20,                   max_eval=None,                   tolerance_grad=1e-07,                   tolerance_change=1e-09,                   history_size=100,                   line_search_fn=None)

(11)torch.optim.Rprop

torch.optim.Rprop(params,                   lr=0.01,                   etas=(0.5, 1.2),                   step_sizes=(1e-06, 50))

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

(1)预处理阶段:

1>中心化:所有数据减去均值,使得均值为0

2>标准化:方法一:除以标准差,使得分布接近高斯分布

                        方法二:按比例缩放到-1~1之间

3>PCA(主成分分析):能够降低数据的维度

4>白噪声:与PCA一样,先将数据投影到一个特征空间,再每个维度除以特征值来标准化数据,使得数据呈(0,1)的多元高斯分布

(2)权重初始化

1>全0(不可取)

2>随机初始化:高斯随机化,均匀随机化 

3>稀疏初始化:(使用较少)

4>初始化偏置:(bias)

5>批标准化:通常在全连接层后面,非线性层前面(标准技术)

(3)防止过拟合:

一般采用全局权重L2正则化搭配Dropout

1>正则化:L2正则化使用较多(对权重过大的部分进行惩罚)

2>Dropout:训练网络时依概率P保留每个神经元

8、多层全连接层实现手写数字识别

import torchimport torch.nn as nnimport torch.nn.functional as Fimport torch.optim as optimfrom torchvision import datasets, transformsimport torchvisionfrom torch.autograd import Variablefrom torch.utils.data import DataLoaderimport cv2# 数据集加载train_dataset = datasets.MNIST(    root='./num/',    train=True,    transform=transforms.ToTensor(),    download=True)test_dataset = datasets.MNIST(    root='./num/',    train=False,    transform=transforms.ToTensor(),    download=True)batch_size = 64train_loader = torch.utils.data.DataLoader(    dataset=train_dataset,    batch_size=batch_size,    shuffle=True)test_loader = torch.utils.data.DataLoader(    dataset=test_dataset,    batch_size=batch_size,    shuffle=True)# 单批次数据预览# 实现单张图片可视化images, labels = next(iter(train_loader))img = torchvision.utils.make_grid(images)img = img.numpy().transpose(1, 2, 0)std = [0.5, 0.5, 0.5]mean = [0.5, 0.5, 0.5]img = img * std + meanprint(labels)cv2.imshow('win', img)key_pressed = cv2.waitKey(0)# 神经网络模块class LeNet(nn.Module):    def __init__(self, in_dim=None, n_hidden_1=None, n_hidden_2=None, out_dim=None): super(LeNet, self).__init__() self.flatten = nn.Flatten() self.layer1 = nn.Linear(in_dim, n_hidden_1) self.layer2 = nn.Linear(n_hidden_1, n_hidden_2) self.layer3 = nn.Linear(n_hidden_2, out_dim)    def forward(self, x): x = self.flatten(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) return x# 训练模型if torch.cuda.is_available():    device = 'cuda'else:    device = "cpu"net = LeNet(28 * 28, 300, 100, 10).to(device)criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(params=net.parameters(), lr=1e-3)epoch = 1if __name__ == '__main__':    for epoch in range(epoch): sum_loss = 0.0 for i, data in enumerate(train_loader):     inputs, labels = data     inputs, labels = Variable(inputs).to(device), Variable(labels).to(device)     optimizer.zero_grad()  # 将梯度归零     outputs = net(inputs)  # 将数据传入网络进行前向运算     loss = criterion(outputs, labels)  # 得到损失函数     loss.backward()  # 反向传播     optimizer.step()  # 通过梯度做一步参数更新     # print(loss)     sum_loss += loss.item()     if i % 100 == 99:  print('[%d,%d] loss:%.03f' % (epoch + 1, i + 1, sum_loss / 100))  sum_loss = 0.0    net.eval()  # 将模型变换为测试模式    correct = 0    total = 0    for data_test in test_loader: images, labels = data_test images, labels = Variable(images).to(device), Variable(labels).to(device) output_test = net(images) _, predicted = torch.max(output_test, 1) total += labels.size(0) correct += (predicted == labels).sum()    print("correct1: ", correct)    print("Test acc: {0}".format(correct.item() /     len(test_dataset)))

 

 测试结果:90.47%正确率