PyTorch深度学习(2)

2023-03-09 17:10:55 浏览数 (2)

Deep Learning = Learning Hierarchical Representations 深度学习即学习层次的表征。

1. 卷积神经网络

1.1 神经网络可视化(Visualization of neural networks)

神经网络每一层的操作有点像将空间某些区域进行折叠

1.2 卷积神经网络的起源(Convolutional Neural Network;CNN)

受到Fukushima在视觉皮层建模方面的启发,使用简单/复杂的细胞层次结构,结合有监督的训练和反向传播,由Yann LeCun教授于88-89年在多伦多大学开发了第一个CNN。

Fukushima的工作具体是什么呢? 手写数字识别。首次提出应用多层简单或者复杂的细胞结构建模,特征:手工加无监督聚类学习。无反向传播。

1.3 卷积神经网络分解

通用的CNN架构能被分解为以下几个基本结构。

  • 标准化(Normalisation):对比度标准化等
  • 滤波器组(Filter banks):边缘检测等
  • 非线性化(Non-linearities):稀疏化、ReLU等
  • 池化(pooling):最大池化(max pooling)等

2. 自然信号数据(Natural Signals)

2.1 自然信号数据特性

  • 周期性:在时域很多模式都会重复出现
  • 局部性:相邻的点较相远的点来说更具关联性
  • 合成性:复杂的事物可以由简单的事物组合而成。字母->单词->句子->文章

2.2 对应神经网络中的处理方法

  • 周期性rightarrow参数共享如果数据存在周期性,可以使用参数共享,即卷积核。
  • 局部性rightarrow稀疏如果数据存在局部性,那么每个神经元只需要与前几个神经元连接
  • 合成性rightarrow多层即神经网络中多层网络合成最终的结果

3. Pytorch实现Mnist手写字识别

代码语言:javascript复制
# load package and data
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt

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

# 神经网络模型偏爱标准化数据,原因是均值为0方差为1的数据在sigmoid、tanh经过激活函数后求导得到的导数很大,
# 反之原始数据不仅分布不均(噪声大)而且数值通常都很大(本例中数值范围是0~255),激活函数后求导得到的导数
# 则接近与0,这也被称为梯度消失。
# 目录放自己下载好的mnist目录,没有下载将download=True,自己新建一个存放数据目录即可
train_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../LSTM_mnist/mnist', train=True, download=False,
                   transform=transforms.Compose([
                       transforms.ToTensor(),
                       # mnist数据集均值0.1307,标准差0.3081
                       transforms.Normalize((0.1307,), (0.3081,))
                   ])),
    batch_size=64, shuffle=True)

test_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../LSTM_mnist/mnist', train=False, transform=transforms.Compose([
                       transforms.ToTensor(),
                       transforms.Normalize((0.1307,), (0.3081,))
                   ])),
    batch_size=1000, shuffle=True)
代码语言:javascript复制
# define model
class SimpleCNN(nn.Module):
    def __init__(self, input_size, n_feature, output_size):
        super(SimpleCNN, self).__init__()
        self.n_feature = n_feature
        # 关于nn.Conv2d()中参数的解释
        # in_channels (int): Number of channels in the input image
        # out_channels (int): Number of channels produced by the convolution
        # kernel_size (int or tuple): Size of the convolving kernel
        # default stride=1, padding=0, dilation=1, groups=1
        # [groupsc参数详解](https://www.jianshu.com/p/20ba3d8f283c)
        # [图解卷积神经网络中stride, padding等操作可视化](https://github.com/vdumoulin/conv_arithmetic)
        # input: (N, C_in, H_in, W_in)
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=n_feature, kernel_size=5)
        self.conv2 = nn.Conv2d(n_feature, n_feature, kernel_size=5)
        self.fc1 = nn.Linear(n_feature*4*4, 50)
        self.fc2 = nn.Linear(50, 10)

    def forward(self, x):
        x = self.conv1(x)  # Mnist数据原始大小(28*28)28-5 1 = 24 (24*24*n_feature)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)  # (12*12*n_feature)
        x = self.conv2(x)  # 12-5 1 = 8 (8*8*n_feature)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)  # (4*4*n_feature)这里解释了上面全连接时为啥是4*4
        x = x.view(-1, self.n_feature*4*4)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.log_softmax(x, dim=1)
        return x
代码语言:javascript复制
# hyper parameters
epochs = 1
input_size = 28*28
output_size = 10
n_features = 6
lr = 0.01

model = SimpleCNN(input_size, n_features, output_size)
model.to(device)
# optimizer
optimizer = optim.SGD(model.parameters(), lr, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model)))

# model train
for epoch in range(epochs):
    model.train()
    for i, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)

        output = model(data)
        loss = F.nll_loss(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if i % 100 == 0:
            print('Train Epoch [{}/{}], [{}/{} ({:.0f}%)], Loss: {:.4f}'.format(
                epoch 1, epochs, i*len(data), len(train_loader.dataset),
                100*i/len(train_loader), loss.item()))
# model eval
model.eval()
test_loss = 0
correct = 0
accuracy_list = []
for data, target in test_loader:
    data, target = data.to(device), target.to(device)

    output = model(data)
    test_loss  = F.nll_loss(output, target, reduction='sum').item()
    pred = output.data.max(1, keepdim=True)[1]  # get the index of the max log-probability
    correct  = pred.eq(target.data.view_as(pred)).cpu().sum().item()

test_loss /= len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
accuracy_list.append(accuracy)
print('nTest set Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)n'.format(
    test_loss, correct, len(test_loader.dataset), accuracy))
代码语言:javascript复制
# 几个预测的实例可视化
for i in range(10):
    plt.subplot(2, 5, i 1)
    plt.imshow(data[i][0])
    plt.title("Prediction: {}".format(
        output.data.max(1, keepdim=True)[1][i].item()))
plt.show()

4. 补充

  1. 可以做一个有趣的实验即打乱图片中的像素后CNN识别正确率下降,而全连接网络则不会,即与最开始提到的三个特性以及对于神经网络采取的假设是吻合的。
  2. 参考2中是对卷积神经网络全面的介绍,包括CNN中常用那些层,以及常用的模型和参数多少计算。

0 人点赞