【专知-PyTorch手把手深度学习教程06】NLP-Word Embedding快速理解与PyTorch实现: 图文+代码

【导读】主题链路知识是我们专知的核心功能之一,为用户提供AI领域系统性的知识学习服务,一站式学习人工智能的知识,包含人工智能( 机器学习、自然语言处理、计算机视觉等)、大数据、编程语言、系统架构。使用请访问专知 进行主题搜索查看 - 桌面电脑访问www.zhuanzhi.ai, 手机端访问www.zhuanzhi.ai 或关注微信公众号后台回复" 专知"进入专知,搜索主题查看。值国庆佳节,专知特别推出独家特刊-来自中科院自动化所专知小组博士生huaiwen和Kun创作的-PyTorch教程学习系列, 今日带来第五篇-< NLP系列(一) 用Pytorch 实现 Word Embedding >

  1. < 一文带你入门优雅的Pytorch >
  2. < 快速理解系列(一): 图文+代码, 让你快速理解CNN>
  3. < 快速理解系列(二): 图文+代码, 让你快速理解LSTM>
  4. < 快速理解系列(三): 图文+代码, 让你快速理解GAN >
  5. < 快速理解系列(四): 图文+代码, 让你快速理解Dropout >
  6. < NLP系列(一) 用Pytorch 实现 Word Embedding >
  7. < NLP系列(二) 基于字符级RNN的姓名分类 >
  8. < NLP系列(三) 基于字符级RNN的姓名生成 >

Word Embedding: 编码词汇的语义

在一般任务中, 我们总是非常自然的用特征值来表示一个词汇。但是, 到底怎么样表示一个词, 才是最合理的? 存储其ASCII码表示,只会告诉你这个词是什么,并不能表示这个词真正的语义(也许你可以从这个词的词缀中获得该词的词性或其他属性,但也只能获得这些东西)。更进一步的, 我们应该在什么场景下, 将这些词的表示联合起来考虑? 因为我们的神经网络, 常常输入维度是整个词典的大小|V|,输出维度是标签集合的大小(一般远小于|v|). 如何从稀疏的高维空间生成较小的维度空间?

如果我们用one-hot来表示词的话:

我们能得到如图的一个表示: 只有某一维度的值是1, 其他维度都是0, 这个值为1的维度就代表这个词.

你可能马上就会意识到, 这样表示如果词典大了, 会不会向量就太长了? 是的! 但这不是这个表示的最大问题, 这个表示最大的问题是: 它将所有单词视为彼此无关的独立实体。但是, 我们真正想要的表示, 是表示词语的语义, 显然有很多词的语义是相似的, 而不是独立的. 一个好的表示, 应该要把这些相似关系也刻画出来.

现在举一个例子说明为什么要表示词语之间相似:

假设我们正在建立一个语言模型,语料是如下几个句子:

  1. The mathematician ran to the store.
  2. The physicist ran to the store.
  3. The mathematician solved the open problem.

假如有一个句子从没在训练数据中出现过:

  1. The physicist solved the open problem.

其实, 简单的语言模型就能将上面的句子处理的很好, 但是如果我们的语言模型能够使用下面的两个事实, 显然它能做的更好:

  • 我们可以从训练语料里看到mathematician 和 physicist 在句子中的角色是相同的(句子 1,2), 显然他们之间有某种语义关系。
  • 我们能够看到mathematician 曾在语料库的句子中扮演的角色(句子 3)和现在 新出现的句子里的physicist(句子 4) 一样.

这样, 其实我们可以判断, physicist出现在句子 4 的那个位置, 是有一定道理的? 这就是我们想要表示的相似性:语义相似性,而不是简单地这两个词有相似的正交表示。这是一种通过链接我们学过的知识和我们没学过的知识, 来对抗语料稀疏问题的技巧. 当然, 这个例子取决于一个基本的语言学假设:出现在类似语境中的词在语义上是相互关联的。 这被称为分布假说(Distributional semantics)。

获得稠密的词向量表示

怎么才能搞到一个稠密的词向量表示?这个问题等同于怎么有效的编码词汇之间的语义相似度。

最淳朴的想法就是观察得到一些语义属性,例如通过观察句子1,2 我们能够知道mathematician 和 physicist都能 run , 那么就可以给这些词关于“is able to run” 这个语义特征一个高分。我们可以用人工定义出很多这样的特征。

如果把每个语义特征当做一个维度,那么我们可以得到如下向量:

然后我们可以根据下面这个式子来计算这两个向量的余弦相似度:

这样相似度被归一化了, 范围为从[-1,1], 越大越相似。

你可以将本节开头的稀疏one-hot向量看做我们刚定义的向量的一个特例,在这个特例中,每个单词之间相似度为0,我们给每个单词一个唯一的语义特征。显然, 刚定义的这些新向量是稠密的,也就是说它们的实体(通常)非零。

显然一个好的表示, 不应该是先人为设计出多个语义属性, 然后在计算出来的, 它应该是被学出来的. 或者说, 是被Embedding出来的, 人不可能完美定义各种语义属性. 尽管人为定义出来的语义属性, 具有天然的可解释性can run, likes coffee, 而学出来的, 大家并不知道它的每一维度表示的是啥.

总而言之, word embedding 可以有效的表示跟你的任务相关的语义信息, 而且可以轻松的embedding进去各种其他信息, 比如词性, 句法树之类的语言学特征.

Word Embeddings in Pytorch

显然, 一个Word Embeddins 矩阵, 应该是|V| x D的, 每一行表示一个词, 每一列是词的某一位词向量表示.

我们首先要把词搞成索引:构建一个word_to_ix的字典, 输入是一个词, 输出是这个词的索引.

然后使用Embedding模块: torch.nn.Embedding,它有两个参数:词典大小和Embedding向量维度。

我们用一个词作为输入, 去预测这个词的上下文(content)来学习Word Embedding.

# 上下文宽度
CONTEXT_SIZE = 2
# embedding 维度
EMBEDDING_DIM = 10
# 训练语料
test_sentence = """When forty winters shall besiege thy brow,
And dig deep trenches in thy beauty's field,
Thy youth's proud livery so gazed on now,
Will be a totter'd weed of small worth held:
Then being asked, where all thy beauty lies,
Where all the treasure of thy lusty days;
To say, within thine own deep sunken eyes,
Were an all-eating shame, and thriftless praise.
How much more praise deserv'd thy beauty's use,
If thou couldst answer 'This fair child of mine
Shall sum my count, and make my old excuse,'
Proving his beauty by succession thine!
This were to be new made when thou art old,
And see thy blood warm when thou feel'st it cold.""".split()


# 我们把训练语料拆成三元组, 如:
# [(['When', 'forty'], 'winters'), (['forty', 'winters'], 'shall'), (['winters', 'shall'], 'besiege')]

trigrams = [ ([test_sentence[i], test_sentence[i+1]], test_sentence[i+2]) for i in xrange(len(test_sentence) - 2) ]

# 构建词语索引字典,
# 比如:word_to_ix = { "hello": 0, "world": 1 }

vocab = set(test_sentence)
word_to_ix = { word: i for i, word in enumerate(vocab) }

# 集成nn.Module 实现Embedding过程
class NGramLanguageModeler(nn.Module):
    
    def __init__(self, vocab_size, embedding_dim, context_size):
        super(NGramLanguageModeler, self).__init__()
        # 定义Embedding层
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        # 定义线性隐层
        self.linear1 = nn.Linear(context_size * embedding_dim, 128)
        # 输出层
        self.linear2 = nn.Linear(128, vocab_size)
        
    # 编写前向过程
    def forward(self, inputs):
        embeds = self.embeddings(inputs).view((1, -1))
        out = F.relu(self.linear1(embeds))
        out = self.linear2(out)
        log_probs = F.log_softmax(out)
        return log_probs

# 选择损失函数, 优化方法, 实例化网络
losses = []
loss_function = nn.NLLLoss()
model = NGramLanguageModeler(len(vocab), EMBEDDING_DIM, CONTEXT_SIZE)
optimizer = optim.SGD(model.parameters(), lr=0.001)

# 对于每一个epoch
for epoch in xrange(10):
    total_loss = torch.Tensor([0])
    for context, target in trigrams:
    
        # 准备数据, 打包成Variable
        context_idxs = map(lambda w: word_to_ix[w], context)
        context_var = autograd.Variable( torch.LongTensor(context_idxs) )
    
        # 清空梯度缓存
        model.zero_grad()
    
        # 计算前向过程
        log_probs = model(context_var)
    
        #  计算损失
        loss = loss_function(log_probs, autograd.Variable(torch.LongTensor([word_to_ix[target]])))
    
        #  反向传播, 优化一步
        loss.backward()
        optimizer.step()
    
        total_loss += loss.data
    losses.append(total_loss)

# 打印一下损失
print losses 

############################
[
 518.8207
[torch.FloatTensor of size 1]
, 
 516.3852
[torch.FloatTensor of size 1]
, 
 513.9670
[torch.FloatTensor of size 1]
, 
 511.5646
[torch.FloatTensor of size 1]
, 
 509.1782
[torch.FloatTensor of size 1]
, 
 506.8095
[torch.FloatTensor of size 1]
, 
 504.4555
[torch.FloatTensor of size 1]
, 
 502.1131
[torch.FloatTensor of size 1]
, 
 499.7835
[torch.FloatTensor of size 1]
, 
 497.4669
[torch.FloatTensor of size 1]
]

明天继续推出:专知PyTorch深度学习教程系列-< NLP系列(二) 基于字符级RNN的姓名分类 >,敬请关注。

原文发布于微信公众号 - 专知(Quan_Zhuanzhi)

原文发表时间:2017-10-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏深度学习自然语言处理

【论文笔记】中文词向量论文综述(二)

一、Improve Chinese Word Embeddings by Exploiting Internal Structure

1143
来自专栏ATYUN订阅号

机器学习中的问题解决方案:解析解vs数值解

这篇文章会让你了解为什么没人能告诉你要使用什么算法,或如何为特定的数据集配置算法。另外,找到好的数据、算法、配置实际上是应用机器学习的难点,也是你需要集中解决的...

1365
来自专栏PPV课数据科学社区

【学习】R语言与机器学习(分类算法)logistic回归

由于我们在前面已经讨论过了神经网络的分类问题,如今再从最优化的角度来讨论logistic回归就显得有些不合适了。Logistic回归问题的最优化问题可以表述为:...

2884
来自专栏杨熹的专栏

用 TensorFlow 做个聊天机器人

上一次提到了不错的学习聊天机器人的资源,不知道小伙伴们有没有去学习呢。 自己动手做聊天机器人教程 我最近每天都会学一点,拿出解读来和大家分享一下。 本文结构...

3696
来自专栏小小挖掘机

推荐系统遇上深度学习(四)--多值离散特征的embedding解决方案

在本系列第三篇文章中,在处理DeepFM数据时,由于每一个离散特征只有一个取值,因此我们在处理的过程中,将原始数据处理成了两个文件,一个记录特征的索引,一个记录...

2775
来自专栏机器之心

LSTM入门必读:从基础知识到工作方式详解

选自echen 机器之心编译 参与:机器之心编辑部 长短期记忆(LSTM)是一种非常重要的神经网络技术,其在语音识别和自然语言处理等许多领域都得到了广泛的应用。...

3518
来自专栏大数据挖掘DT机器学习

用TensorFlow实现文本分析模型,做个聊天机器人

不错的学习聊天机器人的资源,不知道小伙伴们有没有去学习呢。 自己动手做聊天机器人教程 http://www.shareditor.com/blogshow...

4655
来自专栏AI2ML人工智能to机器学习

一步一步走向锥规划 - LP

一般来说凸优化(Convex Optimization, CO)中最一般的是锥规划 (Cone Programming, CP) 问题, 前面我们介绍了最简单...

1022
来自专栏专知

【干货】理解特征工程Part 1——连续数值数据(附代码)

7181
来自专栏AI研习社

博客 | Word2Vec 学习心得

好嘛博主食言了。不过本文没什么干货,主要是前后看了大概一个星期,反复去读源码和解读文章,终于感觉这东西不那么云山雾罩了。同时也发现网上很多材料有点扯淡,99% ...

1312

扫码关注云+社区

领取腾讯云代金券