深度学习中数据集很小是一种什么样的体验

人工智能99

前言

今天提一个比较轻松的话题,简单探讨数据集大小对深度学习训练的影响。
不知道大家有没有看过这篇文章:Don't use deep learning your data isn't that big
深度学习中数据集很小是一种什么样的体验

是的,有人对深度学习的局限性提供了一个证据:那就是当你数据比较少的时候,深度学习的作用相比较于其他传统的方法并没有什么优势,相反效果还不如传统的方法。

提出这个说法的作者利用两种方法进行了测试,测试的数据集是MNIST,测试计算机是否能正确识别0和1,采用的方法分别是:

  • 5层的深度神经网络,活函数是双曲正切函数;
  • 另一种方法使用的是李加索变量选择方法,这种方法思想就是挑选10个边际p值最小的像素来进行(用这些值做回归就可以了);

然后得出一个结论:
深度学习中数据集很小是一种什么样的体验

那就是使用李加索方法的表现要优于神经网络。What?

正文

那么回到正题,上面的说法到底对不对,我们在数据比较小的时候能否正确地进行深度学习的训练从而达到比较满意的效果?

我们都知道,神经网络相当于一个无限深的万能函数,我们输入变量 x_然后得到结果 _y,中间经历了很多复杂的计算过程。理论上,通过传统算法可以解决的问题通过深度学习都可以解决,但是如果神经网络足够深的时候,虽然这个网络的功能很强大,但是如果数据不够,很容易达到过拟合的现象,从而达不到我们要求的效果。

那么数据集过小是否可以通过深度学习来做,我们来测试一下。

一维信号

我们测试数据很简单,不是我们平常使用的三通道RGB图(3 x 256 x 256),而是普通的一通道一维信号(1 x 168)。

深度学习中数据集很小是一种什么样的体验

上方是我们的一维信号,532nm和1064mn分别对应两种不同的信号,我们只需要对一种信号处理器可。信号的格式是.mat文件,也就是matlab文件。

上面的文件中,train数据集是161 x 168,第一行是x轴的坐标我们不用理会只需要y轴的数据,然后每40个数据组是一类也就是 2-41、42-81、82-121、122-161,一共四类。而test数据集是81x168,第一行同样是x坐标我们不管,每20个数据组是一类(和train数据组顺序上类别是一样的)。也就是说我们一共有四类信号要进行分类。

label分别为: 0、1、2、3.

我们的训练数据量只有160组,而测试数据量也只有80组。

数据读取

我们采用的深度学习库是 Pytorch,利用的 python上的 scipy库, scipy是一个线性函数处理库,当然我们只是使用它对mat文件的读取功能。

创建一个文件读取 .py,引入以下头文件。

import torch
import torch.utils.data as data
import scipy.io
import os
import os.path as osp

然后我们编写文件读取类 .py

# 将原始数据转化为训练需要的数据格式
def to_tensor(data):
    data = torch.from_numpy(data).type(torch.float32)
    data = data.unsqueeze(0)
    return data

# 读取数据类
class LineData(data.Dataset):

    def __init__(self, root, name=532, train=True, transform=to_tensor):
        self.root = os.path.expanduser(root)
        self.name = name
        self.train = train
        self.transform = transform
        self.classes = [0, 1, 2, 3]

        if not osp.exists('datasets'):
            raise FileExistsError('Missing Datasets')

        if self.train:
            self.train_datas = []
            self.train_labels = []

            dataset_dir = osp.join(self.root, 'train_{}nm.mat'.format(self.name))
            train_data = scipy.io.loadmat(dataset_dir)['lineIntensity']
            data_length = len(train_data) - 1              # 161 - 1 = 160

            if self.transform:

                for i in range(data_length):                   # 0 - 159
                    self.train_datas.append(transform(train_data[i+1]))        # i+1 => 1 - 160
                    self.train_labels.append(self.classes[int(i / 40)])
            else:
                raise ValueError('We need tranform function!')

        if not self.train:
            self.test_datas = []
            self.test_labels = []

            dataset_dir = osp.join(self.root, 'test_{}nm.mat'.format(self.name))
            test_data = scipy.io.loadmat(dataset_dir)['lineIntensity']
            data_length = len(test_data) - 1              # 81 - 1 = 80

            if self.transform:

                for i in range(data_length):                   # 0 - 79
                    self.test_datas.append(transform(test_data[i+1]))         # i+1 => 1 - 80
                    self.test_labels.append(self.classes[int(i / 20)])
            else:
                raise ValueError('We need tranform function!')

    def __getitem__(self, index):
"""
        Args:
            index (int): Index

        Returns:
            tuple: (image, target) where target is index of the target class.

"""
        if self.train:
            data, target = self.train_datas[index], self.train_labels[index]
        else:
            data, target = self.test_datas[index], self.test_labels[index]

        return data, target

    def __len__(self):
        if self.train:
            return len(self.train_datas)
        else:
            return len(self.test_datas)

编写神经网络

写好文件读取代码后,我们来设计一下神经网络,因为数据量很少,所以我们的神经网络的层数也应该下降。否则很容易出现过拟合的现象。

我们首先设计5层的神经网络,两个卷积层,一个池化层,两个线性层,激活函数使用Relu:

每个数据的长度为168
模型:两个个卷积层、两个线性层
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv1d(1, 10, 3)    # (168 - 3)/1 + 1 = 166 (* 10)
        self.pool = nn.MaxPool1d(2, 2)      # (166 - 2)/2 + 1= 83 (* 10)
        self.conv2 = nn.Conv1d(10, 20, 3)   # (83 - 3)/1 + 1 = 81 (* 20)
        self.fc1 = nn.Linear(81*20, 100)
        self.fc2 = nn.Linear(100, 4)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = F.relu(self.conv2(x))
        x = x.view(-1, 81*20)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

训练以及测试

设计好神经网络后,我们来进行训练吧!

首先编写训练块的代码,我们使用的优化策略是SGD随机下降法(带有动能),默认的学习率设置为 0.001,验证方式采用经典的分类常用的验证法 CrossEntropyLoss

我们首先进行训练然后进行验证准确率,准确率就是每次测试这四种信号正确次数和总次数的比。

# 主程序页面

import torch
import torch.nn as nn
import torch.utils.data
import torch.optim as optim
from model import Net
from data_utils import LineData

root = 'datasets'    # 数据所在目录,相对目录地址
train_name = '532'   # 或者 '1064'

# device = torch.device('cuda:0')

# 读取文件类
trainset = LineData(root, name=train_name)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True)

testset = LineData(root, name=train_name, train=False)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=True)

net = Net()
# net = net.to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

# 下面的epoch改成 2 可以达到100%的准确率
epoch_sum = 1
# 训练
for epoch in range(epoch_sum):

    loss_sum = 0.0
    for i, data in enumerate(trainloader, 0):

        inputs, labels = data
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        loss_sum += loss.item()
        if i % 10 == 9:
            print('[epoch:{} num:{}] loss:{}'.format(epoch, i, loss_sum / 20))
            loss_sum = 0.0

print('Finished Training')

# 验证
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        inputs, labels = data
        outputs = net(inputs)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 80 test images: %d %%' % (
    100 * correct / total))

pass

好了,开始训练,由于数据量很少,所以在CPU上训练即可。

第一次训练,epoch为1,lr为0.001:

[epoch:0 num:9] loss:1.693671927541118e+16
[epoch:0 num:19] loss:53694975.30745087
[epoch:0 num:29] loss:6.2672371854667905e+28
[epoch:0 num:39] loss:51403236.52956776
Finished Training
Accuracy of the network on the 80 test images: 25 %

结果看起来很不好嘛...准确率25%,看起来是猜的,损失波动很剧烈,应该是我们学习率调的太高了,接下来调整一下学习率。

第二次训练,epoch为1,lr为0.0001:

[epoch:0 num:9] loss:133432.54784755706
[epoch:0 num:19] loss:67940.00796541572
[epoch:0 num:29] loss:109.18773172795773
[epoch:0 num:39] loss:1.1358043849468231
Finished Training
Accuracy of the network on the 80 test images: 25 %

loss下降很平缓,但是epoch看起来不够导致loss下降没有彻底,准确率依然很低,让我们来调整一下epoch。

第三次训练,epoch为5,lr为0.0001:

[epoch:0 num:9] loss:3024598166.2773805
[epoch:0 num:19] loss:3117157163.829549
[epoch:0 num:29] loss:258.4028107881546
[epoch:0 num:39] loss:0.6990358293056488
[epoch:1 num:9] loss:0.6830220401287079
[epoch:1 num:19] loss:66.56461009383202
[epoch:1 num:29] loss:0.7117315053939819
[epoch:1 num:39] loss:0.6977931916713714
[epoch:2 num:9] loss:0.6974189281463623
[epoch:2 num:19] loss:0.6898959457874299
[epoch:2 num:29] loss:0.7101178288459777
[epoch:2 num:39] loss:0.6914324820041656
[epoch:3 num:9] loss:0.686737447977066
[epoch:3 num:19] loss:0.6972651600837707
[epoch:3 num:29] loss:0.7028001189231873
[epoch:3 num:39] loss:0.6998239696025849
[epoch:4 num:9] loss:0.6997098863124848
[epoch:4 num:19] loss:0.6969940900802613
[epoch:4 num:29] loss:0.696108078956604
[epoch:4 num:39] loss:0.6910847663879395
Finished Training
Accuracy of the network on the 80 test images: 25 %

loss下降到一定级别没有再下降,而准确率依然很迷,有可能还是因为学习率过高而导致loss一直卡在一个范围无法彻底下降,我们再试着尝试下降一下学习率。

第四次训练,epoch为2,lr为0.00001:

[epoch:0 num:9] loss:200.58453428081702
[epoch:0 num:19] loss:5.724525341391564
[epoch:0 num:29] loss:0.2976263818090047
[epoch:0 num:39] loss:0.05558242934057489
[epoch:1 num:9] loss:0.0004892532759185996
[epoch:1 num:19] loss:0.00012833428763769916
[epoch:1 num:29] loss:9.479262493137242e-05
[epoch:1 num:39] loss:3.948449189010717e-05
Finished Training
Accuracy of the network on the 80 test images: 100 %

完美,看来我们摸索出了合适的学习率( 0.00001),经过10次测试,准确率分别为:100%、100%、100%、100%、100%、100%、100%、100%、100%、98%。

如果我将epoch从2换成1,则是100%、77%、100%、100%、100%、86%、100%、100%、100%、100%。

epoch从1换成3则是:100%、100%、100%、100%、100%、100%、100%、100%、100%、100%。

我们如果修改一下神经网络层为3层全连接层,lr为 0.00001效果会很差,即使训练10个以上的epochy也不会达到100%的准确率,但是如果将lr下降到 0.000001,准确率则就会达到100%了:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(168, 1000)
        self.fc2 = nn.Linear(1000, 100)
        self.fc3 = nn.Linear(100,4)

    def forward(self, x):
        x = x.view(-1, 168)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

结论

通过上面的测试,看起来200数量以内的数据集,只要设计层合理,学习率合适,那么准确率也是可以达到比较好的效果。

其实所说的过拟合常常是因为我们设计的神经网络层数过深,但是数据没有那么多,神经网络就会充分"榨干"那些训练数据,过度吸收那些训练集的信息,导致在测试的时候没有那么准确,说以如果数据集过少,可以通过减少层数的方法来减轻错误。

但是如果数据包含的信息很丰富,但是数据量很少,这时候光调整层数就不够了,我们需要一些数据增强的技术扩充数据集,从而"喂饱"神经网络,不至于让神经网络出现异常。当然,数据集扩充是针对含信息量很丰富的信息来实现的,如果信息都像我们之前使用的一维信号一样,一般就没有必要扩充了。

撩我吧

  • 如果你与我志同道合于此,老潘很愿意与你交流;
  • 如果你喜欢老潘的内容,欢迎关注和支持。
  • 如果你喜欢我的文章,希望点赞👍 收藏 📁 评论 💬 三连一下~

想知道老潘是如何学习踩坑的,想与我交流问题~请关注公众号「oldpan博客」。
老潘也会整理一些自己的私藏,希望能帮助到大家,点击神秘传送门获取。

Original: https://www.cnblogs.com/bigoldpan/p/14466359.html
Author: 老潘的博客
Title: 深度学习中数据集很小是一种什么样的体验



相关阅读

Title: [论文阅读笔记67]Chinese NER by Span-Level Self-Attention

1. 基本信息

题目论文作者与单位来源年份Chinese NER by Span-Level Self-AttentionXiaoyu Dong,Xin Xin,Ping Guo 北京理工大学201915th International Conference on Computational Intelligence and Security (CIS)

1 Citations, 20 References

论文链接:https://sci-hub.st/https://ieeexplore.ieee.org/abstract/document/9023665/

论文代码:没有发现代码

2. 要点

研究主题问题背景核心方法流程亮点数据集结论论文类型关键字NER把词作为语义单元,而分词的错误很有可能延伸到后面的任务,特别对于词典外的词。在语义表达层上使用自关注力机制。通过bert进行中文字符编码,然后输到LSTM中进行多span的语义编码,最后self-attention进行学习,输出预测结果。 对于基于char与span两个层进行了实验。OntoNotes 4.0OntoNotes 4.0取得79.97% F1-scoreself-attention,ner

3. 模型(核心内容)

3.1 模型

深度学习中数据集很小是一种什么样的体验

Span Feature Representation

字符层:

深度学习中数据集很小是一种什么样的体验

采用了bert的倒数第二隐含层的编码输出。

span层:

深度学习中数据集很小是一种什么样的体验

p_i为第i个span, c表示字符,e_p表示LSTM编码,最后进到一组span的编码。x_p=深度学习中数据集很小是一种什么样的体验.用这个表达来表示一个句子了。

Span Semantic Value

这里加了一个全连接来转一下。

深度学习中数据集很小是一种什么样的体验

Span-level Self-attention

这里进入到自关注的模型了。

深度学习中数据集很小是一种什么样的体验

深度学习中数据集很小是一种什么样的体验

深度学习中数据集很小是一种什么样的体验

把span向量输入到多头自关注中进行计算,这个公式表示的是transformer block的一部分,原论文的那部分圈出来:

深度学习中数据集很小是一种什么样的体验

有一个问题:bert编码那里都已经有跑了很多层transformer了,虽然是在字符上,这里是否在span层上用真的起到作用?看了一下实验,好像是只有0.2的提升

这个有一个处理冲突的细节:

Covering conflict:取长实体;

Overlap conflict:取概率分类高的实体。

; 4. 实验与分析

4.1 数据集

OntoNotes 4.0

24,371 sentences,490,000 characters

4.2 训练参数

深度学习中数据集很小是一种什么样的体验

; 4.3 效果

深度学习中数据集很小是一种什么样的体验

第一个框:word-based methods

第二个框: character-based method

第三个框:论文自己的baseline:"Char-Attn": 在字符之间进行了self-attention. "Span-LSTM":经过两层384维的LSTM来处理,直接到输出层进行分类了。

作者对提升进行了总结:通过LSTM可以使用在词级上的信息。使用了Span-Attn可以使模型对spans之间的依赖信息。

还有两张与baseline的分析图:

深度学习中数据集很小是一种什么样的体验

深度学习中数据集很小是一种什么样的体验

5. 代码

6. 总结

6.1 优

中文基于span在self-attention的一次研究,这个思路值得学习。

6.4 不足

一般的span思路研究,没有看到代码的细节。实验整的来看少了一点。
如果换了语料,对于要枚举这么多实span实体,有点担心效率问题,O(k2n2)。

7. 知识整理(知识点,要读的文献,摘取原文)

8. 参考文献

made by happyprince

Original: https://blog.csdn.net/ld326/article/details/123824174
Author: happyprince
Title: [论文阅读笔记67]Chinese NER by Span-Level Self-Attention