深度学习:IMDB 分类玩具示例中的架构选择。嵌入的性能低于简单基线

问题描述 投票:0回答:1

我正在比较两种不同网络架构的性能,以解决“IMBD 电影评论”的二元分类问题,该问题在“Python 深度学习”第 3 章中介绍。

加载数据:

# num_words means only use most common `n` words in the vocab (train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words=10_000) train_xs = torch.vstack([multi_vectorize(t) for t in train_data]).to(torch.float) train_ys = torch.tensor(train_labels).unsqueeze(dim=1).to(torch.float) # 250k -> (250k,1) for compatability w/ train ## train/val split val_xs = train_xs[0:10_000] val_ys = train_ys[0:10_000] partial_train_xs = train_xs[10_000:] partial_train_ys = train_ys[10_000:]

本书使用的架构是一个简单的顺序密集网络:

Sequential( (0): Linear(in_features=10000, out_features=16, bias=True) (1): ReLU() (2): Linear(in_features=16, out_features=16, bias=True) (3): ReLU() (4): Linear(in_features=16, out_features=1, bias=True) (5): Sigmoid() )

该网络的输入是“multihot”编码的文本片段。例如,给定一篇包含 80 个单词的评论,假设总词汇量为 10k 个单词(域),则每个输入将是一个包含 10k 个元素的向量,如果向量中的索引位置对应于向量中的字母,则带有 
0

词汇不存在,如果存在则

1
VOCAB_SZ = max(max(s) for s in train_data) + 1
def multi_vectorize(seq):
    t = torch.zeros(VOCAB_SZ)
    for s in seq:
        t[s] = 1
    return t

这是有道理的,但它也会忽略重复的单词,因为输入只能将它们表示为存在或不存在。

我知道嵌入通常用作 NLP 任务中的第一层,因此我尝试运行一个包含嵌入层的基本实验,假设它会提高性能:


添加嵌入层:

我做了一些修改来创建嵌入层。首先,我们现在不需要每个向量都是 10K 元素,因为我们不对每个输入进行多热编码。相反,我们确保每个输入向量的大小相同,这是通过找到训练集中最大的输入大小并使用给定的“填充标记”将每个输入填充到至少那么大来实现的。那么嵌入层就是

(10001,3)

。第一个维度是

10001
,反映
10000
的词汇大小加上新添加的填充标记的词汇大小。第二个维度是任意的,表示每个嵌入令牌的维度。
## make all token lists the same size.
MAX_INPUT_LEN = len(max(train_data,key=len))

## zero is already in the vocab, which starts tokens at zero
## since the max token is VOCAB_SZ - 1 (zero based) we can 
## use VOCAB_SZ as the start point for new special tokens
PAD_TOKEN = VOCAB_SZ

def lpad(x,maxlen=MAX_INPUT_LEN,pad_token=PAD_TOKEN):
    padlen = maxlen - len(x)
    if padlen > 0:
        return [pad_token] * padlen + x
    return x

EMB_SZ = 3
NUM_EMBED = VOCAB_SZ + 1 # special pad char (10,000)
emb_model = nn.Sequential(
          nn.Embedding(NUM_EMBED,EMB_SZ),
          nn.Flatten(),
          nn.Linear(EMB_SZ * MAX_INPUT_LEN,16),
          nn.ReLU(),
          nn.Linear(16,16),
          nn.ReLU(),
          nn.Linear(16,1),
          nn.Sigmoid()
        )


结果/问题:

该网络的训练时间要长一个数量级,而且性能也更差。我不确定为什么训练速度这么慢(第一个版本中的 10 个 epoch 大约需要 3 秒,而这个版本需要 30 秒)。由于嵌入,存在额外的间接层,但该模型的总参数计数实际上少于第一个版本,因为我们没有为每个输入使用 10K 大小的向量。
所以这就是困惑点#1,为什么训练速度会慢很多?
其次是性能。我本以为添加嵌入层将使模型具有更多维度来表达评论的情绪。至少它可以避免像多热版本那样“忽略”在输入中重复的标记。我尝试了更小和更大的嵌入层,但我似乎无法获得高于约 82% 的验证准确度,并且需要约 80 轮才能达到这一目标。第一个版本仅经过 10 个 epoch 后就达到了 90% 的验证准确率。 我该如何思考为什么嵌入版本的性能更差?

我认为困惑来自以下几点:

python keras deep-learning pytorch
1个回答
0
投票
在第一种方法中,每个文本有一个向量

在第二种方法中,至少按照您定义模型的方式,一个输入对应一个单词。
  • 不确定嵌入层的来龙去脉,但根据我的说法,如果你这样做,你将需要像 LSTM 这样的 RNN。
  • 我不知道在第二种情况下如何提供模型,但我的猜测是它将迭代元组(文本单词,文本标签)而不是(文本,文本标签),这可能花费更长的时间,也解释了性能较差的原因。

不过如果不看你的训练循环就不确定。也不是 Pytorch 专家

© www.soinside.com 2019 - 2024. All rights reserved.