2023/12/3周报

摘要

本周阅读了一篇关于循环神经网络的论文,论文旨在探索将RNN扩展到深度RNN的不同方法。论文通过对RNN结构的理解和分析,发现从三个方面入手可以使网络变得更深, 输入到隐含函数,隐含到隐含转换函数以及隐含到输出函数。基于此类观察结果,论文提出了几种新颖的深度RNN结构,并通过实验验证了深度RNN优于传统的浅层RNN。此外,还对SVM进行进一步的学习。

Abstract

This week, a paper on recurrent neural networks that explores different ways to extend RNN to deep RNN is readed. Through the understanding and analysis of RNN structure, the paper finds that the network can be deepened from three aspects: input to hidden function, hidden to hidden transformation function and hidden to output function. Based on these observations, several novel deep RNN structures are proposed in this paper, and the results show that the deep RNN is superior to the traditional shallow RNN. Then more knowledge of SVM is learnded.

文献阅读

1.题目

How to Construct Deep Recurrent Neural Networks

2.介绍

背景:论文中提到RNN和前馈神经网络一样去堆叠网络深度,可以产生具有影响力的模型,但不一样的是RNN的深度是比较模糊的,因为RNN的隐藏层在时间上展开时,可以表示为多个非线性层的组合,因此RNN已经足够深了。

思路:作者研究了将RNN扩展到深层RNN的方法,首先研究了RNN的哪些部分可能被认为是浅层的,然后对每一个浅层部分,提出一种可以替代的更深层的设计,这会导致RNN出现很多更深的变体。

3.RNN

RNN是模拟具有输入xt,输出yt和隐含状态ht的离散时间动态系统,动态系统被定义为:
在这里插入图片描述

其中:下标t表示时间,fh表示状态转换函数,fo表示输出函数,每个函数由一组参数(θh和θo)进行优化。
给定一组有N个参数的训练序列,通过最小化代价函数去更新RNN的参数:
在这里插入图片描述

其中d(a, b)是a和b之间的预定义散度测度,例如欧式距离或者交叉熵。
Conventional Recurrent Neural Networks
将转换函数和输出函数定义为:
在这里插入图片描述

其中:W,U和V分别为转换矩阵,输入矩阵和输出矩阵,Φh和Φo是逐元素的非线性函数。通常,对于Φh使用饱和非线性函数,例如sigmoid函数或tanh函数。

4.Deep Recurrent Neural Networks

在前馈神经网络中,深度被定义为在输入和输出之间具有的多个非线性层。但不幸的是,由于RNN的时间结构,该定义不适用在RNN中。如下图所示,在时间上展开的RNN都很深,因为在时间k<t的输入到时间t的输出之间的传播路径跨越了几个非线性层。
在这里插入图片描述

然而,对于RNN在每个时间步上的分析表明,某些转换并不深,而仅仅是线性投影的结果。因此,在没有中间非线性隐含层的情况下,隐含-隐含(ht-1 → ht),隐含-输出(ht → yt)和输入-隐含(xt → ht)函数都是浅的。
在这里插入图片描述

论文中提到可以通过这些转换来思考RNN深度的不同类型,通过在两个连续的隐含状态(ht-1和ht)之间具有一个或多个中间非线性层,可以使隐含-隐含的转换更深。同时,通过在隐含状态ht和输出yt之间插入多个中间非线性层,可以使隐含-输出函数更深。

4.1 Deep Transition RNN

从RNN模拟的动态系统的状态转移方程中可以发现,fh的形式没有限制。因此,论文中建议使用多层感知器来代替fh。
在这里插入图片描述

其中:Φl表示第l层的单元非线性函数,Wl表示第l层的权重矩阵。

4.2 Deep Output

与上述类似,论文中提出可以使用具有L个中间层的多层感知器来建立下图中的输出函数fo:
在这里插入图片描述

4.3 Stacked RNN

堆叠式RNN具有多个层次的转换函数,其定义为:
在这里插入图片描述

其中:ht,l表示在时间t时,第l层的隐含状态。当l = 1时,使用xt代替ht,l来计算状态。

5.实验

论文实验比较了RNN、DT(S)-RNN、DOT(S)-RNN和sRNN 2 layers这4种模型,其中每个模型的大小的选择都给定了范围,以保证实验结果的准确性。

5.1实验过程

本实验使用了随机梯度下降法和裁剪梯度的策略,当代价函数停止降低时,训练结束。

在Polyphonic Music Prediction实验中,为了正则化模型,论文在每次计算梯度时,将标准偏差0.075的高斯白噪声添加到每个权重参数中。

在Language Modeling实验中,学习率从初始值开始,每次代价函数没有显著降低时,学习率减半。实验中不使用任何正则化来进行字符级建模,但对于单词级建模,实验会添加权重噪声。

5.2 结果与分析

如下图所示,展示了四种不同模型在同一数据集上的表现结果。
在这里插入图片描述

从上图的数据可以表明,深度RNN的表现都优于传统的浅层RNN,但每个深度RNN的适用性取决于其所训练的数据。

深度学习

SVM

SVM描述

对二维空间中SVM的形象解释:
1)表示为一条直线,即为线性函数;
2)将一个平面分为两个部分,即具有分类功能,是一种二值分类;
3)位于平面正中间,不偏向任何一方,即注重公平原则,保证双方利益最大化。

总的来说,SVM本质模型是特征空间中最大化间隔的线性分类器,是一种二分类模型。
学习方法包括构建由简至繁的模型:线性可分支持向量机、线性支持向量机及非线性支持向量机。

当训练数据线性可分时,通过硬间隔最大化,学习一个线性的分类器,即线性可分支持向量机,又称为硬间隔支持向量机;

当训练数据近似线性可分时,通过软间隔最大化,也学习一个线性的分类器,即线性支持向量机,又称为软间隔支持向量机;

当训练数据线性不可分时,通过使用核技巧及软间隔最大化,学习非线性支持向量机。

对线性可分的数据求解SVM支持向量点和分类器代码实现:

from time import sleep
import matplotlib.pyplot as plt
import numpy as np
import random
import types

#函数说明:读取数据
def loadDataSet(fileName):
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():                                     #逐行读取,滤除空格等
        lineArr = line.strip().split('\t')
        dataMat.append([float(lineArr[0]), float(lineArr[1])])      #添加数据
        labelMat.append(float(lineArr[2]))                          #添加标签
    return dataMat,labelMat

#函数说明:随机选择alpha
def selectJrand(i, m):
    j = i                                 #选择一个不等于i的j
    while (j == i):
        j = int(random.uniform(0, m))
    return j

#函数说明:修剪alpha
def clipAlpha(aj,H,L):
    if aj > H:
        aj = H
    if L > aj:
        aj = L
    return aj

#函数说明:简化版SMO算法
def smoSimple(dataMatIn, classLabels, C, toler, maxIter):
    #转换为numpy的mat存储
    dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose()
    #初始化b参数,统计dataMatrix的维度
    b = 0; m,n = np.shape(dataMatrix)
    #初始化alpha参数,设为0
    alphas = np.mat(np.zeros((m,1)))
    #初始化迭代次数
    iter_num = 0
    #最多迭代matIter次
    while (iter_num < maxIter):
        alphaPairsChanged = 0
        for i in range(m):
            #步骤1:计算误差Ei
            fXi = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b
            Ei = fXi - float(labelMat[i])
            #优化alpha,更设定一定的容错率。
            if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)):
                #随机选择另一个与alpha_i成对优化的alpha_j
                j = selectJrand(i,m)
                #步骤1:计算误差Ej
                fXj = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b
                Ej = fXj - float(labelMat[j])
                #保存更新前的aplpha值,使用深拷贝
                alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy();
                #步骤2:计算上下界L和H
                if (labelMat[i] != labelMat[j]):
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C + alphas[j] - alphas[i])
                else:
                    L = max(0, alphas[j] + alphas[i] - C)
                    H = min(C, alphas[j] + alphas[i])
                if L==H: print("L==H"); continue
                #步骤3:计算eta
                eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T
                if eta >= 0: print("eta>=0"); continue
                #步骤4:更新alpha_j
                alphas[j] -= labelMat[j]*(Ei - Ej)/eta
                #步骤5:修剪alpha_j
                alphas[j] = clipAlpha(alphas[j],H,L)
                if (abs(alphas[j] - alphaJold) < 0.00001): print("alpha_j变化太小"); continue
                #步骤6:更新alpha_i
                alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j])
                #步骤7:更新b_1和b_2
                b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T
                b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T
                #步骤8:根据b_1和b_2更新b
                if (0 < alphas[i]) and (C > alphas[i]): b = b1
                elif (0 < alphas[j]) and (C > alphas[j]): b = b2
                else: b = (b1 + b2)/2.0
                #统计优化次数
                alphaPairsChanged += 1
                #打印统计信息
                print("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num,i,alphaPairsChanged))
        #更新迭代次数
        if (alphaPairsChanged == 0): iter_num += 1
        else: iter_num = 0
        print("迭代次数: %d" % iter_num)
    return b,alphas

#函数说明:分类结果可视化
def showClassifer(dataMat, w, b):
    #绘制样本点
    data_plus = []                                  #正样本
    data_minus = []                                 #负样本
    for i in range(len(dataMat)):
        if labelMat[i] > 0:
            data_plus.append(dataMat[i])
        else:
            data_minus.append(dataMat[i])
    data_plus_np = np.array(data_plus)              #转换为numpy矩阵
    data_minus_np = np.array(data_minus)            #转换为numpy矩阵
    plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7)   #正样本散点图
    plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图
    #绘制直线
    x1 = max(dataMat)[0]
    x2 = min(dataMat)[0]
    a1, a2 = w
    b = float(b)
    a1 = float(a1[0])
    a2 = float(a2[0])
    y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2
    plt.plot([x1, x2], [y1, y2])
    #找出支持向量点
    for i, alpha in enumerate(alphas):
        if alpha > 0:
            x, y = dataMat[i]
            plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red')
    plt.show()

#函数说明:计算w
def get_w(dataMat, labelMat, alphas):
    alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat)
    w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas)
    return w.tolist()


if __name__ == '__main__':
    dataMat, labelMat = loadDataSet('testSet.txt')
    b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40)
    w = get_w(dataMat, labelMat, alphas)
    showClassifer(dataMat, w, b)

处理线性不可分

解决方案:先将数据变成线性可分的,再构造出最优分类超平面。

步骤:SVM选择一个核函数,将低维非线性数据映射到高维空间中,原始空间中的非线性数据经过核函数映射转换后,在高维空间中变成线性可分的数据,从而可以构造出最优分类超平面。

SVM核技巧

对于核技巧,其目的是希望通过将输入空间内线性不可分的数据映射到一个高纬的特征空间内使得数据在特征空间内是可分的,我们定义这种映射为ϕ(x)。
核函数的选择包括两部分工作:一是核函数类型的选择,二是确定核函数类型后相关参数的选择.
核函数分类: a、线性核函数。线性核,主要用于线性可分的情况,我们可以看到特征空间到输入空间的维度是一样的,其参数少速度快,对于线性可分数据,其分类效果很理想
b、多项式核函数。多项式核函数可以实现将低维的输入空间映射到高纬的特征空间。
c、高斯核函数。高斯径向基函数是一种局部性强的核函数,其可以将一个样本映射到一个更高维的空间内,该核函数是应用最广的一个。
d、sigmoid核函数。采用sigmoid核函数,支持向量机实现的就是一种多层神经网络。

选取核函数的方法:
1、特征数量和样本数量差不多,选用线性核函数
2、特征数量少,样本数量正常,选用高斯核函数
3、特征数量少,样本数量很大,则需要手动添加一些特征来使用线性核函数。
常用的核函数有:
(1)多项式核函数

在这里插入图片描述
(2)高斯核函数
在这里插入图片描述

SVM总结

优点:1、可用于线性/非线性分类,也可以用于回归,泛化错误率低,也就是说具有良好的学习能力,且学到的结果具有很好的推广性。 2、可以解决小样本情况下的机器学习问题,可以解决高维问题,可以避免神经网络结构选择和局部极小点问题。 3、SVM是最好的现成的分类器,现成是指不加修改可直接使用。并且能够得到较低的错误率,SVM可以对训练集之外的数据点做很好的分类决策。

缺点:对参数调节和函数的选择敏感、难以训练大规模数据集、需要组合多个二分类SVM来实现多分类。

总结

本周学习了SVM的实现,阅读了一篇RNN的文章,对RNN进行了复习。下周将继续阅读时序相关的文章。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值