Pytorch Note12 多层神经网络

Posted Real&Love

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorch Note12 多层神经网络相关的知识,希望对你有一定的参考价值。

Pytorch Note12 多层神经网络


全部笔记的汇总贴: Pytorch Note 快乐星球

多层神经网络

在前面中,我们了解到了机器学习领域中最常见的两个模型,线性回归模型和 Logistic 回归模型,他们分别是处理机器学习中最常见的两类问题-回归问题和分类问题。

在前面的线性回归中,我们的公式是 y = w x + b y = w x + b y=wx+b,而在 Logistic 回归中,我们的公式是 y = S i g m o i d ( w x + b ) y = Sigmoid(w x + b) y=Sigmoid(wx+b),其实它们都可以看成单层神经网络,其中 Sigmoid 被称为激活函数,之后我们会详细介绍激活函数以及为什么必须使用激活函数,下面我们从理解神经网络入手。

理解神经网络

神经网络的灵感来自于人脑的神经元系统,下面我们放一张人脑的神经元和神经网络的对比图

img

左边是一张神经元的图片,神经元通过突触接受输入,然后通过神经激活的方式传输给后面的神经元。这对比于右边的神经网络,首先接受数据输入,然后通过计算得到结果,接着经过激活函数,再传给第二层的神经元。

所以前面讲的 logistic 回归模型和线性回归模型都可以看做是一个单层神经网络,而 logistic 回归中使用了激活函数 sigmoid。

神经网络使用的激活函数都是非线性的,每个激活函数都输入一个值,然后做一种特定的数学运算得到一个结果,下面举几个例子

sigmoid 激活函数

σ ( x ) = 1 1 + e − x \\sigma(x) = \\frac{1}{1 + e^{-x}} σ(x)=1+ex1

def Sigmoid(x):
    return 1 / (1 + np.exp(-x))
    
x = np.arange(-10,10,0.1)    
plt.plot(x, Sigmoid(x),clip_on=False)
plt.title('Sigmoid')

在这里插入图片描述

tanh 激活函数

t a n h ( x ) = 2 σ ( 2 x ) − 1 tanh(x) = 2 \\sigma(2x) - 1 tanh(x)=2σ(2x)1

def Tanh(x):
    return 2 * Sigmoid(2*x) - 1
    
plt.plot(x, Tanh(x))
plt.title('Tanh')

在这里插入图片描述

ReLU 激活函数

R e L U ( x ) = m a x ( 0 , x ) ReLU(x) = max(0, x) ReLU(x)=max(0,x)

def Relu(x):
    return np.maximum(0, x)

plt.plot(x, Relu(x))
plt.title('Relu')

在这里插入图片描述

神经网络的结构

神经网络就是很多个神经元堆在一起形成一层神经网络,那么多个层堆叠在一起就是深层神经网络,我们可以通过下面的图展示一个两层的神经网络和三层的神经网络

可以看到,神经网络的结构其实非常简单,主要有输入层,隐藏层,输出层构成,输入层需要根据特征数目来决定,输出层根据解决的问题来决定,那么隐藏层的网路层数以及每层的神经元数就是可以调节的参数,而不同的层数和每层的参数对模型的影响非常大.

神经网络向前传播也非常简单,就是一层一层不断做运算就可以了,可以看看下面这个例子

为什么要使用激活函数

激活函数在神经网络中非常重要,使用激活函数也是非常必要的,前面我们从人脑神经元的角度理解了激活函数,因为神经元需要通过激活才能往后传播,所以神经网络中需要激活函数,下面我们从数学的角度理解一下激活函数的必要性。

比如一个两层的神经网络,使用 A 表示激活函数,那么

y = w 2 A ( w 1 x ) y = w_2 A(w_1 x) y=w2A(w1x)

如果我们不使用激活函数,那么神经网络的结果就是

y = w 2 ( w 1 x ) = ( w 2 w 1 ) x = w ˉ x y = w_2 (w_1 x) = (w_2 w_1) x = \\bar{w} x y=w2(w1x)=(w2w1)x=wˉx

可以看到,我们将两层神经网络的参数合在一起,用 w ˉ \\bar{w} wˉ 来表示,两层的神经网络其实就变成了一层神经网络,只不过参数变成了新的 w ˉ \\bar{w} wˉ,所以如果不使用激活函数,那么不管多少层的神经网络, y = w n ⋯ w 2 w 1 x = w ˉ x y = w_n \\cdots w_2 w_1 x = \\bar{w} x y=wnw2w1x=wˉx,就都变成了单层神经网络,所以在每一层我们都必须使用激活函数。

最后我们看看激活函数对神经网络的影响

可以看到使用了激活函数之后,神经网络可以通过改变权重实现任意形状,越是复杂的神经网络能拟合的形状越复杂,这就是著名的神经网络万有逼近定理。

下面我们通过例子来感受一下神经网络的强大之处

二分类问题

import torch
import numpy as np
from torch import nn
from torch.autograd import Variable
import torch.nn.functional as F

import matplotlib.pyplot as plt
%matplotlib inline

决策边界

首先我们先定义一个决策边界的函数,这样可以方便我们后面画出我们的决策边界,这里我们是采用了plt.contourf来进行画,因为有时候我们的函数并不是一个线性函数,很难表示。

def plot_decision_boundary(model, x, y):
    # Set min and max values and give it some padding
    x_min, x_max = x[:, 0].min() - 1, x[:, 0].max() + 1
    y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
    h = 0.01
    # Generate a grid of points with distance h between them
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
    # Predict the function value for the whole grid
    Z = model(np.c_[xx.ravel(), yy.ravel()]) # 得到所有的点的坐标
    Z = Z.reshape(xx.shape)
    # Plot the contour and training examples
    plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral) # 绘制等高线轮廓
    plt.ylabel('x2')
    plt.xlabel('x1')
    plt.scatter(x[:, 0], x[:, 1], c=y.reshape(-1), s=40, cmap=plt.cm.Spectral)

这次我们仍然处理一个二分类问题,但是比前面的 logistic 回归更加复杂

随机生成数据

首先我们随机生成一些数据

np.random.seed(1)
m = 400 # 样本数量
N = int(m/2) # 每一类的点的个数
D = 2 # 维度
x = np.zeros((m, D))
y = np.zeros((m, 1), dtype='uint8') # label 向量,0 表示红色,1 表示蓝色
a = 4

for j in range(2):
    ix = range(N*j,N*(j+1))
    t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # theta
    r = a*np.sin(4*t) + np.random.randn(N)*0.2 # radius
    x[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
    y[ix] = j
plt.scatter(x[:, 0], x[:, 1], c=y.reshape(-1), s=40, cmap=plt.cm.Spectral)

在这里插入图片描述

logistic 回归解决

x = torch.from_numpy(x).float()
y = torch.from_numpy(y).float()

w = nn.Parameter(torch.randn(2, 1))
b = nn.Parameter(torch.zeros(1))

optimizer = torch.optim.SGD([w, b], 1e-1)

def logistic_regression(x):
    return torch.mm(x, w) + b

criterion = nn.BCEWithLogitsLoss()
for e in range(100):
    out = logistic_regression(Variable(x))
    loss = criterion(out, Variable(y))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if (e + 1) % 20 == 0:
        print('epoch: {}, loss: {}'.format(e+1, loss.data[0]))
epoch: 20, loss: 0.7033562064170837
epoch: 40, loss: 0.6739853024482727
epoch: 60, loss: 0.6731640696525574
epoch: 80, loss: 0.6731465458869934
epoch: 100, loss: 0.6731461882591248

结果演示

def plot_logistic(x):
    x = Variable(torch.from_numpy(x).float())
    out = F.sigmoid(logistic_regression(x))
    out = (out > 0.5) * 1
    return out.data.numpy()
plot_decision_boundary(lambda x: plot_logistic(x), x.numpy(), y.numpy())
plt.title('logistic regression')

在这里插入图片描述

可以看到,logistic 回归并不能很好的区分开这个复杂的数据集,如果你还记得前面的内容,你就知道 logistic 回归是一个线性分类器,这个时候就该我们的神经网络登场了!

神经网络解决二分类问题

# 定义两层神经网络的参数
w1 = nn.Parameter(torch.randn(2, 4) * 0.01) # 隐藏层神经元个数 2
b1 = nn.Parameter(torch.zeros(4))

w2 = nn.Parameter(torch.randn(4, 1) * 0.01)
b2 = nn.Parameter(torch.zeros(1))

# 定义模型
def two_network(x):
    x1 = torch.mm(x, w1) + b1
    x1 = F.tanh(x1) # 使用 PyTorch 自带的 tanh 激活函数
    x2 = torch.mm(x1, w2) + b2
    return x2

optimizer = torch.optim.SGD([w1, w2, b1, b2], 1.)

criterion = nn.BCEWithLogitsLoss()
# 我们训练 10000 次
for e in range(10000):
    out = two_network(Variable(x))
    loss = criterion(out, Variable(y))
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if (e + 1) % 1000 == 0:
        print('epoch: {}, loss: {}'.format(e+1, loss.data[0]))
def plot_network(x):
    x = Variable(torch.from_numpy(x).float())
    x1 = torch.mm(x, w1) + b1
    x1 = F.tanh(x1)
    x2 = torch.mm(x1, w2) + b2
    out = F.sigmoid(x2)
    out = (out > 0.5) * 1
    return out.data.numpy()
plot_decision_boundary(lambda x: plot_network(x), x.numpy(), y.numpy())
plt.title('2 layer network')

在这里插入图片描述

可以看到神经网络能够非常好地分类这个复杂的数据,和前面的 logistic 回归相比,神经网络因为有了激活函数的存在,成了一个非线性分类器,所以神经网络分类的边界更加复杂。

下一章传送门:Note13 反向传播算法

以上是关于Pytorch Note12 多层神经网络的主要内容,如果未能解决你的问题,请参考以下文章

深度学习6. 多层感知机及PyTorch实现

深度学习6. 多层感知机及PyTorch实现

送书 | 从零开始学习 PyTorch:多层全连接神经网络

Pytorch Note31 深度残差网络 ResNet

Pytorch学习笔记——多层感知机的实现

Pytorch Note32 稠密连接的卷积网络 DenseNet