多层感知机

感知机

  • 给定输入x,权重w,和偏移b,感知机输出 o = σ ( < w , x > + b ) o = \sigma(<w,x> + b) o=σ(<w,x>+b)

    • σ ( x ) = { 1 , if x>0 0 , otherwise \sigma(x) =\begin{cases}1, & \text{if x>0}\\ 0, & \text{otherwise}\end{cases} σ(x)={1,0,if x>0otherwise
      - [
  • 可以看做是二分类问题: 0,1,输出离散的类

    • 线性回归输出实数
    • softmax回归输出概率

训练感知机

  • 训练过程
    • 初始化w =0,b=0
    • 循环 if y i ( < w , x > + b ) ≤ 0 y_i(<w,x> + b ) ≤ 0 yi(<w,x>+b)0
    • 注 :≤0相当于感知机的预测样本错了, ( < w , x > + b ) < 0 (<w,x> + b )<0 (<w,x>+b)<0为负类,因此 y i y_i yi也应为负,正号同理, y与$(<w,x> + b )要同号
      • w ← w + y i x i , b ← b + y i w \leftarrow w+y_ix_i,b \leftarrow b + y_i ww+yixibb+yi
      • 注: w = w + y i x i w=w+y_ix_i w=w+yixi 标号乘样本 做权重更新, $b = b+y_i $ ,b加上标号,
    • 直到所有分类正确
  • 等价于使用批量大小为1的梯度下降,并使用如下损失函数: l ( y , x , w ) = m a x ( 0 , − y < w , x > ) l(y,x,w) = max(0, -y<w,x>) l(y,x,w)=max(0,y<w,x>)
    • 损失函数求导,w导数为 y i x i y_ix_i yixi,b导数为 y i y_i yi
    • max()对应上面if的语句 分类对了,就 = 0不更新,分类错了就会存在梯度,因此损失函数会进行更新

收敛定理

  • 假设数据在半径 r 内
  • 余量ρ分类两类 y ( x T w + b ) ≥ ρ y(x^Tw+b)≥ρ y(xTw+b)ρ 对于 ∣ ∣ w ∣ ∣ 2 + b 2 ≤ 1 ||w||^2+b^2≤1 w2+b21
  • 感知机保证在 r 2 + 1 ρ 2 \large \frac{r^2+1}{ρ^2} ρ2r2+1 步后收敛

XOR 异或 问题

  • 感知机不能拟合XOR函数,它只能产生线性分割面
    - [

对于感知机

  • 感知机是二分类模型

  • 求解算法等价于使用批量大小为1的梯度下降

  • 不能拟合XOR函数

多层感知机

在网络中加入隐藏层在这里插入图片描述

单隐藏层-单分类

  • 输入 x ∈ R n x∈R^n xRn

  • 隐藏层 W 1 ∈ R m × n , b 1 ∈ R m W_1 ∈ R^{m×n},b_1∈R^m W1Rm×n,b1Rm

  • 隐藏层 W 2 ∈ R m , b 2 ∈ R W_2 ∈ R^m,b_2∈R W2Rm,b2R

  • h = σ ( W 1 x + b 1 ) h =\sigma(W_1x+b_1) h=σ(W1x+b1) σ \sigma σ 是按元素的激活函数

  • o = w 2 T h + b 2 o = w^T_2 h +b_2 o=w2Th+b2

  • 为什么需要非线性的激活函数

    • 假设 h = W 1 x + b 1 h =W_1x+b_1 h=W1x+b1,那么 o = w 2 T h + b 2 = w 2 T W 1 x + w 2 T b 1 + b 2 o = w^T_2 h +b_2 = w_2^TW_1x+w_2^Tb_1+b_2 o=w2Th+b2=w2TW1x+w2Tb1+b2 仍然是线性的 ,相当于单层感知机

sigmodi激活函数

  • 对于一个定义域在R中的输入, sigmoid函数将输入变换为区间(0, 1)上的输出。 σ ( x ) = { 1 , if x>0 0 , otherwise \sigma(x) =\begin{cases}1, & \text{if x>0}\\ 0, & \text{otherwise}\end{cases} σ(x)={1,0,if x>0otherwise
  • 因此,sigmoid通常称为挤压函数(squashing function): 它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:
    • s i g m o i d ( x ) = 1 1 + e x p ( − x ) sigmoid(x) = \frac{1}{1+exp(-x)} sigmoid(x)=1+exp(x)1
  • 结果如图:

Tanh激活函数

  • 将输入投影到(-1,1)
  • t a n h ( x ) = 1 − e x p ( − 2 x ) 1 + e x p ( − 2 x ) tanh(x) = \frac{1-exp(-2x)}{1+exp(-2x)} tanh(x)=1+exp(2x)1exp(2x)

ReLU激活函数:rectified linear unit 修正线性单元

  • ReLU(x) = max(x,0)

多类分类:在softmax回归中加了一层隐藏层

  • 输入 x ∈ R n x∈R^n xRn

  • 隐藏层 W 1 ∈ R m × n , b 1 ∈ R m W_1 ∈ R^{m×n},b_1∈R^m W1Rm×n,b1Rm

  • 隐藏层 W 2 ∈ R m × k , b 2 ∈ R k W_2 ∈ R^{m×k},b_2∈R^k W2Rm×k,b2Rk

  • h = σ ( W 1 x + b 1 ) h =\sigma(W_1x+b_1) h=σ(W1x+b1) σ \sigma σ 是按元素的激活函数

  • o = w 2 T h + b 2 o = w^T_2 h +b_2 o=w2Th+b2

  • y = softmax(o)

  • 可以有多隐藏层: h 1 = σ ( W 1 x + b 1 ) h_1 =\sigma(W_1x+b_1) h1=σ(W1x+b1) h 2 = σ ( W 2 h 1 + b 2 ) h_2 =\sigma(W_2h_1+b_2) h2=σ(W2h1+b2) h 3 = σ ( W 3 h 2 + b 3 ) h_3 =\sigma(W_3h_2+b_3) h3=σ(W3h2+b3) o = W 4 h 3 + b 4 o =W_4h_3+b_4 o=W4h3+b4

    • 超参数:隐藏层数 每层隐藏层的大小
  • 示意图如下:

注:

  • 层数越多 模型越复杂,第一层隐藏层设得稍微大一点,取决于输入的复杂度有多少,

  • 假设数据比较复杂,

    • 使用单隐藏层,将隐藏层设的大一些,假设输入维度是128,隐藏层可设64.128.256,
    • 单隐藏层当其设的过大时,容易过拟合,且不好训练
    • 使用多隐藏层,设的相对于单隐藏层较小,且越深是越来越小
  • 多隐藏层,假设第一层设的相对输入较小,那么可能会损失很多信息,需要注意

知识总结

  • 多层感知机在输出层和输入层之间增加一个或多个全连接隐藏层,并通过激活函数转换隐藏层的输出。
  • 常用的激活函数包括ReLU函数、sigmoid函数和tanh函数
  • 使用Softmax来处理多类分类
  • 超参数为隐藏层数 和 每层隐藏层的大小
  • 激活函数的本质 是引入非线性性

代码实现

导入工具包

import torch
from torch import nn
from d2l import torch as d2l

模型

  • 与softmax回归的实现相比, 唯一的区别是我们添加了2个全连接层(之前我们只添加了1个全连接层)

  • 第一层是隐藏层,它包含256个隐藏单元,并使用了ReLU激活函数。 第二层是输出层。

  • net = nn.Sequential(nn.Flatten(),  # Flatten成2维
                        nn.Linear(784, 256),
                        nn.ReLU(),
                        nn.Linear(256, 10))
    
    def init_weights(m):
        if type(m) == nn.Linear:
            nn.init.normal_(m.weight, std=0.01)
    
    net.apply(init_weights);
    

训练过程

  • batch_size, lr, num_epochs = 256, 0.1, 10
    loss = nn.CrossEntropyLoss(reduction='none')
    trainer = torch.optim.SGD(net.parameters(), lr=lr)
    
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
    
    • 运行结果如图:
      在这里插入图片描述
  • updater是更新模型参数的常用函数,它接受批量大小作为参数,可以是sgd函数,也可以是框架的内置优化函数

  • def train_epoch_ch3(net, train_iter, loss, updater):  #@save
        """训练模型一个迭代周期(定义见第3章)"""
        # 将模型设置为训练模式
        if isinstance(net, torch.nn.Module):
            net.train()
        # 训练损失总和、训练准确度总和、样本数
        metric = Accumulator(3)
        for X, y in train_iter:
            # 计算梯度并更新参数
            y_hat = net(X)
            l = loss(y_hat, y)
            if isinstance(updater, torch.optim.Optimizer):
                # 使用PyTorch内置的优化器和损失函数
                updater.zero_grad()
                l.mean().backward()
                updater.step()
            else:
                # 使用定制的优化器和损失函数
                l.sum().backward()
                updater(X.shape[0])
            metric.add(float(l.sum()), accuracy(y_hat, y), y.numel()) # 将样本数,正确的样本数等放进累加器
        # 返回训练损失和训练精度
        return metric[0] / metric[2], metric[1] / metric[2]
    
  • 一个在动画中绘制数据的实用程序类Animator

    • class Animator:  #@save
          """在动画中绘制数据"""
          def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
                       ylim=None, xscale='linear', yscale='linear',
                       fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
                       figsize=(3.5, 2.5)):
              # 增量地绘制多条线
              if legend is None:
                  legend = []
              d2l.use_svg_display()
              self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
              if nrows * ncols == 1:
                  self.axes = [self.axes, ]
              # 使用lambda函数捕获参数
              self.config_axes = lambda: d2l.set_axes(
                  self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
              self.X, self.Y, self.fmts = None, None, fmts
      
          def add(self, x, y):
              # 向图表中添加多个数据点
              if not hasattr(y, "__len__"):
                  y = [y]
              n = len(y)
              if not hasattr(x, "__len__"):
                  x = [x] * n
              if not self.X:
                  self.X = [[] for _ in range(n)]
              if not self.Y:
                  self.Y = [[] for _ in range(n)]
              for i, (a, b) in enumerate(zip(x, y)):
                  if a is not None and b is not None:
                      self.X[i].append(a)
                      self.Y[i].append(b)
              self.axes[0].cla()
              for x, y, fmt in zip(self.X, self.Y, self.fmts):
                  self.axes[0].plot(x, y, fmt)
              self.config_axes()
              display.display(self.fig)
              display.clear_output(wait=True)
      
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值