pytorch入门——边学边练04一个简单网络

访问本站观看效果更佳

写在前面

经过前面三节基础课程,我们可以来一些更加复杂的内容了,今天我们一起来看一个简单的神经网络是如何构成的,并仔细看看神经网络与之前的逻辑回归等课程有什么区别。完整代码参见feedforward_neural_network

概念

前面和大家讨论了线性分类器。但既然是线性的分类器,自然没有办法处理一些非线性结构,比如下图:
image1
解决办法是多层神经网络,底层神经元的输出是高层神经元的输入。我们可以在中间横着画一条线,再竖着画一条线。每画一条线就是使用了一个神经元。大家还记不记得上一节我们讲到的利用10sigmod函数加上一个线性结构对手写数字进行识别?如果我们把这些神经元的输出当作输入,后面再连接一个神经元就能达到很强的分类能力。原理性的知识点这里不多做赘述,我们直接来讲怎么做吧!

目标以及思路

为了和先前的实验进行对比,本节我们依然打算使用mnist数据集,进行手写目标分类。这样有一个好处,数据的加载以及整体的框架都不需要大的改动,我们可以集中精力把思路放在修改模型上。之前我们只使用了一个nn.Linear作为model,现在我们把它改掉,数据的接口都不用变,是不是很方便?

网络结构设计

复杂的事物往往是简单事物的叠加。我们前面提到系统表达能力不足是因为线性的model限制了表达复杂模型的能力。我们需要把模型变成非线性结构。非线性结构如何来实现呢?这里我们只需要做出一个微小的改动,增加一层激活函数。从图形上看,输入和输出无法再用一个线性的公式加以表达。有兴趣的同学可以去看看deep learning的相关书籍。我们重点看看网络设计。

# Fully connected neural network with one hidden layer
class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size) 
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, num_classes)  
    
    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

仔细观察我们的改动非常简单,像一个三明治一样,两个nn.Linear夹住了一个nn.ReLU。其中线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元, 是一种人工神经网络中常用的激活函数(activation function),通常指代以斜坡函数及其变种为代表的非线性函数。 相比于传统的神经网络激活函数,诸如逻辑函数(Logistic sigmoid)和tanh等双曲函数,线性整流函数有着以下几方面的优势:
*更加有效率的梯度下降法以及反向传播:避免了梯度爆炸和梯度消失问题

*简化计算过程:没有了其他复杂激活函数中诸如指数函数的影响;同时活跃度的分散性使得神经网络整体计算成本下降

具体实现

为精简篇幅,这里我仅仅展示一部分操作:
首先现在可以用用GPU了,怎么用呢?只需要定义device,然后告诉数据是把数据放到device里计算还是放到numpy里计算啊~

# Device configuration
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

反正都是套路,写上就对了。
接着我们要问一个问题了,nn.Linear的输入参数与数据有关,我们可以不去考虑,那么hidden_size设置多少好呢?我们设置超参数如下:

# Hyper-parameters 
input_size = 784
hidden_size = 500
num_classes = 10
num_epochs = 5
batch_size = 100
learning_rate = 0.001

其实超参数的设置可能就是要多试试了,当然调参也是有技巧的。跑个几轮看看loss变化幅度,自己估计一下,多试几次就行。
打印一下网络结构:

NeuralNet(
  (fc1): Linear(in_features=784, out_features=500, bias=True)
  (relu): ReLU()
  (fc2): Linear(in_features=500, out_features=10, bias=True)
)

损失函数以及优化器:

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)  

结果如下:

Epoch [1/5], Step [100/600], Loss: 0.2624
Epoch [1/5], Step [200/600], Loss: 0.3268
Epoch [1/5], Step [300/600], Loss: 0.2965
Epoch [1/5], Step [400/600], Loss: 0.1089
Epoch [1/5], Step [500/600], Loss: 0.0886
Epoch [1/5], Step [600/600], Loss: 0.3102
Epoch [2/5], Step [100/600], Loss: 0.1234
Epoch [2/5], Step [200/600], Loss: 0.0823
……………………………………………………………………………………………………………
Epoch [4/5], Step [400/600], Loss: 0.0220
Epoch [4/5], Step [500/600], Loss: 0.0245
Epoch [4/5], Step [600/600], Loss: 0.0079
Epoch [5/5], Step [100/600], Loss: 0.0318
Epoch [5/5], Step [200/600], Loss: 0.1382
Epoch [5/5], Step [300/600], Loss: 0.0397
Epoch [5/5], Step [400/600], Loss: 0.0215
Epoch [5/5], Step [500/600], Loss: 0.0479
Epoch [5/5], Step [600/600], Loss: 0.0614
Accuracy of the network on the 10000 test images: 97.89 %

小结

我们前前后后折腾了那么久,应该熟悉pytorch的基本操作了吧?后面我们来看点复杂的东西吧!未完待续

猜你喜欢

转载自blog.csdn.net/zcgyq/article/details/83087809