停止脱离上下文使用单词云
单词云不显示单词之间的关系,失去了上下文。文本网络可视化解决了这个问题。
Obama’s 2013 inauguration address word cloud generated with Wordle
你在上面看到的是巴拉克·奥巴马 2013 年就职演说的文字云。我不知道单词 clouds 是否应该提供信息,希望不是,因为你从上面的单词 mess 中唯一能辨别的是关于“美国”、“人民”、“时间”和“国家”的东西。也许还有“公民”和“一代”。哦,他提到了一些关于“自由”的事情。相当明显,几乎没有任何信息。
如果文字云只是一个摆设,这就不是问题了。只不过它们经常被用作交流工具,帮助表达想法、提供观点、说服甚至推动议程。这使得它们非常危险,因为它们无处不在且易于使用。
单词云的主要问题是它们没有上下文。当失去了背景和细微差别,一切都变得面目全非。知识变得容易产生偏见和错误的解释,这在假新闻和后真相时代产生了更严重的后果。
词云显示没有关系。我们只是简单地看到最常见的较大的单词和一些颜色,它们主要是出于美观的原因。我们看不到任何模式,语言是由模式组成的。因此,文字云,至少以其目前的形式,应该被禁止出现在任何严肃的语境中,留给装饰艺术和儿童游戏的领域,因为它们毕竟只是娱乐。
为什么词云无法修复
Abstract visualization of Obama’s inauguration address made with InfraNodus
如果文字云如此糟糕,我们能对如此不完美呈现的现实做些什么?
答案就在“文本”这个词本身。它的起源是拉丁语文本或*‘编织’*,所以当我们写作时,我们是在编织线,把单词放在一起产生一个意思。如果我们想要形象化这个意思,我们不能仅仅放下单词之间的关系,它们必须被考虑进去。
一个可能的解决方案是在生成词云时考虑二元模型和 n 元模型。这个网上有一些例子,主要涉及 R 和 Python。然而,这些是复杂的,上下文的问题仍然没有解决,因为使用 ngrams,你必须优先考虑某些单词的组合,所以最终信息会丢失。
Making your own word cloud with n-grams in Python. Source: https://avidml.wordpress.com/
即使你设法得到有趣的结果,单词云表示本身也会把一切搞得一团糟,因为你必须根据上下文把这些短语一个接一个地排列起来,而没有一个框架能让你做到这一点。
Bigrams of words. Source: https://avidml.wordpress.com/
因此,让我们暂时忘记单词云、二元模型和 n-grams,再次思考它们之间的关系。
我们需要一种表示,让我们看到文本中最重要的术语,识别主要的主题簇,并显示它们之间的关系。
文本网络分析让我们可以做到这一点。
文本网络分析:带上下文的词云
Barack Obama’s 2013 inauguration speech represented as a text network graph with InfraNodus.Com. The bigger nodes are the words with a higher betweenness centrality, the colors indicate the topical clusters. The proximity of the words means the frequency of their co-occurrence.
文本网络分析是将每一个词表示为一个节点,将每一个词的共现表示为它们之间的一种关系的方法。(单词不一定要彼此相邻,它们也可以很近,并且可以用连接的权重来编码接近度)。然后创建单词节点和边的图。
文本网络图的好处是它们可以用定性和定量的方式进行分析。这意味着它们既可以被人类使用,也可以被机器使用。
使用该图,我们可以应用社区检测算法来识别主题聚类,而 Force-Atlas 布局算法可以被应用来在视觉上对齐彼此相邻的共现单词节点。节点的大小可以根据它们的频率(与它们的程度相关)进行调整。一个更有趣的衡量标准是中间中心性,它表明单词在不同上下文之间出现的频率:意思的中心连接。
例如,我们可以从下面的文本网络中辨别出“民族”一词是与“人民”、“使”、“自由”、“风险”等词连用的。利用这一概念宣传让人们自由冒险的国家理念:
Selecting a node on the text network graph shows the other words it’s connected to
我们还可以检测单词共现的模式(基于社区检测算法,它们具有相同的颜色,并且基于 Force Atlas 布局,它们彼此更接近):
Nodes that are closer to each other and have the same color indicate topical clusters of co-occurring words.
最后,如果我们单击节点,我们还可以看到这个单词组合最常出现的实际文本。这对于标签云来说是不可能的,或者至少没有实现可以很容易地看到单词出现的上下文。
Clicking the words on the graph shows us the context where they appear in the text.
你自己判断吧,但我认为文本网络作为交流工具比标准的文字云更强大、更精确,最终也更有用。
每个单词节点的背景网络数据使得可以应用来自图论的各种方法来执行进一步的分析,并通过 API 将它传递给其他算法,这些算法可以更进一步。
现在,我要公开一件事。我对文字和网络着迷已经很多年了。这是我创建一个开源工具 InfraNodus 的部分原因,该工具用于为本文创建文本网络可视化。我喜欢在一幅图像中表现文本的复杂性,融合叙述展开所需的时间,展示文本编织的美,但又不失去上下文。此外,我们的大脑是网络,意义是相关的,所以使用这个比喻才有意义。
与此同时,通过我在 InfraNodus 工作时的经验和用户反馈,我了解到对于不习惯网络可视化的人来说,这可能很难理解(尽管这种情况正在迅速改变)。因此,将文字云的简单性与网络的力量结合起来可能会很有趣。这就是为什么 InfraNodus 即将发布的版本将提供一个词云应用程序,以便用户可以基于文本网络数据生成可嵌入的交互式词云,根据图形测量对词进行排序,并根据社区检测算法使它们更加接近。
如果你想探索文本网络,我鼓励你尝试一下开源工具【InfraNodus.Com】,我用它来做上面的可视化。
如果你对编码感兴趣,你也可以从GitHub(你需要节点。Js、Java 和 Neo4J)甚至是 Python 版本(正在开发中)。非常感谢您的反馈和代码贡献!
你也可以在【https://infranodus.com/politics/obamanew2013】上使用上面奥巴马演讲的互动图
带权重的单词嵌入之间的单词距离
大规模杀伤性武器和半大规模杀伤性武器的区别
Photo by Edward Ma on Unsplash
在前面的故事中,我介绍了单词移动器的距离(WMD) ,它测量单词嵌入之间的距离。你可能会注意到单词之间没有加权机制。加权对 NLP 任务有什么帮助?为此,黄等人提出了一种改进方法,命名为监督字移动器距离(S-WMD)。
引入监督字移动器的距离(S-WMD)
在介绍单词嵌入之前,词袋(BoW) ,潜在语义索引(LSI)和潜在语义分析(LSA) 是衡量 NLP 任务最有前途的技能。
字动子的距离(WMD)2015 年推出。它利用了 word emveddings (word2vec 于 2013 年推出)。它使用另一种方法,即推土机距离来测量向量之间的差异。一年后,黄等人提出了一种改进方法,称为监督字移动距离(S-WMD)。
The difference t-SNE plots of WMD and S-WMD (Huang et al., 2016)
简而言之,WMD 算法测量将两个文档中的一个单词向量传输到另一个向量的最小值。如果两个文档共享大量的单词,那么在两个文档之间传输只需要很小的移动。换句话说,这两个文档可以归类为相似文档。
加权机制
权重机制对 NLP 任务有什么帮助?通过引入权重,有助于解决文档分类问题。
直观上,预训练的单词向量应该非常好,因为它是在大量数据上训练的。然而,有一个已知的问题是,预先训练的向量可能不会很好地应用于某些问题。例如,预先训练的向量可以将所有可吃的食物放在一起,并将蔬菜和肉类混合在一起。如果分类问题是要分类它是不是织女星呢?
另一方面,两个文档共享大量的单词并不意味着它们都描述相同的主题。例如,“我去学校教学生”和“我去学校学英语”。可以是谈论学校的生活,也可以是在不同的团体中谈论学校的任务。换句话说,它确实依赖于 NLP 任务。它可能相关也可能不相关。
kNN test error (Huang et al., 2016)
关于我
我是湾区的数据科学家。专注于数据科学、人工智能,尤其是 NLP 和平台相关领域的最新发展。你可以通过媒体博客、 LinkedIn 或 Github 联系我。
参考
黄高、郭川、库斯纳·马特 j、孙瑜、温伯格·基连 q、沙飞。2016.https://papers . nips . cc/paper/6139-supervised-word-movers-distance . pdf
Matlab 中的 S-WMD(原文)
单词嵌入(第二部分)
直觉和(一些)数学来理解端到端手套模型
The power of GloVe
NLP(自然语言处理)的原始问题是将单词/句子编码成计算机处理可理解的格式。向量空间中单词的表示允许 NLP 模型学习单词含义。在我们的上一篇文章中,我们看到了的跳格模型,该模型根据单词在当地的上下文来捕捉单词的意思。让我们记住,我们所说的上下文是指围绕目标单词的大小为 n 的固定单词窗口。
在这篇文章中,我们将研究手套模型(全局向量),它被创建来查看单词的局部上下文和全局统计数据以嵌入它们。 GloVe 模型背后的主要思想是关注文本语料库中单词的共现概率(下面的等式 0)以将它们嵌入到有意义的向量中。换句话说,我们要看看在我们所有的文本语料库中,单词 j 在单词 i 的上下文中出现的频率。
为此,假设 X 是我们的单词-单词共现矩阵(共现矩阵示例)并且 X_ij 是单词 j 在单词 i 的上下文中出现的次数。
Equation 0: The co-occurence probability of a word j to occur given a word i is the the ratio of the number of times word j occurs in the context of word i and the number of times any word appears in the context of word i.
GloVe 会查看那些同现概率之间的比率来提取单词的内在含义。更具体地说,我们将关注图 1 中表格的最后一行。
Figure 1: The 2 first rows of the table show the probabilities of the words solid, gas, water and fashion to occur in the context of the words ice and steam. The last row shows the probabilities ratio which is the key learning under the hood of the GloVe model.
对于与"*冰"*相关但不与"蒸汽"像"*固体"*相关的词,比例会高。相反,对于与"蒸汽相关但不与"冰"相关的单词,该比率将较低,而对于与两者都相关或都不相关的单词,如"水"和"时尚",该比率将接近 1。
乍一看,同现概率比收集了比原始概率更多的信息,并且更好地捕捉了“*冰”*和“*蒸汽”之间的关系。的确,只看原始概率,单词"水"最好地代表了"*冰"*和"*蒸汽"的意思,我们将无法区分这两个单词的内在含义。
既然我们已经理解了共现概率比捕获了关于单词关系的相关信息,那么 GloVe 模型旨在构建一个函数 F ,该函数将在给定两个单词向量 w_i 和 w_j 以及一个上下文单词向量 w_k 作为输入的情况下预测这些比率。
Equation 1: The GloVe model will learn meaningful word vectors representations w_i, w_j and w_k to feed F and correctly predict the probabilities ratios.
希望对 GloVe 有一个高层次的概述的读者可能想要跳过下面的等式(从等式 2 到等式 6 ),这些等式更深入地理解了 GloVe 模型如何构造这个 F 函数来学习单词向量表示。
让我们看看这个 F 函数是如何构建的,一步一步地去捕捉最终公式背后的逻辑,这个公式乍一看相当复杂(方程式 6)。
要比较向量 w_i 和 w_j 这两个向量是线性结构,最直观的方法就是通过相减,就这么做吧。
Equation 2: Comparing two vectors by making the difference.
我们有两个向量作为 F 的输入,一个标量在等式的右边,从数学上讲,如果我们保持这种方式,它会增加我们想要构建的线性结构的复杂性。将标量值与标量值关联起来更容易,这样我们就不必玩向量维数了。因此手套模型使用两个输入向量的点积。
Equation 3: Scalar values to scalar values thanks to the dot product.
一直以来,我们将单词向量与上下文单词向量分开。但是,这种分离只是一个角度的问题。的确,如果说“水”是“汽”的语境词,那么“汽”就可以是“水”的语境词。在构建***【F***时,必须考虑到 X 矩阵(我们的共生矩阵)的对称性,我们必须能够切换 w_i 和 w_k 。首先我们需要 F 是一个同态 (F(a+b)=F(a)F(b))。
Equation 4: Using the homomorphism property of F to associate word vectors dot product (which can be interpreted as similarities between words) to the probability they occur in a same context.
exp 函数是方程 4 的解,exp(a-b)=exp(a)/exp(b),我们就用它吧。
Equation 5: Almost symmetric if there was not b_i term.
为了恢复对称性,为矢量 w_k 增加一个偏置 b_k 。
Equation 6: We can express our word vectors given corpus statistics and symmetry is respected (we can switch w_i and w_k).
由于我们的 F 函数,我们现在能够使用我们的词向量表示来定义成本/目标函数(等式 7)。在训练期间手套将学习正确的字向量 w_i 和 w_j 以最小化这个加权最小平方问题。事实上,必须使用权重函数 f(X_ij) 来限制非常常见的同现(如“this is”)的重要性,并防止罕见的同现(如“下雪的撒哈拉”)具有与平常相同的重要性。
Equation 7: Final GloVe Equation
总之,手套模型为我们要求他执行的单词类比任务使用了一个有意义的知识来源:同现概率比**。然后,它构建一个目标函数 J 将单词向量关联到文本统计。最后,手套最小化这个 J 功能通过学习有意义的单词向量来表示。**
瞧啊!
参考资料和其他有用资源: - 原始手套论文
Python 中使用 BERT 的单词嵌入
使用深度学习 NLP 模型(BERT)将单词嵌入向量,只需几行 Python 代码
单词嵌入:它们是什么?
在 NLP 的世界中,以向量形式或单词嵌入来表示单词或句子打开了各种潜在应用的大门。这种将单词编码成向量的功能是 NLP 任务的强大工具,例如计算单词之间的语义相似度,利用它可以构建语义搜索引擎。例如,这里有一个单词嵌入的应用程序,通过它 Google 可以更好地理解使用 BERT 的搜索查询。可以说,它是最强大的语言模型之一,在机器学习社区中变得非常流行。
使用大的句子语料库对 BERT(来自变压器的双向编码器表示)模型进行预训练。简而言之,训练是通过屏蔽句子中的几个单词(根据论文作者的说法,大约 15%的单词)并让模型预测被屏蔽的单词来完成的。随着模型训练预测,它学习产生单词的强大内部表示,如单词嵌入。今天,我们将看到如何轻松地建立和运行 BERT 模型,并将单词编码到单词嵌入中。
BERT 单词嵌入模型设置
使用 Pytorch 和 Tensorflow 运行 BERT 模型有一套可用的选项。但是,为了让您非常容易地接触到 BERT 模型,我们将使用 Python 库来帮助我们快速设置它!
B ert-as-a-service 是一个 Python 库,它使我们能够在本地机器上部署预先训练好的 BERT 模型并运行推理。它可以用于服务于任何已发布的模型类型,甚至是针对特定下游任务进行微调的模型。此外,它需要后端的 Tensorflow 来处理预训练的模型。因此,我们将继续在控制台中安装 Tensorflow 1.15。
pip3 install tensorflow-gpu==1.15
接下来,我们将安装 bert 即服务客户端和服务器。同样,这个库不支持 Python 2。因此,请确保您拥有 Python 3.5 或更高版本。
pip3 install -U bert-serving-server bert-serving-client
BERT 服务器将模型部署在本地机器上,客户端可以订阅它。此外,用户可以在同一台机器上安装这两个服务器,或者在一台机器上部署服务器,然后从另一台机器上进行订阅。安装完成后,下载您选择的 BERT 模型。你可以在这里找到所有车型的列表。
部署模型
现在初始设置已经完成,让我们用下面的命令启动模型服务。
bert-serving-start -model_dir /path_to_the_model/ -num_worker=1
例如,如果模型的名称是 uncased_L-24_H-1024_A-16,并且它位于“/model”目录中,则该命令如下所示
bert-serving-start -model_dir /model/uncased_L-24_H-1024_A-16/ -num_worker=1
“num_workers”参数用于初始化服务器可以处理的并发请求的数量。然而,只需使用 num_workers=1,因为我们只是在用单个客户端来处理我们的模型。如果您正在部署多个客户端进行订阅,请相应地选择“num_workers”参数。
通过 BERT 客户端订阅
我们可以运行一个 Python 脚本,从中使用 BERT 服务将我们的单词编码成单词嵌入。鉴于此,我们只需导入 BERT-client 库并创建一个 client 类的实例。一旦我们这样做了,我们就可以输入我们想要编码的单词或句子的列表。
from bert_serving.client import BertClient()client = BertClient()vectors = client.encode([“dog”],[“cat”],[“man”])
我们应该将想要编码的单词输入 Python 列表。上面,我输入了三个列表,每个列表都有一个单词。因此,“vectors”对象的形状为(3,embedding_size)。通常,嵌入大小是 BERT 模型编码的单词向量的长度。事实上,它将任意长度的单词编码成一个恒定长度的向量。但是这可能在不同的 BERT 模型之间有所不同。
计算单词之间的相似度
好的,目前为止一切顺利!如何处理只有一些数字的向量?它们不仅仅是数字。我前面说过,这些向量代表了单词在 1024 维超空间中的编码位置(这个模型的 1024 uncased _ L-24 _ H-1024 _ A-16)。此外,用某种相似度函数来比较不同单词的向量,将有助于确定它们的相关程度。
余弦相似性就是这样一个函数,它给出 0.0 到 1.0 之间的相似性得分。假设 1.0 表示单词意思相同(100%匹配),0 表示它们完全不同。下面是单词嵌入之间余弦相似性的 scikit-learn 实现。
**from** sklearn.metrics.pairwise **import** cosine_similaritycos_lib = cosine_similarity(vectors[1,:],vectors[2,:]) #similarity between #cat and dog
伯特完成单词嵌入!
你也可以输入一个完整的句子而不是单个单词,服务器会处理好的。有多种方式可以将单词嵌入组合起来,以形成像连接这样的句子嵌入。
自然语言处理中的单词嵌入
理解单词嵌入及其在深层自然语言处理中的应用
在本文中,我们将了解如何处理文本,以便在机器学习算法中使用。什么是嵌入,为什么它们被用于文本处理?
word2vec and GloVe word embeddings
自然语言处理(NLP)是指旨在理解人类语言的计算机系统。人类语言,如英语或印地语,由单词和句子组成,NLP 试图从这些句子中提取信息。
NLP 用于的一些任务
- 文本摘要:提取或抽象的文本摘要
- 情感分析
- 从一种语言到另一种语言的翻译:神经机器翻译
- 聊天机器人
机器学习和深度学习算法只接受数字输入,那么我们如何将文本转换成数字呢?
单词袋(蝴蝶结)
单词包是一种简单而流行的文本特征提取技术。单词包模型处理文本,找出每个单词在句子中出现的次数。这也称为矢量化。
创建弓的步骤
- 将文本标记成句子
- 把句子符号化成单词
- 删除标点符号或停用字词
- 将单词转换为较低的文本
- 创建单词的频率分布
在下面的代码中,我们使用 CountVectorizer、 it 标记一组文本文档,构建一个已知单词的词汇表,并使用该词汇表对新文档进行编码。
#Creating frequency distribution of words using nltk
**from nltk.tokenize import sent_tokenize
from nltk.tokenize import word_tokenize
from sklearn.feature_extraction.text import CountVectorizer****text="""Achievers are not afraid of Challenges, rather they relish them, thrive in them, use them. Challenges makes is stronger.
Challenges makes us uncomfortable. If you get comfortable with uncomfort then you will grow. Challenge the challenge """**#Tokenize the sentences from the text corpus
**tokenized_text=sent_tokenize(text)**#using CountVectorizer and removing stopwords in english language
**cv1= CountVectorizer(lowercase=True,stop_words='english')**#fitting the tonized senetnecs to the countvectorizer
**text_counts=cv1.fit_transform(tokenized_text)**# printing the vocabulary and the frequency distribution pf vocabulary in tokinzed sentences
print(cv1.vocabulary_)
print(text_counts.toarray())
在文本分类问题中,我们有一组文本和它们各自的标签。我们使用单词袋模型来从文本中提取特征,并且我们通过将文本转换成文档中单词出现的矩阵来实现这一点。
包话有什么问题?
在单词袋模型中,每个文档被表示为一个单词计数向量。这些计数可以是二进制计数,一个单词可能出现在文本中,也可能不出现,或者将具有绝对计数。向量的大小等于词汇表中元素的数量。如果大多数元素都是零,那么单词包将是一个稀疏矩阵。
在深度学习中,我们将拥有稀疏矩阵,因为我们将处理大量的训练数据。由于计算和信息的原因,稀疏表示更难建模。
**巨大数量的权重:**巨大的输入向量意味着神经网络的巨大数量的权重。
**计算量大:**权重越大,训练和预测所需的计算量越大。
缺乏有意义的关系,不考虑词序: BOW 是在文本或句子中出现的具有字数统计的词的集合。单词包不考虑它们出现的顺序。
单词嵌入是解决这些问题的方法
嵌入将大的稀疏向量转换到保持语义关系的低维空间。
单词嵌入是一种技术,其中领域或语言的单个单词被表示为低维空间中的实值向量。
通过将高维数据映射到一个更低维的空间来解决带有 BOW 的稀疏矩阵问题。
通过将语义相似项的向量彼此靠近放置,解决了 BOW 缺乏有意义的关系的问题。这样,具有相似意思的单词在向量空间中具有相似的距离,如下所示。
“国王对王后就像男人对女人一样”编码在向量空间中,动词时态和国家及其首都编码在低维空间中,保持语义关系。
语义相似的物品是如何靠近放置的?
让我们用推荐引擎中使用的协同过滤来解释这一点。
推荐引擎基于具有相似兴趣的其他用户的历史购买来预测用户将购买什么。使用协同过滤
亚马逊和网飞使用推荐引擎向用户推荐产品或电影
协同过滤是将多个顾客购买的所有相似产品嵌入到一个低维空间的方法。这个低维空间将包含彼此接近的相似产品,因此,它也被称为最近邻算法。
这种最近邻技术用于将语义相似的项目彼此靠近放置
我们如何将高维数据映射到一个更低维的空间?
使用标准降维技术
像主成分分析(PCA)这样的标准降维技术可以用来创建单词嵌入。PCA 试图找到高度相关的维度,这些维度可以使用 BOW 折叠成一个维度。
Word2Vec
Word2vec 是 Google 发明的用于训练单词嵌入的算法。word2vec 依赖于分布假设。分布假设指出,经常具有相同相邻单词的单词倾向于语义相似。这有助于将语义相似的单词映射到几何上接近的嵌入向量。
分布假设使用连续词袋(CBOW)或跳过克。
**word2vec 模型是具有输入层、投影层和输出层的浅层神经网络。它被训练来重建单词的语言环境。**word 2 vec 神经网络的输入层采用更大的文本语料库来生成向量空间,通常有数百个维度。文本语料库中的每个唯一单词被分配给空间中的相应向量。
这种架构被称为连续单词包 CBOW,因为它使用上下文的连续分布式表示。它既考虑了历史上的语序,也考虑了未来的语序。
这有助于语料库中的常见上下文单词向量在向量空间中彼此靠近。
Source: Efficient Estimation of Word Representations in Vector Space by Mikolov-2013
跳过克
Skip gram 不基于上下文预测当前单词,而是使用每个当前单词作为具有连续投影层的对数线性分类器的输入,并预测当前单词前后一定范围内的单词。
GloVe:单词表示的全局向量
手套是由潘宁顿等人在斯坦福开发的。它被称为全局向量,因为全局语料库统计数据是由模型直接捕获的。
它利用了这两者
- 用于生成低维单词表示的全局矩阵分解方法,如潜在语义分析(LSA)
- 局部上下文窗口方法,例如 Mikolov 等人的 skip-gram 模型
LSA 有效地利用了统计信息,但在单词类比方面做得不好,因此表明了次优的向量空间结构。
像 skip-gram 这样的方法在类比任务上表现得更好,但是很少利用语料库的统计数据,因为它们没有在全局共现计数上进行训练。GloVe 使用特定的加权最小二乘模型来训练全局单词共现计数,以有效地利用统计数据。
考虑热力学领域中的两个词I =冰,j =蒸汽 。这些词的关系可以通过研究它们与各种 探测词 k 共现概率的比值来考察。
ratio of co-occurrence probabilities
探查像 水或者时尚 这种或者与 冰与蒸汽 都有关系,或者都没有关系的词,比例应该接近 1。探测词像 固体 与 冰 但不与 汽 有较大的比值
Source: GloVe: Global Vectors for Word Representation — Jeffrey Pennington
与原始概率相比,该比率能够更好地区分相关的词(固体和气体)和不相关的词(水和时尚),并且还能够更好地区分两个相关的词。
Source: https://nlp.stanford.edu/projects/glove/
区分男人和女人的是性别,类似于词对,比如国王和王后或者兄弟和姐妹。从数学上来说,我们可能期望矢量差男人 : 女人,国王 : 王后,以及兄弟:姐妹可能都大致相等。这个特性和其他有趣的模式可以在上面一组使用 GloVe 的可视化中观察到。
结论:
单词嵌入被认为是目前无监督学习的成功应用之一。它们不需要任何带注释的语料库。嵌入使用低维空间,同时保留语义关系。
参考资料:
【https://nlp.stanford.edu/projects/glove/
向量空间中单词表示的有效估计—托马斯·米科洛夫、程凯、格雷格·科拉多、杰弗里·迪恩
估计时间:10 分钟分类数据指的是代表一个或多个离散项的输入特征…
developers.google.com](https://developers.google.com/machine-learning/crash-course/embeddings/categorical-input-data) [## Word2vec
Word2vec 是一组用于产生单词嵌入的相关模型。这些模型很浅,有两层…
en.wikipedia.org](https://en.wikipedia.org/wiki/Word2vec)
https://blog . aylien . com/overview-word-embeddings-history-word 2 vec-cbow-glove/
单词嵌入(第一部分)
直觉和(一些)数学来理解端到端跳格模型
Photo by Susan Yin on Unsplash
自然语言处理的最初问题是将一个单词/句子编码成计算机可理解的格式。向量空间中单词的表示允许 NLP 模型学习。如图 1 所示,将单词表示成向量的第一种简单表示法是一热编码法。
Fig 1: One-hot-vectors of each words from the sentence “The quick brown fox runs away.”
这种实现缺乏像单词的上下文(T2)这样的信息,我们所说的上下文是指给定单词与哪些其他单词相关。事实上,“布朗”和“福克斯”是正交的,因此给定我们的一次性编码是不相关的。最重要的是,one-hot-vector 的大小与词汇表一样,可以达到数千个单词,这使得它不切实际。
对这些限制的第一个解决方案将是:
1)考虑给定其上下文
的单词的含义 2)将它的表示维度减少到更实际的大小
Skip-gram 模型是最流行的单词嵌入模型之一,它旨在根据给定的上下文对单词进行编码。
“从一个人和什么样的人交往,你就可以知道他是什么样的人”(弗斯,J. R. 1957)
引用 20 世纪语言学家弗斯的话,很好地说明了我们的担忧。通过“它保持的公司”或上下文,我们指的是在固定大小的窗口中出现在中心单词附近的单词。
Fig 2: Context words of “brown” within a one window size (one the right and one on the left).
这个想法是,出现在相似上下文中的单词将具有相同的单词表示。为了实现这个目标, Skip-gram 将作为给定中心单词的固定大小 m 的窗口内的上下文单词的预测器。因此,对于大小为 T 的词汇表,跳格模型将希望最大化以下预测准确性或可能性:
为了便于计算,并且因为在机器学习中我们更喜欢最小化函数而不是最大化它们,我们现在将考虑平均负对数似然性并将其最小化:
为了计算 P(w_{i+j} | w_{i}),我们将使用两个向量:
-当 w 是上下文词时 u _ { w }
-当 w 是中心词时 v_{w}
然后,我们将使用 softmax 函数计算给定中心词 c 的上下文词 o (外部词)的概率:
让我们来解释这个等式,以便更好地理解 Skip-gram 模型背后的直觉。中心单词和上下文单词之间的相似度越高,分子上的点积越高,因此上下文单词被预测为邻近单词的概率越高。
这里,我们强制 Skip-gram 模型学习那些 u_{w}和 v_{w}向量,以便做出正确的预测。
Skip-gram 模型可通过下图进行总结。
Fig 3: End-to-end Skip-gram model training on the sentence “The quick brown fox”. We choose the window dimension m=1 for representation ease.
一旦跳跃式语法模型已经训练了它的预测任务,单词表示在中心单词的单词嵌入矩阵表示中是可用的。
瞧啊!
现在,我们能够用跳格模型嵌入单词。然而,我们必须注意到 Skip-gram 在给定单词的本地上下文的情况下捕捉单词的意思,而没有考虑更全面的学习。例如,假设我们有这样一个句子:“狐狸……”,“the”和“狐狸”可能经常一起出现,但是 Skip-gram 不知道“The”是一个常用词还是一个与“狐狸”特别相关的词。
为了应对这个潜在的问题,已经创建了 Glove 模型来查看单词的本地上下文和全局统计。如果你想更深入地研究单词嵌入方法,这里有一个简短演示来快速理解这个手套模型。
参考资料和其他有用的资源: --原文 Skip-gram 论文
使用编码器-解码器模型的单词级英语到马拉地语神经机器翻译
使用 LSTM 构建序列对序列模型的指南
目录
- 介绍
- 先决条件
- 编码器-解码器架构
- 编码器 LSTM
- 解码器 LSTM —训练模式
- 解码器 LSTM —推理模式
- 代码遍历
- 结果和评价
- 未来的工作
- 结束注释
- 参考
1.介绍
已经发现,在给定大量数据的情况下,递归神经网络(或者更准确地说,LSTM/GRU)在解决复杂的序列相关问题方面非常有效。它们在语音识别、自然语言处理(NLP)问题、时间序列预测等方面有实时应用。这篇 博客 很好地解释了其中的一些应用。
序列对序列(通常缩写为 seq2seq)模型是一类特殊的递归神经网络架构,通常用于(但不限于)解决复杂的语言相关问题,如机器翻译、问答、创建聊天机器人、文本摘要等。
这篇博文的目的是详细解释序列对序列模型是如何构建的,并给出它们如何解决这些复杂任务的直观理解。
我们将把机器翻译的问题(将文本从一种语言翻译成另一种语言,在我们的例子中是从英语翻译成马拉地语)作为本博客中的运行示例。然而,技术细节通常适用于任何序列对序列的问题。
由于我们使用神经网络来执行机器翻译,更常见的是称为神经机器翻译(NMT)。
2.先决条件
这篇文章假设你:
a.了解机器学习和神经网络的基本概念
b.知道高中线性代数和概率
c.有 Python 和 Keras 的 LSTM 网络的工作知识
(解释了 RNNs 如何被用来建立语言模型)和 理解 LSTM 网络 (用坚实的直觉解释了 LSTMs 的工作原理)是两篇精彩的博客,如果你还没有看过,我强烈建议你浏览一下。这些博客中解释的概念在我的文章中被广泛使用。
3.编码器-解码器架构
用于构建 Seq2Seq 模型的最常见架构是编码器解码器架构。这是我们将在这篇文章中使用的。下面是该架构的高级视图。
Source: https://towardsdatascience.com/sequence-to-sequence-model-introduction-and-concepts-44d9b41cd42d
注意事项:
a.编码器和解码器都是典型的 LSTM 模型(或者有时是 GRU 模型)
b.编码器读取输入序列,并在称为内部状态向量的东西中总结信息(在 LSTM 的情况下,这些称为隐藏状态和单元状态向量)。我们丢弃编码器的输出,只保留内部状态。
c.解码器是一个 LSTM,其初始状态被初始化为编码器 LSTM 的最终状态。使用这些初始状态,解码器开始产生输出序列。
d.在训练和推理过程中,解码器的表现稍有不同。在训练过程中,我们使用了一种称为教师强制的技术,这有助于更快地训练解码器。在推理过程中,解码器在每个时间步的输入是前一个时间步的输出。
e.直观地说,编码器将输入序列总结为状态向量(有时也称为思维向量),然后将状态向量馈送给解码器,解码器开始根据思维向量生成输出序列。解码器只是一个以初始状态为条件的语言模型。
现在我们将通过考虑将一个英语句子(输入序列)翻译成其对等的马拉地语句子(输出序列)的例子来详细理解上述所有步骤。
4.编码器 LSTM
本节简要概述了编码器 LSTM 的主要组件。我将保持这种直觉,而不进入数学领域。这就是它们的内容:
LSTM processing an input sequence of length ‘k’
LSTM 一个接一个地读取数据。因此,如果输入是一个长度为“k”的序列,我们说 LSTM 在“k”个时间步中读取它(把这想象成一个具有“k”次迭代的 for 循环)。
参考上图,以下是 LSTM 的 3 个主要组成部分:
a.Xi = >时间步长 I 的输入序列
b.hi 和 ci => LSTM 在每个时间步保持两种状态(“h”代表隐藏状态,“c”代表单元状态)。这些组合在一起,就是 LSTM 在时间步 I 的内部状态
c.Yi = >时间步长 I 的输出序列
重要提示:从技术上来说,所有这些组件(Xi、hi、ci 和 Yi)实际上都是浮点数的向量(解释如下)
让我们试着在我们问题的背景下把所有这些联系起来。回想一下,我们的问题是将一个英语句子翻译成马拉地语的对等物。出于这个博客的目的,我们将考虑下面的例子。比方说,我们有下面这个句子
输入句子(英语)= >“Rahul 是个好孩子”
输出句子(马拉地语)= >“राहुलचांगलामुलगाआहे”
现在只关注输入,即英语句子
对 Xi 的解释:
现在,一个句子可以被看作是单词或字符的序列。例如,在单词的情况下,上面的英语句子可以被认为是 5 个单词的序列(“Rahul”、“is”、“a”、“good”、“boy”)。在字符的情况下,它可以被认为是一个 19 个字符的序列(’ R ‘,’ a ‘,’ h ‘,’ u ‘,’ l ‘,’ ‘,……,’ y ')。
我们将按单词分解句子,因为这种方案在现实应用中更常见。因此得名“单词级 NMT”。因此,参考上图,我们有以下输入:
X1 = ‘拉胡尔’,X2 = ‘是’,X3 = 'a ',X4 = '好,X5 = ‘小子’。
LSTM 将按如下 5 个时间步长逐字读这句话
Encoder LSTM
但我们必须回答的一个问题是,如何将每个 Xi(每个单词)表示为一个向量?
有各种将单词映射(嵌入)到固定长度向量的单词嵌入技术。我假设读者熟悉单词嵌入的概念,不会详细讨论这个主题。但是,我们将使用 Keras API 的内置嵌入层将每个单词映射到一个固定长度的向量。
hi 和 ci 的解释:
下一个问题是内部状态(hi 和 ci)在每个时间步的作用是什么?
简单地说,他们记得 LSTM 到目前为止读过(学过)的东西。例如:
h3,c3 = >这两个向量会记住网络到现在都是读“Rahul 是 a”。基本上是存储在向量 h3 和 c3 中的直到时间步长 3 的信息的汇总(因此称为时间步长 3 的状态)。
类似地,我们因此可以说 h5,c5 将包含整个输入句子的摘要,因为这是句子结束的地方(在时间步骤 5)。这些从最后一个时间步骤出来的状态也被称为“思维向量,因为它们以向量的形式总结了整个序列。
那 h0,c0 呢?这些向量通常被初始化为零,因为模型还没有开始读取输入。
注意:这两个向量的大小等于 LSTM 细胞中使用的单位(神经元)数量。
易解释:
最后,每一个时间点的易呢?这些是 LSTM 模型在每个时间步的输出(预测)。
但是 Yi 是什么类型的向量呢?更具体地,在单词级语言模型的情况下,每个 Yi 实际上是通过使用 softmax 激活生成的整个词汇表上的概率分布。因此,每个 Yi 是代表概率分布的大小为“vocab_size”的向量。
根据问题的背景,它们有时会被使用,有时会被丢弃。
在我们的例子中,除非我们已经阅读了整个英语句子,否则我们没有任何输出。因为一旦我们阅读了整个英语句子,我们将开始生成输出序列(等价的马拉地语句子)。因此,对于我们的问题,我们将丢弃编码器的 Yi。
编码器概述:
我们将逐字读出输入序列(英语句子),并保存在最后一个时间步 hk,ck 之后产生的 LSTM 网络的内部状态(假设该句子有“k”个单词)。这些向量(状态 hk 和 ck)被称为输入序列的编码,因为它们以向量形式编码(汇总)整个输入。由于我们将在读取整个序列后开始生成输出,因此编码器在每个时间步长的输出(Yi)将被丢弃。
此外,你还必须了解什么类型的载体是 Xi,嗨,慈和易。它们的大小(形状)是什么,代表什么。如果你对理解这一部分有任何困惑,那么你需要首先加强你对 LSTM 和语言模型的理解。
5.解码器 LSTM —训练模式
不同于在训练阶段和推理阶段扮演相同角色的编码器 LSTM,解码器 LSTM 在这两个阶段扮演稍微不同的角色。
在本节中,我们将尝试了解如何在训练阶段配置解码器,而在下一节中,我们将了解如何在推理过程中使用它。
回想一下,给定输入句子“Rahul 是个好孩子”,训练过程的目标是训练(教导)解码器输出“राहुल चांगला मुलगा आहे".”正如编码器逐字扫描输入序列一样,解码器也会逐字生成输出序列。
出于一些技术原因(稍后解释),我们将在输出序列中添加两个令牌,如下所示:
输出序列= > “开始 राहुलचांगलामुलगाआहे 结束”
现在考虑下图:
Decoder LSTM — Training Mode
最重要的一点是,解码器的初始状态(h0,c0)被设置为编码器的最终状态。这直观地意味着解码器被训练成根据编码器编码的信息开始生成输出序列。显然,翻译的马拉地语句子必须依赖于给定的英语句子。
在第一个时间步骤中,我们提供 START_ token,以便解码器开始生成下一个 token(马拉地语句子的实际第一个单词)。在马拉地语句子的最后一个单词之后,我们让解码器学习预测 _END 标记。这将在推理过程中用作停止条件,基本上它将表示翻译句子的结束,我们将停止推理循环(稍后将详细介绍)。
我们使用一种被称为“教师强制”的技术,其中每个时间步长的输入被给定为前一个时间步长的实际输出(而不是预测输出)。这有助于更快更有效地训练网络。想了解更多关于老师强迫的事情,参考这个 博客 。
最后,根据每个时间步长的预测输出计算损耗,误差随时间反向传播,以更新网络参数。用足够多的数据在更长的时间内训练网络会产生相当好的预测(翻译),我们将在后面看到。
整个训练过程(编码器+解码器)可以总结在下图中:
Summary of the training process
6.解码器 LSTM —推理模式
现在让我们试着理解推理所需的设置。如前所述,编码器 LSTM 扮演着读取输入序列(英语句子)和生成思维向量(hk,ck)的相同角色。
然而,解码器现在必须预测给定这些思想向量的整个输出序列(马拉地语句子)。
我们举同一个例子,试着直观的理解一下。
input sequence = >“Rahul 是个好孩子”
(预期)输出序列=> “राहुल चांगला मुलगा आहे”
步骤 1 :将输入序列编码成思维向量;
Encode the input sequence into thought vectors
第二步:开始循环产生输出序列,一个字一个字:
在 t = 1 时
Decoder at t=1
在 t = 2 时
Decoder at t = 2
在 t = 3 时
Decoder at t = 3
在 t = 4 时
Decoder at t = 4
在 t = 5 时
Decoder at t = 5
推理算法:
a.在推理过程中,我们一次生成一个单词。因此,解码器 LSTM 在一个循环中被调用,每次只处理一个时间步。
b.解码器的初始状态被设置为编码器的最终状态。
c.解码器的初始输入始终是 START_ token。
d.在每个时间步,我们保留解码器的状态,并将其设置为下一个时间步的初始状态。
e.在每个时间步,预测的输出作为下一个时间步的输入。
f.当解码器预测 END_ token 时,我们中断循环。
整个推理过程可以总结在下图中:
Summary of the inference process
7.代码遍历
当我们实际实现代码时,没有什么比理解代码更重要了,无论我们为理解理论付出了多少努力(然而这并不意味着我们不讨论任何理论,但是我想说的是理论必须总是在实现之后)。
数据集:
从 这里 下载并解压 mar-eng.zip 文件。
在我们开始构建模型之前,我们需要执行一些数据清理和准备工作。在不涉及太多细节的情况下,我将假设读者理解下面的(不言自明的)步骤,这些步骤通常是任何语言处理项目的一部分。
Code to perform Data Cleaning
下面我们计算英语和马拉地语的词汇。我们还计算了两种语言的词汇量和最大序列长度。最后,我们创建了 4 个 Python 字典(每种语言两个),用于将给定的令牌转换成整数索引,反之亦然。
Code for Data Preparation
然后,我们进行 90–10 训练和测试分割,并编写 Python 生成器函数来批量加载数据,如下所示:
Code for loading Batches of Data
然后,我们将培训所需的模型定义如下:
Code to define the Model to be trained
你应该能够从概念上将每一行与我在上面第 4 和第 5 节中提供的解释联系起来。
让我们看看从 Keras 的 plot_model 实用程序生成的模型架构。
Training the network
我们以 128 的批量训练网络 50 个时期。在 P4000 GPU 上,训练时间略多于 2 小时。
推理设置:
Code for setting up Inference
最后,我们通过在一个循环中调用上述设置来生成输出序列,如下所示:
Code to decode the output sequence in a loop
在这一点上,你必须能够在概念上将上面两个模块中的每一行代码与第 6 节中提供的解释联系起来。
8.结果和评价
这篇博文的目的是给出一个直观的解释,说明如何使用 LSTM 构建基本级别的序列到序列模型,而不是开发一个高质量的语言翻译器。所以请记住,由于多种原因,这些结果不是世界级的(而且你不要开始与谷歌翻译进行比较)。最重要的原因是数据集很小,只有 33000 对句子(是的,这些太少了)。如果你想提高翻译质量,我会在博客末尾列出一些建议。然而现在,让我们看看从上面的模型中产生的一些结果(它们也不太坏)。
对训练数据集的评估:
Evaluation on Training Dataset
对测试数据集的评估:
Evaluation on Test Dataset
我们能得出什么结论?
尽管结果不是最好的,但也没那么糟糕。当然比随机产生的序列要好得多。在一些句子中,我们甚至可以注意到预测的单词是不正确的,但是它们在语义上非常接近正确的单词。
此外,需要注意的另一点是,训练集的结果略好于测试集的结果,这表明该模型可能有点过度拟合。
9.未来的工作
如果你有兴趣提高质量,你可以尝试以下措施:
a.获取更多数据。高质量的翻译接受了数百万对句子的训练。
b.建立更复杂的模型,比如注意力。
c.使用剔除和其他形式的正则化技术来减轻过度拟合。
d.执行超参数调整。玩学率,批量,辍学率等。尝试使用双向编码器 LSTM。尝试使用多层 LSTMs。
e.尝试使用波束搜索,而不是贪婪的方法。
f.尝试 BLEU score 来评估您的模型。
g.这个清单永无止境,还在继续。
10.结束注释
如果文章吸引你,一定要提供一些评论、反馈、建设性的批评等。
完整代码在我的 GitHub repo 这里 。
如果你喜欢我的解释,你可以关注我,因为我计划发布一些与深度学习和人工智能相关的更有趣的博客。
你可以在 LinkedIn 这里
11.参考
b.https://blog . keras . io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras . html
c.https://arxiv.org/abs/1409.3215
d.https://arxiv.org/abs/1406.1078
自然语言处理中的词表示第三部分
在我的博客系列关于单词表示的 第二部分 中,我谈到了 Word2Vec 和 GloVe 等分布式单词表示。这些表示将单词的语义(意义)和相似性信息合并到嵌入中。然而,它们不能推广到不属于训练集的“词汇之外”的单词(OOV)。在这一部分,我将描述减轻这个问题的模型。具体说一下最近提出的两个模型:ELMo 和 FastText。ELMo 和 FastText 背后的想法是利用单词的字符和形态结构。与其他模型不同,ELMo 和 FastText 不将单词视为一个原子单位,而是其字符组合的联合,例如"remaking->re+make+ing "
以前模型的问题
诸如 Word2Vec 和 GloVe 的先前模型从字典中查找预训练的单词嵌入,因此没有考虑在特定上下文中使用的词义。换句话说,一词多义(单词的多重含义)没有被考虑在内。例如:
“我的朋友正在考虑向银行贷款.”
"降雨导致莱茵河决堤. "
如果使用 Word2Vec 或 GloVe,那么单词*“bank”*将只有一次嵌入。但在上面两句话里有不同的内涵。在第一句话中,它的意思是为客户提供金融服务的机构。在第二句中,它暗示了水体旁边的斜坡。
ELMo:来自语言模型的嵌入
新模型 ELMo 能够通过将整个序列视为输入来解决以前模型的这个问题。它根据参照系动态地产生单词嵌入。该模型由三层组成:(1)卷积神经网络,(2)双向长短期记忆(LSTM)和嵌入。
Figure 1
ELMo 的模型输入(即 CNN 的输入)完全基于字符。所以最初,我们给 CNN 提供原始字符。然后 CNN 产生紧凑的嵌入,该嵌入被传递给双向 LSTMs。
b)双向 LSTM 层指示模型以正序和逆序在输入序列上运行。例如,让我们在下面的输入中获得单词“后跟的嵌入:
input = “多云的上午紧接着是一个阳光明媚的下午。”
context_straight= ['a ',‘多云’,‘早晨’]
context_reverse = ['by ‘,’ sunny ‘,’ a ‘,‘大部分’,’ sunny ',‘午后’]
因此,对于每个目标单词,模型可以观察它周围的前面和后面的单词。从图 1 中可以看出,堆叠的 LSTM 构成了多层 LSTM。每个 LSTM 都将前一个的输出序列作为输入,除了第一个 LSTM 层从 CNN 获得字符嵌入。
c)嵌入层连接 LSTM 方向的隐藏状态,并产生依赖于上下文的嵌入。在论文中,作者将其定义为隐藏状态乘以特定任务模型权重的线性组合。它为模型正在使用的每个任务学习单独的 ELMo 表示。因此,ELMo 提高了许多 NLP 任务的性能。为了简单起见,我省略了细节。这里可以找到。
使用 Tensorflow-hub 的 EMLo
依赖关系:
- Python 3.6
- 张量流 1.13.1
- 张量流-集线器 0.4.0
可以使用以下方式安装库:
pip 安装张量流==1.13
从 ELMo 模块加载预训练的单词嵌入:
参数trainable = False
因为我只想加载预先训练好的重量。但是图的参数不一定是固定的。通过将其设置为True
,可以重新训练模型并更新参数。
从预先训练的 ELMo 获得单词嵌入:
默认输出大小为 1024,让我们在上面两句话中寻找单词“bank”的前 10 个维度:
正如我们注意到的,在不同的上下文中嵌入同一个单词是不同的。如前所述,ELMo 通过输入一系列字符来动态构建单词嵌入。它依赖于句子中当前周围的单词。
FastText:子字模型
以前的模型的问题,他们不能为 OOV 生成单词嵌入(见上文)。这个问题不仅由 ELMo 解决,而且在子字模型中也解决了。此外,与 ELMo 相反,子词模型能够利用形态学信息。在子词模型中,具有相同词根的词共享参数。它被集成为 FastText 库的一部分,这就是它被称为 FastText 的原因。
子词模型是跳格模型(Word2Vec)的扩展,它产生给定一个词的上下文的概率。模型损耗定义如下:
损失函数的第一部分将所有上下文单词 w_c 视为正例,第二部分随机采样 N_t,c 作为位置 t. 处的作为反例。一方面,目标是将共现和相似的单词放置在彼此靠近的位置。另一方面,它旨在定位向量空间中彼此远离的不同单词。子词模型以类似的方式训练,除了它将计算的 n 元语法添加到特征。n 元语法定义为给定数量的项目序列。例如,n=2 的 n 元模型将给出单词“banking”的以下输出:{ ba,an,nk,ki,in,ng }。
下面是另一个例子:
“河岸”
**在跳格模型中,单词" river "有两个上下文标记: the and *bank。*而 n-gram(n = 2)的子词模型有 13 个上下文标记: th,eh,e_,a,an,nd,d,_b,ba,an,nk,the and bank。在实际中,我们提取 3≤ n ≤ 6 的所有 n 元文法。这是一种非常简单的方法,可以考虑不同组的 n 元语法,例如,取一个单词的所有前缀和后缀。
这种 n 元语法信息用子词信息丰富了词向量,并使模型能够为看不见的词构建向量。这对于形态丰富的语言和包含大量生僻字的数据集非常有益。德语就是一个很好的例子,因为它有丰富的复合名词。“Tischtennis”这个词翻译过来就是乒乓球。这个单词的嵌入将通过简单的加法来构建,例如 Tisch + Tennis → Tischtennis。
使用 Gensim 的快速文本
依赖关系:
- Python 3.6
- Gensim 3.7.2
可以使用以下方式安装库:
pip 安装张量流==1.13
使用自定义数据创建模型
让我们得到一个不属于训练的单词的嵌入:
有 157 种语言使用 wiki 数据的预训练模型,这里 可以找到 。也可以使用 gensim 加载它们。
拿走
ELMO 和子词是高级模型,能够为词汇表中存在和不存在的词产生高质量的嵌入。特别地,ELMo 能够在产生单词嵌入时考虑上下文信息。与其他现有模型相比,它具有更高的矢量质量。但是因为它在运行时进行预测,所以它有推理成本。另一方面,子字非常快,能够有效地合并 n 元语法。
单词间没有空格的语言的分词
Unigram 语言模型是一个良好的开端
Photo by Brett Jordan on Unsplash
如果您正在处理一些与中文、日文和韩文相关的 NLP 任务,您可能会注意到 NLP 工作流不同于英文 NLP 任务。因为与英语不同,这些语言中没有空格来自然地分隔单词。所以分词对于这些语言来说非常重要。我对不同的分词方法做了一点研究。在这篇文章中,我将给出选择最佳方法的简单建议。
TL;速度三角形定位法(dead reckoning)
使用 Unigram 语言模型。您可以从 SentencePiece 中实现,这是一个独立于语言的子词标记器。无论你使用什么语言,这都是一个好的开始。
个案研究
英语中下面的句子用空格隔开,但是日语中的句子没有空格。
from One Piece
两种语言中对应的标记如下所示。
I -> 私
will be -> になる
the prirate king -> 海賊王
So how to extract the “海賊王” is the word segmentation problem we need to deal with. Usually, there are three levels we can use, the word level, character level, subword level. But in recent years, the subword level approach has shown its superiority over other approaches, so in this post, I will focus on the subword level.
子词级分割
这篇帖子很好地介绍了 3 个子字算法:
- 字节对编码(BPE)
- 文字片
- 单语法语言模型
Unigram 语言模型的作者还实现了一个库, SentencePiece ,它包含两个子字算法,BPE 和 Unigram 语言模型。
在最近的强大的语言模型中,BERT 使用了 WordPiece 模型,XLNet 使用了 Unigram 语言模型。
Unigram 语言模型最大的优点就是这是一个独立于语言的模型。无论你使用什么语言,这都是一个好的开始。
查看我的其他帖子 中等 同 分类查看 !
GitHub:bramble Xu LinkedIn:徐亮 博客:bramble Xu
参考
- https://medium . com/@ makcedward/how-subword-helps-on-your-NLP-model-83 D1 b 836 f 46
- https://github.com/google/sentencepiece
- 【https://qiita.com/taku910/items/7e52f1e58d0ea6e7859c
- https://techlife.cookpad.com/entry/2018/12/04/093000
- https://qiita.com/mkt3/items/4d0ae36f3f212aee8002
- https://yoheikikuta.github.io/bert-japanese/
- https://qiita.com/hideki/items/56dc5c4492b351c1925f
Seq2Seq 架构中的字序列解码
自然语言生成【NLG】是生成文本的任务。像机器翻译、摘要、对话系统这样的自然语言生成任务的核心部分是根据给定的输入生成单词序列作为输出。例如,对于机器翻译系统,给定一个英语输入句子,模型需要生成其法语翻译。今天,大多数这样的系统都是建立在编码器-解码器架构及其变体之上的。图 1 显示了这种架构的示意图。
Fig.1 from Source
在上面显示的图像中,编码器负责捕获源/输入语言的完整上下文,而解码器负责使用该信息并输出所需语言的翻译。这种模型是用两种语言的巨大平行句子语料库来训练的。深入这种架构的本质已经超出了本博客的范围。请在此阅读更多T5。此外,实际谷歌的 NMT 系统也有一个关注组件。要了解注意力网络,请 阅读此 。
在每个解码器时间步长,使用 Softmax 激活函数 跨词汇输出概率分布是很常见的。在模型被训练之后选择最终的输出序列取决于所使用的解码策略。
在这里,我们将讨论在推理期间广泛使用的 3 种解码策略
1.贪婪搜索
该策略在每个解码时间步从模型的词汇中选择最可能的单词(即 argmax )作为输出序列的候选。
Decoder Segment
这种方法的问题是,一旦在任何时间步长 t 选择了输出,我们就不能灵活地返回并改变我们的选择。实践证明,贪婪解码策略在生成的文本中容易出现语法错误。这将导致在任何时间步长 t 选择最佳,但是当考虑整个句子语法正确和合理时,这不一定给出最佳。
2.具有固定波束大小的波束搜索
波束搜索策略试图找到具有最大可能性的输出序列。它通过将贪婪采样扩展到 Top-k 采样策略来实现这一点。在任何时间步 t,它将 top-k 最可能的单词视为该步的候选单词。这里,k 称为光束尺寸。在数学上,我们试图最大化下面提到的等式—
下图显示了在 k=3 的情况下实际上是如何发生的
Beam Decoding with k=3 at each time-step
这里,我们通过在解码时跟踪每个时间步长的前 k 个词汇输出来搜索高分输出序列。我们通常在到达句子结束标记(< eos >)时停止搜索,或者直到所有或至少一些 n 输出序列的时间步长 t 时停止搜索。我们还通过长度进行标准化,以避免在对任何序列评分时引起的任何偏倚。
Normalized Beam Search Scoring
这里,波束大小充当时间复杂度和精确度之间的折衷变量。让我们分析一下 k 可以取的最小值和最大值:
- 当 (k=1) —其行为类似于贪婪搜索,其中 argmax 在任何时间步 t 被馈送到后面的连续步骤。
- 当**(k =词汇的大小)** —其行为类似于穷举搜索,其中每个时间步的可能单词都是整个词汇,并且每个单词都给出了随后连续步骤的下一组词汇的概率分布。
Time Complexity Analysis
3.可变波束大小的波束搜索[1]
考虑到固定射束尺寸的限制,发展了可变射束尺寸的概念。固定的波束大小可能不一定是每个解码时间步长的最佳选择。
让我们用一个例子来理解它——让前 5 个词在任何时间步长 t 的概率值是可比较的。在这种情况下,固定波束大小(k)我们可能会错过相关的候选,导致信息丢失。然而,让前两个词在任何时间步长 t 都是可比的,其余的都很低。在这种情况下,固定波束大小(k ),我们可以通过添加不太相关的候选来添加噪声。
相反,波束大小应该是任何解码时间步长(t)的概率分布的函数。在[1]中,作者谈到了可以用来推导这种关系的各种技术。此外,如果你仔细注意,这也可以被视为一个宁滨问题,可以离散化的熵措施。请在这里阅读更多。
4.温度诱导最大值
这不是一个解码策略,但是可以和上面提到的任何搜索一起使用。在任何解码步骤中,我们通常使用 Softmax 激活函数来传递我们的词汇的概率分布。我们不使用普通的 Softmax,而是使用它的修改版本,如下所示
Temperature Induced Softmax
这里,T 是温度变量。很容易看出,较高的 T 值将导致肥胖分布(给所有人几乎相同的概率),而较低的 T 值将导致峰值分布(给一些人高概率)。
虽然这个博客主要集中在谈论单词序列解码,但没有说这些推理时间解码序列算法可以用于任何序列解码任务。
在https://prakhartechviz.blogspot.com查看我的博客库
进一步阅读
随时分享你的想法:)
词向量和词汇语义——基于计数的向量介绍
Image from Ryan Haggins via Unsplash
以下是我基于 2017 年牛津大学举办的深度 NLP 课程的个人笔记。该材料可从[1]处获得。
介绍
单词向量 : 用向量格式表示单词。
词汇语义学 : 分析词义以及词义之间的关系。
神经网络需要矢量表示作为输入。因此,需要将单词或句子转换成向量。
代表单词
文本仅仅是离散符号(即单词)的序列。一种简单的表示方法是对句子中的每个单词进行一次性编码。然而,这样做需要大量的内存/空间,因为向量空间(由一个热点编码向量组成)实际上就是你的词汇表的大小。
这种方法的问题是,由于每个向量都被定义为一个单词,因此每个向量都以一种相当正交的方式表示,在语义上彼此没有明确(弱)的关系。他们彼此之间也很稀疏。因此,需要能够表达语义相似性的更丰富的表示。
分布语义学
分布语义学 : 发展和研究理论和方法的研究领域,这些理论和方法基于语言项在大量语言数据样本中的分布特性,对语言项之间的语义相似性进行量化和分类【2】。
“从一个人所交往的人身上,你就可以知道他所说的话”——J . R .弗斯(1957)
上面的引用和其他类似的类比指出,可以通过观察人们如何使用单词来理解单词的意思。
同时,我们也对减少向量空间的大小感兴趣。这可以通过产生密集矢量表示(与稀疏相反)来实现。
从计算角度来看,有 3 种主要方法可以做到这一点。
- 基于计数的
- 预言性的
- 基于任务的
能够将单词指定为向量的优点是,可以开始客观地测量和比较单词向量,或者计算相似性、距离等。
让我们先介绍一下基于计数的方法。
计数法
定义要使用的基本词汇。通常它们是基于我们自己的经验/直觉或语料库的统计数据来选择的。这些词汇最好是信息丰富且有意义的。
通常词汇量是有限的。停用词通常被排除在外,因为它们在大多数可用的语料库中出现得很多。如果我们要包含它们,那么我们将很难确定它们之间的关系,因为停用词到处都在同时出现。
让我们看一个例子:
Credits to [1]
在上面的例子中,我们可以看到某些单词被选为我们感兴趣的基本词汇。还要注意像*、、、*这样的停用词不是基础词汇的一部分。
确定了目标单词及其上下文之后,我们现在可以将其表示为一个向量(如下所示)。
Example. Credits to 1. Note that the value doesn’t have to ONLY be 1.
作为向量,现在可以分析单词,可能通过相似性(计算相似性的最流行的方法是余弦距离)、向量空间中的距离等。
然而,仍然有一些缺点:
- 不是所有的单词都具有同等的信息量,因为有些单词在不同的文本中出现的频率更高;并且由于这一点,不再能够唯一地与特定的上下文相关联。
- 例如,在描述各种四条腿动物的文本中,单词跑或四条腿将无法区分语料库中的动物类型。
- 然而,它们是克服这一点的方法,如 TF-IDF 或 PMI。
在我的下一篇文章中,我们将探索一种更简单的方法来解决这些问题。
参考
- https://github.com/oxford-cs-deepnlp-2017/lectures
- https://en.wikipedia.org/wiki/Distributional_semantics
用 NumPy 从头开始 Word2vec
如何用 Python 和 NumPy 实现 Word2vec 模型
介绍
最近工作中一直在做几个和 NLP 相关的项目。其中一些与培训公司内部的单词嵌入有关。在工作中,这些任务大多是在 Python 库的帮助下完成的: gensim 。然而,我决定在 Python 和 NumPy 的帮助下从头实现一个 Word2vec 模型,因为重新发明轮子通常是一种深入学习的好方法。
单词嵌入
单词嵌入没什么新奇的,不过是用数字方式表示单词的方法。更具体地说,是将词汇映射到向量的方法。
最直接的方法可能是使用一键编码将每个单词映射到一个一键向量。
尽管一键编码非常简单,但也有一些缺点。最值得注意的一点是不容易用数学方法测量单词之间的关系。
Word2vec 是一种神经网络结构,通过在监督分类问题上训练模型来生成单词嵌入。这种方法首先在 Mikolov 等人于 2013 年发表的论文 对向量空间中单词表示的有效估计 中介绍,并被证明在实现单词嵌入方面相当成功,该方法可用于测量单词之间的句法和语义相似性。
Word2vec(跳格)
Mikolov 等人在 2013 年提出了两种模型架构,连续词袋模型和跳格模型。在本文中,我将深入探讨后者。
为了解释跳格模型,我随机引用了我正在读的一本书的一段文字,约翰·博格尔的《投资常识小书》:
扣除投资成本后,跑赢股市是输家的游戏。
正如我上面提到的,word2vec 模型试图优化的是一个监督分类问题。更具体地,给定一个“上下文单词”,我们想要训练一个模型,使得该模型可以预测一个“目标单词”,其中一个单词出现在来自上下文单词的预定义窗口大小内。
以上面的句子为例,给定一个上下文单词“investing ”,窗口大小为 5,我们希望模型生成一个底层单词。([扣除,的,成本,殴打,股票,市场]中的一个词是在这种情况下。)
模型概述
下图显示了 Mikolov 等人 2013 年论文中的原始图表。
我做了另一个更详细的图表
单词嵌入层本质上是一个形状为(语料库中唯一单词的数量,单词嵌入大小)的矩阵。矩阵的每一行代表语料库中的一个单词。单词嵌入大小是一个有待决定的超参数,可以认为是我们想要使用多少特征来表示每个单词。模型的后一部分只是神经网络形式的逻辑回归。
在训练过程中,单词嵌入层和密集层被训练,使得在训练过程结束时,给定上下文单词,模型能够预测目标单词。在用大量数据训练这样一个模型之后,单词嵌入层将最终成为单词的表示,它可以用数学方式展示单词之间的多种酷关系。(对更多细节感兴趣的可以参考原论文。)
使用 Python 从头开始实现
培训数据的准备
为了生成训练数据,我们首先对文本进行标记。当涉及到标记文本数据时,有许多技术,比如去掉出现频率很高或很低的单词。我只是用一个简单的正则表达式分割文本,因为本文的重点不是标记化。
接下来,我们给每个单词分配一个整数作为它的 id。另外,使用word_to_id
和id_to_word
记录映射关系。
最后,我们为模型生成训练数据。对于每个上下文单词tokens[i]
,生成:(tokens[i], tokens[i-window_size]), ..., (tokens[i], tokens[i-1]), (tokens[i], tokens[i+1]), ..., (tokens[i], tokens[i+window_size])
。以窗口大小为 5 的上下文单词investing
为例,我们将生成(investing, deduction), (investing, of), (investing, the), (investing, costs), (investing, of), (investing, beating), (investing, the), (investing, stock), (investing, market), (investing, is)
。注意:在代码中,训练(x,y)对用单词 id 表示。
以下是生成训练数据的代码:
培训流程概述
生成训练数据后,让我们继续研究模型。与大多数神经网络模型类似,训练 word2vec 模型的步骤是**初始化权重(我们要训练的参数)、向前传播、计算成本、向后传播和更新权重。**根据我们想要训练多少个纪元,整个过程将重复几次迭代。
待训练参数的初始化
模型中有两层需要初始化和训练,即单词嵌入层和稠密层。
字嵌入的形状会是(vocab_size, emb_size)
。这是为什么呢?如果我们想用一个包含emb_size
个元素的向量来表示一个词汇,并且我们的语料库中的词汇总数是vocab_size,
,那么我们可以用一个vocab_size x emb_size
矩阵来表示所有的词汇,其中每行代表一个单词。
密集层的形状将是(vocab_size, emb_size)
。怎么会这样将在这一层中执行的操作是矩阵乘法。这一层的输入将是(emb_size, # of training instances)
,我们希望输出是(vocab_size, # of training instances)
(对于每个单词,我们希望知道该单词出现在给定输入单词中的概率)。注意:我不包括密集层中的偏差。
以下是初始化的代码:
前进传球
The Upper part shows the forward propagation.
正向传播有三个步骤,从单词嵌入获得输入单词的矢量表示,将矢量传递给密集层,然后将 softmax 函数应用于密集层的输出。
在一些文献中,输入被表示为一个热码向量(假设第 I 个元素为 1 的一个热码向量)。通过将单词嵌入矩阵和独热向量相乘,我们可以得到表示输入单词的向量。但是,执行矩阵乘法的结果本质上与选择单词嵌入矩阵的第 I 行相同。我们可以通过简单地选择与输入单词相关的行来节省大量的计算时间。
剩下的过程只是一个多类线性回归模型。
下图可用于回忆致密层的主要操作。
然后,我们将 softmax 函数应用于密集层的输出,这给出了每个单词出现在给定输入单词附近的概率。下面的等式可以用来提醒什么是 softmax 函数。
以下是向前传播的代码:
成本的计算(L)
这里,我们将使用交叉熵来计算成本:
以下是成本计算的代码:
反向传递(反向传播)
在反向传播过程中,我们希望计算可训练权重相对于损失函数的梯度,并使用其相关梯度更新权重。反向传播是用来计算这些梯度的方法。除了微积分中的链式法则之外,没什么稀奇的:
我们想要训练的是密集层和单词嵌入层中的权重。因此,我们需要计算这些重量的梯度:
下一步是使用以下公式更新权重:
以下是向后传播的代码:
注意:你可能会奇怪为什么在dL_dW
中有一个1/m
的因子,而在dL_dword_vec
中没有。在每一遍中,我们一起处理m
训练示例。对于密集层中的权重,我们希望用m
梯度下降的平均值来更新它们。对于单词向量中的权重,每个向量都有其自己的权重,这导致其自己的梯度下降,因此我们在更新时不需要聚集m
梯度下降。
模特培训
为了训练模型,重复向前传播、向后传播和权重更新的过程。在训练期间,每个时期之后的成本应该有下降的趋势。
下面是为模型定型的代码:
估价
在用从上面的示例句子生成的数据训练模型之后,窗口大小为 3,5000 个时期(具有简单的学习率衰减),我们可以看到,在给定每个单词作为输入单词的情况下,模型可以输出最多的相邻单词。
你可以在这个笔记本里找到端到端的流程。请随意下载并试玩。
这是我的第一个中等职位。谢谢你们的阅读。请随时向我提供反馈或向我提问。
在这里停止阅读是好的,但如果你对我在尝试用更大的数据集训练时发现需要的一些优化感兴趣,请继续阅读。
优化(空间)
当我试图用更大的数据集训练上面的模型时,我发现在训练过程中内存消耗不断增加,python 内核最终关闭。后来,我发现这个问题与我将标签Y
输入模型的方式有关。
在原始代码中,每个标签都是一个 hot vector,它使用一串 0 和一个 1 来表示带标签的输出字。当词汇量越来越大时,我们浪费了太多的内存到那些不能给我们提供有用信息的零上。
在我开始只给标签添加相关的单词 ind 之后,内存消耗问题就消失了。我们把空间从 O(词汇量* m)减少到 O(m)。
以下是我的代码实现(只有 2 个地方需要修改):
为了优化训练时间,可以用分级 softmax 代替上述常规 softmax。然而,这篇文章有点太长了,所以我们下次再讨论这个话题。
感谢大家多阅读。同样,请随时向我提供反馈或向我提问。
更新
- *【2019–02–17】*如果你对如何得出密集层的输出相对于损失的梯度感兴趣,这里有一个我的导数的书面笔记的链接:https://github . com/ujhuyz 0110/written _ notes/blob/master/soft max _ gradient . pdf
Word2vec 变得简单
这篇文章是 word2vec 的一个简单而深入的指南。在本文中,我们将从头实现 word2vec 模型,看看嵌入如何帮助找到相似/不相似的单词。
介绍
Word2Vec 是 NLP(自然语言处理)的基础。托马斯·米科洛夫和他的研究团队于 2013 年在谷歌开发了这项技术。他们的方法首先发表在论文《向量空间中单词表示的有效估计》中。他们改进了他们的模型,通过使用像频繁词的二次抽样和采用负抽样这样的技术来提高表示的质量和计算的速度。这项工作发表在论文“单词和短语的分布式表示及其组合性”上。
Word2Vec 是一种将单词表示为向量的高效且有效的方式。整个文本被压缩在一个低维度的空间里。在这个空间中,所有向量都有一定的方向,并且可以明确地定义它们之间的关系。单词作为嵌入向量的分布式表示为以适合 NLP 中许多应用的方式找到单词提供了许多可能性。
履行
我们将保持语料库简单,因为它有助于我们轻松理解每一步,而且我们可以清楚地可视化关系,使其更加具体。CBOW(连续单词包)和 Skip-Gram 是两种最流行的单词嵌入框架。在 CBOW 中,在所选单词的上下文(周围单词)中出现的单词被用作输入,中间或所选单词被用作目标。在 Skip-Gram 中正好相反,这里中间的单词试图预测它前面和后面的单词。
考虑由从“a”到“z”的字符顺序组成的文本[a,b,c,d,e,f,g,h,I,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z],进一步让整数 0 到 25 代表相应的字母。在保持窗口大小为 2 的情况下实现 CBOW,我们可以看到“a”与“b”和“c”相关,“b”与“a”、“c”和“d”相关,依此类推。由此可见,表示输入单词的一个热向量的维数为[26,1]。在模型的帮助下,我们将找到大小为[10,1]的密集分布向量。嵌入向量的大小是任意选择的。
下图说明了上下文和目标词。
Left. Arrangement of CBOW and Skip-gram models. Right. Character and corresponding integers grouped into lists of input and targets. For each the first column represents the input character and the remaining items in each sub-lists are targets for the input.
想象关系的模式是很容易的。当它们在两个字符的范围内同时出现时,它们是相关的或者共现是真实的。下面的表格和地图描述了这种模式。
Left. Characters appearing together (not fully visualized). Right. The black color region implies no co-occurrence and white region implies characters occurring together given windows size of 2 #Also note the diagonal symmetry — implying that co-occurrence from a to b means co-occurrence from b to a but these relationships are depicted different axes.
Word2Vec 是一个概率模型。该模型的关键组件是两个权重矩阵。第一矩阵(w1)的行和第二矩阵(w2)的列分别嵌入输入单词和目标单词。给定所选择的输入单词,这两个单词向量的乘积然后被用于获得成为目标单词的概率。在训练时,使用梯度下降优化这些嵌入向量,使得真实目标的概率最大化。显然,矩阵 w1 和 w2 是因式分解的概率矩阵,它非常类似于共生矩阵。
下图对模型进行了说明和解释。
Schematic diagram of Word2Vec model. Input and Output vectors are of size V, while hidden vector (embedding) is of size N. (Source: https://lilianweng.github.io/lil-log/2017/10/15/learning-word-embedding.html)
In this illustration, the model is learning to embed 6 characters (‘a’ to ‘f’) into a 3-dimensional embedding vector. A. Co-occurrence Matrix of these characters with a window size of 2, co-occurrence is expressed as either present or absent. (size 6, 6) B. Weight matrix w1 — transposed. Each row of matrix w1 is embedding vector for the one word as one hot vector uniquely selects the corresponding row of w1 (or col of W1 transpose) C. Matrix of one hot vector, each column represents one word/item D. Product of w1 and input matrix results in matrix h (hidden layer). Here the whole input matrix is as an identity matrix and simply passes weight matrix w1 as hidden matrix h. However it is not necessary to be an identity matrix, the order and size of the input matrix(and hence hidden layer) could be different E. Weight matrix w2 — transposed (size 6,3). Each column of matrix w2 closely represents represents the target words F. Hidden layer — h, identical to w1 as described before G. Each row of w2 — transposed products with a column of hidden (that embeds an input word ) outputting scores of length of the size vocab H. As mentioned all rows of w2_transposed interacting with 1 column of hidden — results in one column of Score Matrix , total product of w2_transposed and h is the matrix S (size 6, 6) I. Softmax is applied to score matrix. Each entry in a column is converted into probabilities J. Probability matrix — each item in a column of this matrix represents probabilities for being a target word given an input word L. Error —Probability at the position of true indices are to be maximized, error is computed comparing this probability assigned to the index corresponding to true targets M. Back prop — At the start weights are initialized randomly and resulting probabilities are low and similar for all targets. After training, back propagation of gradients and optimization of weights, probabilities are dense around targets and close to 0 at other places.
py torch 中的实施
从上面可以明显看出,网络是轻的,嗯模糊的。在这里,我们只需要为每个字母创建一个热点向量,并将其与所有目标配对。例如,字母“a”是[1。, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.](调整为大小为 26,1)作为一个热向量,其目标索引为 1 和 2(“b”和“c”)。
网络有两个完全连接的层,分别计算隐藏层和输出层。没有使用偏倚,因为它们对于相似性度量是多余的。Softmax 是唯一的激活,它将输出分数转换为概率。这里的损失标准(nn。CrossEntropyLoss)实现 Softmax 并计算损失。优化权重时选择了 Adam 优化器。
#**Dependencies**import torch
import torch.optim as optim
import matplotlib.pyplot as plt#**Generating desired pair of inputs and targets**#Empty list that collects input and target in pairs
inp_target_list = []
for i in range(26):
temp = []
a, b, c, d = i- 2, i - 1, i + 1, i + 2 #targets for input i
temp.extend([a, b, c, d])#keep targets within range of 0 to 25
for j in range(4):
if temp[j] >=0 and temp[j] <=25:
inp_target_list.append([i, temp[j]])print(inp_target_list[:5])
#[[0, 1], [0, 2], [1, 0], [1, 2], [1, 3]]**#Get one hot vectors for all inputs**#Initiate tensor with 0’s that holds all inputs in inp_target pairs
inp_tensor= torch.zeros(len(inp_target_list), 26)#Substitute 1 for 0, at position indicated by respective input
for i in range(len(inp_tensor)):
inp_tensor[i, np.array(inp_target_list)[i, 0]] =1#One_hot for 0 or letter 'a'
print(inp_tensor[0])
#tensor([1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0.])**#Create Network**
#2 fully connected layers with NO bias
#Embedding dimension is 10
#Softmax is implemented using loss criterion (nn.CrossEntropyLoss())fc1 = nn.Linear(26, 10, bias = False)
fc2 = nn.Linear(10, 26, bias = False)
params = list(fc1.parameters()) + list(fc2.parameters())LR = 0.001 #Learning rate
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(params, lr = LR)**#Train**#Define inputs and target tensors
inp_tensor = inp_tensor
target_tensor = torch.tensor(inp_target_list)[:, 1]losses = []for i in range(10000):
out_1 = fc1(torch.Tensor(inp_tensor)) #hidden layer
out_2 = fc2(out_1) #Score matrix optimizer.zero_grad() #Flushing gradients
loss = criterion(out_2, target_tensor.long().view(out_2.shape[0],))#Apply Softmax, get loss
loss.backward() #Getting grads
optimizer.step() #Correcting parameters
if i % 1000 == 0:
losses.append(loss.item())
print(loss.data)**#Loss printed**
tensor(3.2619)
tensor(3.0980)
tensor(2.7768)
tensor(2.4193)
tensor(2.1216)
tensor(1.8937)
tensor(1.7242)
tensor(1.6007)
tensor(1.5130)
tensor(1.4526)
tensor(1.4121)
.........
结果和推论
这里我们将回顾一系列矩阵。解释图片/图案要容易得多,这些图片/图案让我们对分布在整个矩阵中的数字有一个清晰的概念。
下面每个热图的内容都在各自的标题中进行了讨论和解释。得分矩阵中的每一行都是单词作为输入和单词作为目标的嵌入向量的乘积。乘积被视为概率矩阵中的概率。两个字符的窗口内的相邻字符具有更高的值和密集概率。
距离矩阵是从输入单词的每个嵌入向量到作为输入的单词的所有嵌入向量(包括其自身)的余弦距离。热对角线值是其自身的乘积,距离为 1。接近对角线的值是暖的,表示它们是每个对角线元素的近邻。当矩阵被绘制为 1 时,这种模式得到了很大的增强,正距离和负距离与平滑距离一样。
#Note: As there is no transposition of weight matrices in forward #propagation columns represent the embedding vectors#**Score Matrix**
plt.matshow((fc1.weight.t() @ fc2.weight.t()).detach().numpy())#Probability Matrix
plt.matshow(nn.Softmax(dim = 1)(fc1.weight.t() @ fc2.weight.t()).detach().numpy()) #**Distance Matrix**
dist_matrix = torch.zeros(26, 26)
for i in range(26):
for j in range(26):
dist = torch.nn.functional.cosine_similarity(fc1.weight.t()[i, :], fc1.weight.t()[j, :], dim = 0, eps = 1e-8)
dist_matrix[i, j] = dist #**Smoothed distances**
if dist_matrix[i, j] ==1 --> 1
if dist_matrix[i, j] < 0 --> -0.5
if dist_matrix[i, j] 0 to 0.99 --> 0.5
A. Score matrix: Product of each context vector with each word vector. Cells corresponding to co-occurrence have high score and rest have low scores, closely resembles co-occurrence matrix. B. Probability Matrix: Obtained applying softmax to score matrix. Each row corresponds to a probability of target word for the index word (chars here). a,z have two targets, assigned probs are 0.5 each b, y have 3 targets, assigned probs are 0.33 each rest have 4 targets, assigned probs are 0.25 each This matrix also represents the prediction of model given any word. (same cells represent prediction with assigned probs) Prediction involves both matrices of the model and Softmax as end activation. Symmetry is consequence of reciprocity ie. context and target words have reciprocal relationship in this example.
`Left. Cosine distance calculated from each character to other. The distance between a word with itself is 1 (maximum) The similarity distances with neighbors are large and non- neighbors are small. Prediction and distances are not the same. Distances are computed from the word vectors (weight matrix 1) alone. B. Smoothed Distances: Here distances are smoothed Distance of 1 → 1, Pos distances < 1 → 0.5 , Neg Distances → 0.5. Map clearly identifies the neighboring cells with higher similarity distances.
嵌入向量
首先,让我们看看 w1 中的‘a’和 w2 中的‘b’的嵌入,它们分别代表输入/周围单词和目标/中间单词。“a ”(作为输入)和“b ”(作为目标)之间的向量积是 18.217,这是一个相对较大的正数,而对于所有其他字符来说,它很小或为负数(除了“c”)。这意味着“b”(和“c”)将有更高的概率。另一方面,从 w1 中取两个矢量,作为输入的矢量“a”和作为输入的矢量“b”之间的余弦相似度是 0.4496 或大约 63 度,这意味着一些相似性。
**#Embedding for ‘a’ and ‘b’**
vec_a = fc1.weight.t()[0].data #select 'a' from w1
vec_b = fc1.weight.t()[1].data #select 'b' from w1
vec_b_as_target = fc2.weight[1].data #select 'b' from w2#vec_a
[1.7211128, -1.8706707, 0.15043418, -1.7761097, 0.25396731, 0.17291844, 0.11687599, -2.0173464, 1.4879528, -1.6174731],#vec_b
[-1.8015, -0.6789, -1.3880, -1.6618, 1.5363, -1.8415, 1.9647, -1.5331, 2.0684, -1.7526] #vec_b_as_target
[1.9113195, -1.9370987, 1.349203, -1.5565106, 1.1705781, -0.78464353, -1.7225869, -1.7434344, 1.9383335, -1.2209699]#Cosine similarity between two characters
torch.nn.functional.cosine_similarity(vec_a_as_input, vec_b_as_input, dim = 0, eps = 1e-8) #0.4496 or 63 degrees#vector product between input and target vectors --> raw score
vec_a@vec_b_as_target #18.217
余弦相似度
在不同的距离度量中,余弦相似度更直观,在 word2vec 中使用最多。它是两个向量的归一化点积,这个比值定义了它们之间的角度。具有相同方向的两个向量的余弦相似度为 1,90°的两个向量的相似度为 0,直径方向相反的两个向量的相似度为-1,与它们的大小无关。
Top left: Equation for cosine distance Top right: Cosine distance varies from 1 to -1 and corresponding angle varies from 0 to 180 degrees. Bottom left: Cosine distances from ‘c’ to all the characters. Bottom right: Same distances expressed as angles. Note ‘c’ is most similar to itself.
矢量组合并寻找它的邻居
一旦单词用向量表示,寻找相似或不相似单词的任务就变得容易了。任何矢量组合都会产生新的矢量,余弦距离或其他相似性度量可以像以前一样使用。这些操作构成了著名等式“国王-男人+女人=王后”的基础。
用于降维的 t-SNE
t-SNE(t-分布式随机邻居嵌入)有助于进一步将向量的维数降低到 2 或 3 维,使得可以可视化向量及其空间排列或分布。下面的代码是嵌入向量从 10 维到 2 维的 t-SNE 变换的一个例子。
from sklearn.manifold import TSNE
tsne_2d = TSNE(n_components=2).fit_transform(fc1.weight.t().detach().numpy())#First five 2d vectors
print(tsne_2d[:5])
array([[-1.11534159e-04, 1.24468185e-04],
[-8.66758155e-05, -1.63095172e-04],
[-5.46419301e-05, 6.82841112e-05],
[ 1.30452306e-04, 1.16242307e-04],
[-2.39734325e-05, 1.93809960e-04]])
Left. For the selected combination [c + d -e], most similar characters ‘c’ and most dissimilar character is ‘w’. Right — Scatter plot of characters in 2D after t-SNE transformation of embedding. As expected no clusters are observed as data is evenly spread.
结论
word2vec 实现的关键是构造两个互补的权重矩阵,将单词表示为输入和上下文或目标。嵌入维度可以是任意维度,这取决于词汇表的大小。模型的输出或预测不同于相似性或距离。当模型学习从输入到输出的映射时,嵌入捕获它们彼此的相对位置。Softmax 适用于较小的语料库,但随着词汇量的增加,它会变得低效,因为它涉及到对整个词汇长度的分数求和。负采样 Skip gram 是首选算法。
最后,Gensim 是一个受欢迎的免费库,我们可以很容易地使用它进行单词嵌入和文本分析。但是了解了基本原理,使用这些工具就变得更加清晰和容易了。
数学推导供参考
符号和等式:
x:一个热向量输入(大小:vocab,1)
w1:权重矩阵 1(大小:vocab,嵌入 dim)
h:隐藏层(大小:嵌入尺寸,1)
Vc:单词输入的向量嵌入(在 CBOW 中,输入单词是上下文单词)
w2:权重矩阵 2(大小:嵌入 dim,vocab)
Vw_i:第 I 个目标单词的向量嵌入(在 CBOW 中,给定所选的周围单词,我们试图预测中间的单词)。尺寸(嵌入尺寸,1)
S 和 S_i : S_i 是 h(或 Vc 或 w1 的选定行)和 Vw_i(或 w2 的第 I 列)的向量积。s 代表每个 Vw 的 Vc 得分。(大小:S_i 是标量,S 的分数和 vocab 一样多)
Y_i: Softmax 将得分 S_i 转换为概率 Y_i(或第 I 个目标词的概率)。这样做 Softmax 需要对所有分数求和
Vw_prime:对所有目标词求和
P(w|c):给定上下文或输入单词的目标单词的概率
L(theta):参数的似然性(theta 表示 w1 和 w2,它们又是语料库中所有单词的 Vc 和 Vw 的集合)
l(θ):θ的对数似然
rho:学习率
注意:以下等式一次使用一个字符或一个单词向量(Softmax 标准化期间除外),但在算法中实现时会处理一批或全部词汇。
正向传播
似然和反向传播
参考资料:
[1]托马斯·米科洛夫,程凯,格雷格·科拉多,杰弗里·迪恩,向量空间中词表示的有效估计(2013),arXiv:1301.3781 [cs .CL]
[2]米科洛夫、托马斯、伊利亚·苏茨基弗、程凯、格雷戈里·科拉多和杰弗里·迪恩。“单词和短语的分布式表示及其组合性.” NIPS (2013)。
另请查看:阿里·高德西,Lec 13: Word2Vec Skip-Gram
请通过以下方式连接:
邮件:mnshonco@gmail.com 或
领英:https://www.linkedin.com/in/mrlakhey/
激励人心的话,TED 演讲上的数据科学项目
“激励人心的话语”是对 2500 多个 TED 演讲的分析,使用文本分析和 R 上的机器学习来寻找使一些演讲比其他演讲更受欢迎的因素。
做这个项目的动机是什么?
我是伦敦一个名为 Data Scientist speakers 的 meetup 小组的成员,该小组定期开会练习数据科学演讲,并接收反馈以提高公众演讲水平。
俱乐部每年都会举办一场比赛,看谁能带来最好的数据科学故事。我参加了这个比赛,并希望参与一些特别的事情:我想结合我的数据科学技能来分析著名的演讲或会谈,并使用这些见解来构建一个全新的演讲或会谈。
灵感的来源是什么?
我以我最喜欢的三篇演讲开始了我的分析,它们是由最杰出的公共演说家发表的,他们的演讲激励了数百万人塑造我们今天生活的世界。
你能从下面的片段中认出这些演讲和他们的演讲者吗?
我说的是约翰·肯尼迪、马丁·路德·金和温斯顿·丘吉尔。
信封背面的计算 对于这三篇演讲,我分析了他们使用的词的频率,我得到了一个大惊喜…每篇演讲中使用最多的词是相同的!你能在单词云的中间看到它吗?
三位演讲者用得最多的词是“Will”(温斯顿·丘吉尔用的是 Shall,妥妥的英式风格!).他们可能会用“Will”这个词来激励人们采取行动,或者表示未来会发生变化。除了这种相似性,三位演讲者还使用了一种叫做结构重复的东西。他们多次重复同一句话来制造影响和记忆。
但是我们需要更多的数据!这些巧合让我想到,单词中可能存在潜在的模式,可以让演讲更具启发性。但三次演讲肯定不足以得出结论,这促使我寻找一组合适的演讲来进行分析。理想情况下,要进行数据分析,会谈应包括:
- 足够数量的会谈进行分析
- 理想情况下,采用相同的形式和风格,以避免因谈话形式不同而产生的强烈偏见
- 应该有可用的抄本,因为这将减少时间和精力
- 对于机器学习的使用,应该有一种方法来跟踪受欢迎程度的进展,以检测更鼓舞人心的谈话和不太鼓舞人心的谈话
突然灵机一动
看来,要找到一套考虑到这些因素的谈判方案可能是一项艰巨的任务。然而,我很快意识到已经有具备所有这些特征的演讲了:Ted 演讲!
类似风格的 Ted 演讲有成千上万个,他们记录受欢迎程度,他们有可用的抄本和其他信息,比如他们网站上的浏览量和评论。为了让事情变得更容易,数据科学竞赛网站 Kaggle 已经公布了所有这些数据,并允许任何人以合适的格式下载它们。
数据科学方法
有了现在可用的数据,我就可以进行分析了,分析可以分为三个阶段:
一.数据提取和特征工程
二。数据分析和模型集成
三。模型洞察力
一、数据提取和特征工程
Kaggle 提供的数据集包含大量数据,需要首先进行转换才能执行分析。我是 R 的常客,但对文本分析不是很熟悉,所以基本上我遵循了“用 R 进行文本挖掘”这本书上的所有内容。这本书绝对是使用 r 进行文本分析的来源。
该数据集包含了所有 TED 演讲活动及其所有的文字记录,以及你可以在他们的网页上看到的任何其他数据。一个非常好的地方是,它还包括数据提取的日期,每个 ted 演讲在网站上的发布日期以及它们的拍摄日期。这些特征对于通过使用机器学习算法在模式搜索中执行预测分析将变得很重要
我构建了 50 多个特征作为潜在因素,来测试为什么有些演讲比其他演讲更受欢迎。这些原始因素组中的大多数与字数的频率分析相关,例如:
- 通过使用每分钟的单词数、他们说的句子数和每句话的单词数来判断说话者的语速
- 观众的反应利用了一个在记录中发现的有趣特征,包括观众笑的具体场合,掌声,提问的次数
- 我还加入了许多最常见的 n-grams,看看是否有他们倾向于重复的特定单词
有了这些因素,我的目标是一个分类问题来预测一个 ted 演讲是否会流行
二。数据分析和模型集成
这个阶段可以概括为以下步骤
**1。描述性分析:**该分析的一个关键特征是以某种方式标准化了在线观看 Ted 演讲的时间。一个 TED 演讲在网站上出现的时间越长,被浏览的机会就越多。因此,我将每月的平均指标标准化,而不是使用总数。
**2。相关性分析:**许多变量将倾向于与其他变量相关。因此,我使用的一种技术是仅使用最具预测性的变量(在单变量水平上),并丢弃预测性较低的变量。
**3。额外的特征工程:**一些 n-gram 在它们之间是相关的,因为它们使用相同的单词,所以我将那些有用的相似的 n-gram 组合成一个变量。
**4。模型评估:**我开始使用逻辑回归分析单变量水平的数据,以找到最相关的变量,并丢弃完全没有预测性的变量。使用前 20 个最相关的单个变量,我开始通过调整 hyper 参数、变量箱和不同的变量选择方法,手动开发几种类型的模型,包括逻辑回归、随机森林和 XGBoost。
除了手动开发的模型,我还使用了 H2O 的 AutoML 功能,该功能可以自动开发多种类型的模型,如堆叠模型、深度学习和其他梯度推进方法。这种自动建模技术将帮助我参考其他类型的模型如何与我手工开发的模型进行比较。
三世。模型洞察
令人惊讶的是,H20 开发的不同类型的模型在性能方面与人工逻辑回归模型相差不远。因此,我决定使用逻辑回归来更容易地解释预测是如何建立的。为了使模型更容易理解并避免任何异常值问题,我在最终建模阶段将独立变量分成四分位数。最终的模型有七个变量,AUC 为 76%,正确预测流行话题的准确率为 73%。
赢家模型的洞察力告诉我:
- 持续时间较短的会谈比持续时间较长的会谈更有效
- 慢慢说更有效,这是通过计算每分钟的字数来衡量的,使用的是说话的总字数及其持续时间
- 在谈话过程中提问更有效。这是通过识别记录中的问号来衡量的
- 让观众发笑更有效。这是通过识别文字记录中笑声标题的出现来衡量的
对于这个最终模型,我还检查了最高和最低的预测分数,并查看了模型的排名。在这里,从左到右,我们从表现不好的谈话到表现较好的谈话(当然,不要低估得分最低的人!).
- 在排名最低的模特中,我发现伊森·祖克曼的“倾听全球之声”节目表现不佳。这个人在每一个变量上都得分最低(持续时间长,语速快,几乎没有笑的问题)
- 谷歌的谢尔盖·布林和拉里·佩奇得分也很低
- 杰夫·贝索斯关于“网络未来的电隐喻”的演讲也得分较低
- 在模特的谈话中得分最高的是斯蒂芬·霍金,他的谈话是“质疑宇宙”。这个演讲在模型的变量中得分很高,因为这个演讲是关于问很多问题的,并且说得很慢(因为辅助声音很慢!)
- 其中一个很好的演讲是来自的 Alan Smith 的演讲“为什么你应该热爱统计学”。这给了我希望,统计学家可以成为一个真正优秀的演讲者!
现在有了一个开发好的模型,为什么不让每个人都可以使用它呢!我用 Shiny 和 ShinyApps 部署了一个在线工具,你可以在这个网站的分析你的谈话部分使用。请按照说明,你需要做的只是把一个演讲,并会排名它会有多好,你可以做些什么来改善它!
我从这个项目中学到了什么?
我发现有一些因素可以帮助预测一个演讲是否会受欢迎,这些因素基于诸如提问、慢慢说、使用幽默和简洁等词语的使用。
我还了解到,使用工作中的副业项目也非常有趣,可以尝试和学习新的数据科学主题以及如何进行更好的演讲!
我也有机会在伦敦的两个不同场合展示这个项目。我已经在 2019 年 6 月 25 日的伦敦会议和 2019 年 9 月 11 日在伦敦举行的 EARL 2019 会议上介绍了它。这里有一些事件的照片
干杯,
爱德华多
原载于 2019 年 10 月 15 日http://www.speakthedata.com。
工作。旅行。大数据。重复
了解大数据如何成为旅游业引擎的燃料
简介
我选择了人迹较少的一个,
这让一切都不同了。”—作者罗伯特·弗罗斯特
甚至没有人知道罗伯特·弗罗斯特的这些标志性的诗句会成为旅游业成功的秘诀。大数据将为旅游业带来翻天覆地的变化。
随着每个行业都在走大数据分析的道路,旅游行业是较少走这条路的行业之一。随着大数据的出现,它正在将旅游业带到各个地方。大数据将为你提供前所未有的旅行体验。它将在旅游业中不遗余力。
让我们来一次短途旅行,看看大数据如何丰富您的旅行体验。
大数据是您完美的旅行伙伴
工作充实了你的口袋,旅行充实了你的灵魂,但还是有一些漏洞。大数据可以填补这些空白。旅行是为了探索不同的地方,而大数据是为了探索一系列很快将彻底改变旅游业的机会。大数据旨在确保所有沉迷于旅游的人获得无压力的旅行体验。
以下是大数据被证明对旅游业至关重要的几个领域
- 更好的客户体验
旅游业是与客户互动最多的行业。他们通过这些互动收集了大量的数据。这些数据是通过社交媒体平台、反馈、网站评论和服务使用数据收集的。这些数据有助于他们深入了解客户的问题和需求。使用这些数据,公司可以对他们目前提供的服务、即将过时的服务以及他们需要引入的最新服务做出精确的、数据驱动的决策。 - 价格政策 旅行者在计划旅行时考虑的最重要的部分是预算。为客户提供优化的价格解决方案是旅游公司建立忠诚客户群的全部需求。通过大数据分析获得的洞察将为公司提供竞争对手向其客户提供的价格和优惠,然后相应地设定价格。
- 实时协助 您的移动设备的位置数据可以为旅游企业提供一些宝贵的见解。一些旅游商业公司已经在利用这些实时数据为旅行者提供实时帮助和相关建议。
想象一下这样一种情况,智能手机中的旅行应用程序跟踪你的位置,并识别出你在一个受欢迎的旅游地点附近,因此在下一分钟它就开始向你发送附近酒店、餐馆等的特别优惠或交易。这可以帮助你省钱。此外,它还可以推荐一些附近值得一游的地方。我们现在有了自己的私人旅行助理。我们还需要什么?
大把花钱去旅游。Lol。
希思罗机场
乘飞机旅行省时,但有时也令人伤脑筋。多重安检、车厢座位拥挤、行李丢失和转机延误——这在旅程的每一点都考验着你的耐心。但大数据分析可以缓解这种痛苦,因为它将彻底改变你的旅行体验。
希斯罗机场 在哈佛商学院客座副教授 Yael Grushka-Cockayne 和其他一些来自伦敦大学学院的研究人员的合作下,他们决定根除痛苦的转接航班这一主要问题。
他们面临的主要问题是他们的遗留系统无法有效通信。
希思罗机场的利益相关方计划升级机场现有的数据系统,目的是更好地利用其客户的数据来增强转机乘客的体验,这些乘客占每年通过希思罗机场的所有旅客的三分之一。
他们的目标是开发一个既能识别转机乘客又能准确预测他们转机时间的系统。只有从多个来源收集数据,然后进行实时分析,才有可能做到这一点。
就在现场试验开始两年后,他们观察到了一些惊人的结果。利用大数据分析后,客流假设的平均绝对误差下降了 20%以上。从那以后,希思罗机场的利益相关方一直追求和信任大数据分析,胜过其他任何东西。
在希思罗机场完成这个项目后,Grushka-Cockayne 和她的团队收到了世界上一些最大的机场代表的邀请,如巴黎、新加坡、洛杉矶,更多的计划在他们自己的设施中实施类似的系统。
尾注
ig Data 的目的是促进旅游业的发展,并使其达到更高的水平。通过大数据分析获得的洞察力正在帮助旅游企业改善客户的旅行体验。即将获得旅游行业的窗口席位。
如果你是科学家,如何用 Python 组织代码
可报告、可重复使用和可再现的计算研究工作流程
如果你从事计算研究或数据科学,并且你没有计算机科学背景,你可能产生了惊人的科学知识,但是你写的代码并不完全符合学术标准。你可能需要一周的时间让你的脚本再次做同样的事情。即使你是一个经验丰富的程序员,你可能会发现很难同时做好开发人员和科学家的工作。
作为一名研究生,我自己也面临过这个挑战。虽然我参加了软件工程的课程,但我发现很难从交给我的研究问题中转移出来,去思考如何从我的代码中创建有用的工具。经过一些尝试和错误,我设计了一个方法来帮助我无缝地进行转换,现在我作为一名数据科学家在我的探索性工作中使用它。
在这篇文章中,我分享了我组织编码工作流的方式,给你一些提示和技巧,并向你展示我使用的工具堆栈。目标是使从实验到工具开发的过渡更加容易。
Jupyter 笔记本:数字实验室笔记本
为了让研究成为可重复的**,你需要记录你正在做的所有事情。如果您只想尽可能快地进行实验并进行特别分析,这可能是一个负担。**
我做实验用的工具是 Jupyter Notebook。交互式编程接口允许您即时检查您的代码做了什么,因此您可以一步一步地构建算法。此外,您可以使用 Markdown 单元格来写下您的想法和结论,以及代码。这使得记录和报告你所做的一切变得非常容易。
你可以在网上找到大量的 Jupyter 教程。我建议熟悉一下键盘快捷键**(它们在编辑器的帮助菜单下有描述),因为它们会显著加快你的工作。**
关于循环的实验
在数字实验中,循环实验变量非常简单。毕竟,计算机的能力来自于它们不断重复做事情的能力。
我在下面的代码中构建了正式的实验。
为了透明起见,我将当前实验的所有重要变量都放在文件开头的列表中。
这里要考虑的一件事是如何处理每次迭代的输出:你应该把它处理成一个可视化,计算一个度量还是存储它?应用和期望的报告形式决定了这种选择。
集中化和交叉引用
应该为每一个重要的实验创建一个笔记本文件,由你来决定这意味着什么。每当我使用不同的参数或新的做事方式重复一个实验时,我都会保存一个相关的标题和版本号。
这与版本控制不同,因为我保留了我工作的所有记录,而不仅仅是它的最新版本。而且,我把所有的实验放在同一个文件夹里,不管它们被分配到哪个项目。
Example of how to organize experiments in the same folder
虽然这会创建一大堆文件,但是通过按修改日期排序,您可以很容易地将相关的文件放在最上面。集中化通过简单的搜索就可以轻松找到特定的文件,而不是在你不记得逻辑的文件夹层次中穿行。
把东西放在一起的最大好处是你可以在笔记本内部和之间实现交叉引用**。这可以通过 Markdown 中的 html 链接来实现。**
若要创建对笔记本中某一节的引用,请在被引用部分之前的 Markdown 单元格中添加以下代码:
<a id='label_of_your_choice'></a><!--referenced section in file experiment00.ipynb-->
现在,在您希望显示引用链接的地方,编写以下内容之一:
[description](#label_of_your_choice) <!--to make link in the same notebook-->[description](experiment00.ipynb#label_of_your_choice) <!--to make link in another notebook-->
例如,[previous experiment] (experiment00.ipynb#label_of_your_choice)
产生链接:
Example of a cross reference to a previous experiment
现在,您可以一键直接跳转到旧实验中的引用部分。
报告应该只是你实验的最佳版本的总结和附带的评论。快速查找你的记录是你工作的可报告性的关键,如果交叉引用设置到位,这是一个点击笔记本的问题。
处理数据
有时您需要保存一些数据结果,用于报告、共享或在其他实验中使用。文件格式由您和具体情况决定。在这种情况下,我将数据保存在实验文件夹内的数据文件夹中,并为它们命名,以表明它们来自哪个实验以及该实验的版本号。
为了使事情易于处理,我在电子表格中记录日志,在那里我列出了我所有实验的数据输入和输出。
包装功能
您可能熟悉在脚本中编写函数,以使代码整洁,增强理解,最重要的是干(不要重复)。随着实验的发展,您的功能也在发展,在其中封装了越来越多的逻辑和其他功能。
如果你遵循了我的方法,你开始将你的实验分成多个笔记本文件,每个实验和它的版本一个。当你从一个实验带到另一个实验的(功能)包袱显著增长时,是时候开始考虑代码的可重用性了。如果您可以像处理其他 Python 库一样,将通过时间考验的函数顺利导入到您的代码中,这不是很好吗?
您应该简单地从在中保存函数开始。py 文件连同你的实验。你可以在你最喜欢的 IDE 中编辑这些文件(我用的是 VS 代码)。然后,您可以在文件名上使用导入语句,将所有这些功能放回您的实验中:
# if you save the experiment_with() function in the
# experiment_functions.py file in the same folder as
# your experiment, you can import it into your codefrom experiment_functions import experiment_with
默认隐藏复杂性
随着您的功能变得更加复杂和灵活,它们将需要大量的输入,这变得难以管理。幸运的是 Python 方便了设置函数参数的默认值。使用默认值可以大大加快实验过程,隐藏不必要的复杂性。这也有助于刚接触你的职能的人立即上手。****
有时您会遇到需要将默认值定义为其他参数的函数的情况。在这种情况下,我使用的策略是将默认值设置为 None** ,并立即在函数体中检查要设置的参数是否在调用时定义。如果不是,那么我相应地给它赋值。请参见下面的示例。**
面向对象编程的灵活性
当函数变得如此之大,以至于它们封装了整个算法,并且有许多参数需要优化时,函数的简单接口可能是不够的。在这种情况下,我更喜欢面向对象方法的灵活性。
通过将算法包装成对象**,您可以通过将参数定义为类的属性来随时改变参数。您可以设置非常具体的配置,并根据需要对算法进行微小的调整。**
类也可以用来构建特定于您的应用程序的数据结构并封装与它们相关的功能。使用面向对象的设计模式是一门完整的科学。
版本控制而不破坏可再现性
既然您的可重用函数位于与实验代码分离的模块中,保持事物的可处理性和可再现性可能会变得具有挑战性。您可能希望修改代码中可重用的部分,使它们及时变得更好。
这是再现性和可重用性发生冲突的时刻。如果你想用你的超级进化算法重现你两年前的实验,你可能会得到完全不同的结果。因此,您希望将您在实验中使用的模块的确切版本与您使用它们的笔记本文件保存在一起(除非您希望掩盖您过去做过的一些蠢事)。如果你为你所做的每一个修改保存一个编号的文件,并把它和实验记录在一起,事情会变得非常复杂。
进入版本控制。软件工程师通过版本控制和使用环境来保持事物的兼容性,从而使事物具有可复制性。完全相同的想法可以应用于我们的实验。您可以在改进函数和类时开始对它们进行版本控制,同时在实验文件中维护对相应版本的引用。
这是我的做法。我整理出那些。将文件复制到名为< project > _func 的项目文件夹中,在其中我建立了存储库并用 git 启动版本控制。如果你之前没用过 git,继续找 git 教程,然后再回来。****
每当我创建一个新的实验文件时,我都确保我已经提交了我正在使用的代码版本,并在实验文件顶部的一个单元格中写下以下几行:
%%bash
cd <project>_func # move inside the directory where you have the
# repository you need
git checkout <git commit id> # restore the version of the code
# you will use
然后在实验中,我根据需要导入我的函数。例如,假设我最近搬到了法国,现在我用法语写所有的报告。导入并运行该功能的最新版本
from magic_func.magic import do_some_magicdo_some_magic()
印刷品:
Salut Le Monde!
问题是,我有一个生成英文报告的旧实验脚本,我想重新运行它。幸运的是,我在实验笔记本的顶部引用了提交 id,如前面所示:
%%bash
cd magic_func
git checkout cff052f7c36bb09ccc101d9ce3652dce87f2acbc
在这个上下文中,上面的相同代码的输出是:
Hello World!
瞧啊。版本控制和编写良好的记录的魔力。
Python 包与世界共享
最终,你会想要打包。将文件复制到适当的 Python 包中**。然后,您将能够与其他人共享它们,并将它们安装在您在实验笔记本中使用的 Ipython 内核的环境中。**
可以跟着官方的 Python 打包指南学习如何打包代码和这个教程上传到 PyPi 上。要在 Jupyter Notebook 中使用您的软件包的特定版本,我建议您将其安装在 conda 环境中。然后,如果您遵循 nb_conda_kernels 扩展的安装说明,您就可以在那个环境中运行 Jupyter 内核。
从实验到单元测试
当你向你的包中添加功能时,你可以采用测试驱动的开发哲学**。它指出,在编写单元测试代码之前,应该先编写单元测试。通过这种方式,你可以使你想从你的包中实现的任务具体化。**
你可能已经在实验文件中摆弄过你的模块了。你可以在你的笔记本中设计测试,然后将它们的代码粘贴到单元测试的正式结构中。对于我的包,我使用 pytest 框架。
当你达到这一点时,你就不再只是一个实验主义者了。你也是一名开发者,你需要分享、维护和改进你创造的工具**。祝编码愉快!**
机器学习项目的工作流程
介绍
在这篇博客中,我们将讨论机器学习项目的工作流程,这包括从头开始构建合适的机器学习项目所需的所有步骤。
我们还将讨论数据预处理、数据清洗、特征探索和特征工程,并展示其对机器学习模型性能的影响。我们还将介绍一些有助于提高模型性能的预建模步骤。
完成任务所需的 Python 库:
1。Numpy
2。熊猫
3。Sci-kit Learn
4。Matplotlib
Overview of the Workflow of ML
了解机器学习工作流程
我们可以将机器学习工作流程定义为 3 个阶段。
- 收集数据
- 数据预处理
- 研究最适合该数据类型的模型
- 训练和测试模型
- 估价
好的,但是首先让我们从基础开始
什么是机器学习模型?
机器学习模型不过是一段代码;工程师或数据科学家通过数据训练让它变得聪明。因此,如果你给模型垃圾,你将得到垃圾作为回报,即训练好的模型将提供错误或错误的预测。
1.收集数据
收集数据的过程取决于我们想要做的项目的类型,如果我们想要做一个使用实时数据的 ML 项目,那么我们可以建立一个使用不同传感器数据的物联网系统。数据集可以从各种源收集,例如文件、数据库、传感器和许多其他这样的源,但是所收集的数据不能直接用于执行分析过程,因为可能有许多丢失的数据、非常大的值、无组织的文本数据或有噪声的数据。因此,要解决这个问题,需要做好数据准备。
我们也可以使用一些互联网上的免费数据集。 Kaggle 和 UCI 机器学习库 是制作机器学习模型使用最多的库。Kaggle 是访问量最大的网站之一,用于练习机器学习算法,他们还举办比赛,人们可以参加比赛,测试他们的机器学习知识。
2.数据预处理
数据预处理是机器学习中最重要的步骤之一。这是最重要的一步,有助于更准确地建立机器学习模型。在机器学习中,有一个 80/20 法则。每个数据科学家都应该花 80%的时间进行数据预处理,20%的时间实际执行分析。
什么是数据预处理?
数据预处理是清理原始数据的过程,即数据是在现实世界中收集的,并被转换为干净的数据集。换句话说,无论何时从不同来源收集数据,都是以原始格式收集的,这些数据对于分析是不可行的。因此,执行某些步骤将数据转换成一个小的干净数据集,这部分过程称为数据预处理。
我们为什么需要它?
众所周知,数据预处理是将原始数据清洗成干净数据的过程,这样可以用来训练模型。因此,我们肯定需要数据预处理,以从机器学习和深度学习项目中的应用模型中获得良好的结果。
大多数真实世界的数据是杂乱的,其中一些类型的数据是:
1.**缺失数据:**当缺失数据不是连续创建的,或者由于应用程序(IOT 系统)中的技术问题,可以找到缺失数据。
2.**噪声数据:**这种类型的数据也称为异常值,这可能是由于收集数据时的人为错误(人为手动收集数据)或设备的某些技术问题造成的。
3.**不一致的数据:**这种类型的数据可能是由于人为错误(名称或值的错误)或数据重复而收集的。
三种数据类型
1.数字,如收入、年龄
2.分类,如性别、国籍
3.序数,例如低/中/高
如何进行数据预处理?
这些是可用于转换原始数据的一些基本预处理技术。
1.**数据的转换:**我们知道机器学习模型只能处理数字特征,因此分类和序数数据必须以某种方式转换成数字特征。
2.**忽略缺失值:**每当我们在数据集中遇到缺失数据时,我们可以根据需要删除该行或该列数据。众所周知,这种方法很有效,但是如果数据集中有大量缺失值,就不应该执行这种方法。
3.**填充缺失值:**每当我们在数据集中遇到缺失数据时,我们可以手动填充缺失数据,通常使用平均值、中值或最高频率值。
4.**机器学习:**如果我们有一些缺失的数据,那么我们可以通过使用现有的数据来预测哪些数据应该出现在空的位置。
5.**异常值检测:**我们的数据集中可能存在一些错误数据,这些数据与数据集中的其他观察值有很大差异。【例:人的体重= 800 斤;由于打错了额外的 0]
3。研究最适合数据类型的模型
我们的主要目标是使用预处理的数据,尽可能训练出性能最佳的模型。
监督学习:
在监督学习中,人工智能系统提供了带标签的数据,这意味着每个数据都标记了正确的标签。
监督学习分为另外两类,即“分类和“回归”。
分类:
分类问题是当目标变量是分类的(即输出可以分类——属于 A 类或 B 类或其他)。
一个分类问题是当输出变量是一个类别时,例如“红色”或“蓝色”,“疾病”或“无疾病”或“垃圾邮件”或“非垃圾邮件”。
Classification | GIF: www.cs.toronto.edu
如上图所示,我们在图上绘制了两个类别,即红色和蓝色,分别表示为‘setosa flower’和‘versicolor flower’,我们可以将 X 轴想象为‘萼片宽度’,将 Y 轴想象为‘萼片长度’,因此我们尝试创建最佳拟合线,将两类花分开。
这些是一些最常用的分类算法。
- K-最近邻
- 朴素贝叶斯
- 决策树/随机森林
- 支持向量机
- 逻辑回归
回归:
而回归问题是当目标变量连续(即输出为数值)时。
Regression | GIF: techburst.io
如上图所示,我们可以想象图中的 X 轴是“考试成绩”,Y 轴代表“智商”。因此,我们试图在给定的图表中创建最佳拟合线,这样我们就可以使用这条线来预测给定数据中不存在的任何近似智商。
这些是一些最常用的回归算法。
- 线性回归
- 支持向量回归
- 决策树/随机森林
- 高斯渐进回归
- 集成方法
无监督学习:
在无监督学习中,人工智能系统呈现的是未标记、未分类的数据,系统的算法在没有事先训练的情况下对数据进行操作。输出取决于编码算法。让系统接受无监督学习是测试人工智能的一种方式。
无监督学习分为另外两类,即“聚类和“关联”。
聚类:
一组输入将被分成组。与分类不同的是,这些组事先并不知道,因此这通常是一项无人监督的任务。
Clustering
用于聚类的方法有:
- 高斯混合
- K-均值聚类
- 助推
- 层次聚类
- K 均值聚类
- 谱聚类
类别下的模型概述:
Overview of models
4.根据数据训练和测试模型
为了训练模型,我们最初将模型分成 3 个部分,即’训练数据’、验证数据和’测试数据。
您使用’训练数据集训练分类器,使用’验证集调整参数,然后在看不见的’测试数据集上测试您的分类器的性能。要注意的重要一点是,在训练分类器期间,只有训练和/或验证集是可用的。在训练分类器期间,不得使用测试数据集。测试集仅在测试分类器期间可用。
**训练集:**训练集是计算机学习如何处理信息的材料。机器学习使用算法来执行训练部分。用于学习的一组数据,即拟合分类器的参数。
**验证集:**交叉验证主要用在应用机器学习中,在看不见的数据上评估机器学习模型的技能。使用来自训练数据的一组看不见的数据来调整分类器的参数。
**测试集:**一组不可见的数据,仅用于评估完全指定的分类器的性能。
一旦数据被分成 3 个给定的部分,我们就可以开始训练过程。
在数据集中,训练集用于建立模型,而测试(或验证)集用于验证所建立的模型。训练集中的数据点从测试(验证)集中排除。通常一个数据集在每次迭代中分为训练集、验证集(有人用‘测试集’代替),或者在每次迭代中分为训练集、验证集、测试集。
该模型使用我们在第 3 步/第 3 点中选择的任何一个模型。一旦模型被训练,我们可以使用相同的训练模型来使用测试数据(即,看不见的数据)进行预测。一旦这样做了,我们就可以开发一个混淆矩阵,它告诉我们我们的模型训练得有多好。一个混淆矩阵有 4 个参数,分别是’真阳性’,,【真阴性’,,【假阳性】,假阴性’。我们更喜欢在真阴性和真阳性中获得更多的值,以获得更准确的模型。混淆矩阵的大小完全取决于类别的数量。
- **真阳性:**这些是我们预测为真且预测输出正确的情况。
- **真否定:**我们预测错误,预测输出正确。
- **误报:**我们预测为真,但实际预测输出为假。
- **假阴性:**我们预测的是假的,但实际预测的输出是真的。
我们还可以使用混淆矩阵来确定模型的准确性。
准确度=(真阳性+真阴性)/(类别总数)
即对于上面的例子:
准确度= (100 + 50) / 165 = 0.9090(准确度为 90.9%)
5.估价
模型评估是模型开发过程不可或缺的一部分。它有助于找到代表我们的数据的最佳模型,以及所选模型在未来的工作情况。
为了改进模型,我们可以调整模型的超参数,并尝试提高准确性,同时查看混淆矩阵,尝试增加真阳性和真阴性的数量。
结论
在这篇博客中,我们讨论了机器学习项目的工作流程,并给了我们一个应该如何解决这个问题的基本想法。
一个机器学习项目的工作流程实现:https://github.com/NotAyushXD/Titanic-dataset
ML 管道的工作流工具
Source: https://www.flickr.com/photos/rauckhaus/8638556209
第 5 章“生产中的数据科学”节选
Airflow 正在成为创作数据工程和模型管道工作流程的行业标准。我的书的这一章探讨了将一个运行在单个 EC2 实例上的简单管道带到一个负责调度任务的完全管理的 Kubernetes 生态系统的过程。这篇文章省略了 GKE 和 Cloud Composer 的全面管理解决方案的部分。
从初创公司到数万亿美元的公司,数据科学在帮助组织最大化…
leanpub.com](https://leanpub.com/ProductionDataScience)
模型管道通常是提供数据源(如湖泊和仓库)和数据存储(如应用程序数据库)的更广泛的数据平台的一部分。在构建管道时,能够安排任务运行、确保管道的所有依赖项都已完成,并在需要时回填历史数据是非常有用的。虽然可以手动执行这些类型的任务,但是已经开发了各种工具来改进数据科学工作流的管理。
在本章中,我们将探索执行一系列任务的批处理模型管道,以便为倾向模型训练和存储结果。这是一个与我们到目前为止所探索的部署不同的任务类型,我们所探索的部署侧重于将实时模型预测作为 web 端点。在批处理过程中,您执行一组存储模型结果的操作,这些结果稍后将由不同的应用程序提供。例如,批处理模型管道可以预测游戏中的哪些用户可能会流失,游戏服务器为开始会话的每个用户获取预测并提供个性化报价。
在为生产系统构建批处理模型管道时,确保管道问题得到快速解决是非常重要的。例如,如果模型管道由于数据库的上游故障而无法获取一组用户的最新数据,那么拥有一个系统是很有用的,该系统可以向拥有管道的团队发送警报,并且可以重新运行部分模型管道,以便解决先决数据或模型输出的任何问题。
工作流工具为管理模型管道中的这类问题提供了解决方案。使用工作流工具,您可以指定需要完成的操作,确定操作之间的依赖关系,然后安排工具执行的操作。工作流工具负责运行任务、提供资源和监控任务的状态。有许多用于构建工作流的开源工具,包括 AirFlow、Luigi、MLflow 和 Pentaho Kettle。我们将重点关注气流,因为它正在被各公司和云平台广泛采用,并且还提供完全受管理的气流版本。
在这一章中,我们将构建一个作为 Docker 容器运行的批处理模型管道。接下来,我们将使用 cron 安排任务在 EC2 实例上运行,然后使用 Kubernetes 探索 cron 的托管版本。在第三部分中,我们将使用 Airflow 来定义要执行的操作的图表,以便运行我们的模型管道,并探索 Airflow 的云产品。
5.1 SKLearn 工作流程
批处理模型管道的常见工作流是从数据湖或数据仓库中提取数据,根据历史用户行为训练模型,针对更近的数据预测未来用户行为,然后将结果保存到数据仓库或应用程序数据库。在游戏行业,这是一个我见过的用于建立购买可能性和流失可能性模型的工作流,其中游戏服务器使用这些预测根据模型预测向用户提供不同的待遇。通常像 sklearn 这样的库用于开发模型,PySpark 这样的语言用于扩展到完整的玩家基础。
对于模型管道来说,在管道可以在最近的数据上运行之前,通常需要在数据平台中运行其他 ETL。例如,数据平台中可能有一个上游步骤,将 json 字符串翻译成模式化的事件,用作模型的输入。在这种情况下,可能有必要在 json 转换过程出现问题的那天重新运行管道。在本节中,我们将通过使用静态输入数据源来避免这种复杂性,但是我们将探索的工具提供了处理这些问题所需的功能。
据我所知,在游戏行业部署的批处理模型管道通常有两种类型:
- **持久:**一个单独的训练工作流用于训练模型,而不是用于建立预测的模型。模型在训练运行之间保持不变,并加载到服务工作流中。
- **瞬态:**相同的工作流用于训练和服务预测,并且不是将模型保存为文件,而是为每次运行重建模型。
在这一节中,我们将构建一个瞬态批处理管道,每次运行都会重新训练一个新的模型。如果训练过程是重量级的,这种方法通常会导致使用更多的计算资源,但它有助于避免模型漂移的问题,我们将在第 11 章中讨论。我们将创建一个执行以下步骤的管道:
- 从 GitHub 获取数据集
- 训练逻辑回归模型
- 应用回归模型
- 将结果保存到 BigQuery
管道将作为执行所有这些步骤的单个 Python 脚本来执行。对于您希望使用跨多个任务的步骤的中间输出的情况,将管道分解为通过工作流工具(如 Airflow)集成的多个流程是很有用的。
我们将通过首先编写一个在 EC2 实例上运行的 Python 脚本来构建这个脚本,然后将脚本进行 Dockerize,以便我们可以在工作流中使用该容器。首先,我们需要安装一个库,用于将 Pandas 数据框写入 BigQuery:
pip install --user pandas_gbq
接下来,我们将创建一个名为pipeline.py
的文件,它执行上面确定的四个管道步骤…下面显示的脚本通过加载必要的库来执行这些步骤,将 CSV 文件从 GitHub 提取到 Pandas 数据框中,将数据框拆分为训练和测试组以模拟历史和最近的用户,使用训练数据集构建逻辑回归模型,为测试数据集创建预测,并将结果数据框保存到 BigQuery。
import pandas as pd
import numpy as np
from google.oauth2 import service_account
from sklearn.linear_model import LogisticRegression
from datetime import datetime
import pandas_gbq ***# fetch the data set and add IDs*** gamesDF = pd.read_csv("https://github.com/bgweber/Twitch/raw/
master/Recommendations/games-expand.csv")
gamesDF['User_ID'] = gamesDF.index
gamesDF['New_User'] = np.floor(np.random.randint(0, 10,
gamesDF.shape[0])/9)***# train and test groups*** train = gamesDF[gamesDF['New_User'] == 0]
x_train = train.iloc[:,0:10]
y_train = train['label']
test = gameDF[gamesDF['New_User'] == 1]
x_test = test.iloc[:,0:10]***# build a model*** model = LogisticRegression()
model.fit(x_train, y_train)
y_pred = model.predict_proba(x_test)[:, 1]***# build a predictions data frame*** resultDF = pd.DataFrame({'User_ID':test['User_ID'], 'Pred':y_pred})
resultDF['time'] = str(datetime. now())***# save predictions to BigQuery*** table_id = "dsp_demo.user_scores"
project_id = "gameanalytics-123"
credentials = service_account.Credentials.
from_service_account_file('dsdemo.json')
pandas_gbq.to_gbq(resultDF, table_id, project_id=project_id,
if_exists = 'replace', credentials=credentials)
为了模拟真实世界的数据集,脚本为每条记录分配一个User_ID
属性,它代表一个惟一的 ID 来跟踪系统中的不同用户。该脚本还通过分配一个New_User
属性将用户分为历史组和最近组。为每个最近的用户构建预测后,我们创建一个包含用户 ID、模型预测和时间戳的结果数据框。为了确定管道是否成功完成,对预测应用时间戳是很有用的。若要测试模型管道,请在命令行上运行以下语句:
export GOOGLE_APPLICATION_CREDENTIALS=
**/**home/ec2-user/dsdemo.json
python3 pipeline.py
如果成功,该脚本应该在 BigQuery 上创建一个名为dsp_demo
的新数据集,创建一个名为user_users
的新表,并用用户预测填充该表。要测试 BigQuery 中是否实际填充了数据,请在 Jupyter 中运行以下命令:
from google.cloud import bigquery
client = **bigquery.Client**()sql = "select * from dsp_demo.user_scores"
**client.query**(sql)**.to_dataframe**()**.head**()
这个脚本将设置一个连接到 BigQuery 的客户机,然后显示提交给 BigQuery 的查询结果集。您还可以浏览到 BigQuery web UI 来检查管道的结果,如图 5.1 所示。我们现在有一个脚本,可以获取数据,应用机器学习模型,并将结果保存为单个过程。
FIGURE 5.1: Querying the uploaded predictions in BigQuery.
使用许多工作流工具,您可以直接运行 Python 代码或 bash 脚本,但是最好为执行脚本建立隔离的环境,以避免不同库和运行时的依赖冲突。幸运的是,我们在第 4 章中探索了一个工具,可以将 Docker 与工作流工具结合使用。将 Python 脚本包装在 Docker for workflow tools 中很有用,因为您可以添加可能没有安装在负责调度的系统上的库,可以避免 Python 版本冲突的问题,并且容器正在成为工作流工具中定义任务的常用方式。
为了将我们的工作流容器化,我们需要定义一个 Dockerfile,如下所示。因为我们正在从头构建一个新的 Python 环境,所以我们需要安装 Pandas、sklearn 和 BigQuery 库。我们还需要将 EC2 实例中的凭证复制到容器中,这样我们就可以运行export
命令向 GCP 进行身份验证。这适用于短期部署,但是对于长期运行的容器,最好在实例化的容器中运行导出,而不是将静态凭证复制到映像中。Dockerfile 列出了运行脚本所需的 Python 库,复制执行所需的本地文件,导出凭证,并指定要运行的脚本。
FROM ubuntu:latest
MAINTAINER Ben Weber RUN apt-get update \
&& apt-get install -y python3-pip python3-dev \
&& cd /usr/local/bin \
&& ln -s /usr/bin/python3 python \
&& pip3 install pandas \
&& pip3 install sklearn \
&& pip3 install pandas_gbq
COPY pipeline.py pipeline.py
COPY /home/ec2-user/dsdemo.json dsdemo.jsonRUN export GOOGLE_APPLICATION_CREDENTIALS=**/**dsdemo.jsonENTRYPOINT ["python3","pipeline.py"]
在将该脚本部署到生产环境之前,我们需要从该脚本构建一个映像,并测试一个示例运行。下面的命令显示了如何从 Docker 文件构建映像,列出 Docker 映像,并运行模型管道映像的实例。
sudo docker image build -t "sklearn_pipeline" .
sudo docker images
sudo docker run sklearn_pipeline
运行最后一个命令后,容器化管道应该更新 BigQuery 中的模型预测。我们现在有了一个模型管道,可以作为单个 bash 命令运行,我们现在需要安排它以特定的频率运行。出于测试目的,我们将每分钟运行一次脚本,但实际上模型通常每小时、每天或每周执行一次。
5.2 Cron
模型管道的一个常见需求是以固定的频率运行任务,例如每天或每小时。Cron 是一个为运行 Linux 操作系统的机器提供调度功能的实用程序。您可以使用 crontab 实用程序设置一个计划任务,并分配一个 cron 表达式来定义运行该命令的频率。Cron 作业直接在使用 cron 的机器上运行,并且可以利用安装在系统上的运行时和库。
在生产级系统中使用 cron 有许多挑战,但是这是开始调度少量任务的一个很好的方法,并且学习许多调度系统中使用的 cron 表达式语法也很有好处。cron 实用程序的主要问题是它运行在一台机器上,不能与版本控制等工具进行本地集成。如果您的机器停机,那么您需要在一台新机器上重新创建您的环境并更新您的 cron 表。
cron 表达式定义了运行命令的频率。它是一个由 5 个数字组成的序列,定义了不同时间粒度下的执行时间,并且可以包含通配符,以便总是在特定时间段内运行。下面的代码片段显示了一些示例表达式:
***# run every minute*** * * * * * ***# Run at 10am UTC everyday*** 0 10 * * * ***# Run at 04:15 on Saturday*** 15 4 * * 6
在开始使用 cron 时,最好使用工具来验证您的表达式。Cron 表达式用于 Airflow 和许多其他调度系统。
我们可以使用 cron 来安排我们的模型管道以固定的频率运行。要计划运行命令,请在控制台上运行以下命令:
crontab -e
该命令将打开 cron 表格文件,在vi
中进行编辑。要安排管道每分钟运行一次,请将以下命令添加到文件中并保存。
***# run every minute*** * * * * * sudo docker run sklearn_pipeline
退出编辑器后,cron 表将使用要运行的新命令进行更新。cron 语句的第二部分是要运行的命令。在定义要运行的命令时,包含完整的文件路径非常有用。使用 Docker,我们只需要定义要运行的映像。要检查脚本是否真的在执行,浏览到 BigQuery UI 并检查user_scores
模型输出表上的time
列。
我们现在有了一个实用程序,可以定期调度我们的模型管道。然而,如果机器停机,那么我们的管道将无法执行。为了处理这种情况,最好探索具有 cron 调度功能的云产品。
5.3 工作流程工具
Cron 对于简单的管道是有用的,但是当任务依赖于其他可能失败的任务时,就会遇到挑战。为了帮助解决这个问题,任务有依赖关系,只有部分管道需要重新运行,我们可以利用工作流工具。Apache Airflow 是目前最流行的工具,但也有其他开源项目提供类似的功能,包括 Luigi 和 MLflow。
在一些情况下,工作流工具比直接使用 cron 更有优势:
- **依赖关系:**工作流工具定义了操作的图形,这使得依赖关系显式化。
- Backfills: 可能有必要在一系列不同的日期对旧数据运行 ETL。
- **版本化:**大多数工作流工具都集成了版本控制系统来管理图表。
- **告警:**这些工具可以在出现故障时发出邮件或者生成页面任务告警。
工作流工具在不同团队安排任务的环境中特别有用。例如,许多游戏公司都有数据科学家来安排模型管道,这些管道依赖于由单独的工程团队安排的 ETL。
在本节中,我们将安排任务使用托管的 Airflow 运行 EC2 实例,然后在 GCP 上探索一个完全托管的 Airflow 版本。
阿帕奇气流
Airflow 是一款开源工作流工具,最初由 Airbnb 开发,于 2015 年公开发布。它有助于解决许多公司面临的一个挑战,即调度具有许多相关性的任务。该工具的核心概念之一是定义要执行的任务以及这些任务之间关系的图表。
在 Airflow 中,一个图被称为 DAG,它是有向无环图的缩写。DAG 是一组要执行的任务,其中每个任务有零个或多个上游依赖项。其中一个限制是不允许循环,两个任务在上游相互依赖。
Dag 是使用 Python 代码设置的,这是与 Pentaho Kettle 等其他工作流工具的区别之一,Pentaho Kettle 以 GUI 为中心。气流方法被称为“代码配置”,因为 Python 脚本定义了要在工作流图中执行的操作。使用代码而不是 GUI 来配置工作流是有用的,因为这使得与版本控制工具(如 GitHub)的集成变得更加容易。
要开始使用 Airflow,我们需要安装库,初始化服务,并运行调度程序。要执行这些步骤,请在 EC2 实例或您的本地计算机上运行以下命令:
export AIRFLOW_HOME=**~/**airflow
pip install --user apache-airflow
airflow initdb
airflow scheduler
Airflow 还提供了一个 web 前端,用于管理已调度的 Dag。要启动此服务,请在同一台计算机上的新终端中运行以下命令。
airflow webserver -p 8080
这个命令告诉 Airflow 在端口 8080 上启动 web 服务。您可以在本机的这个端口打开网页浏览器,查看气流的网页前端,如图 5.3 所示。
FIGURE 5.3: The Airflow web app running on an EC2 instance.
Airflow 预装了许多示例 Dag。对于我们的模型管道,我们将创建一个新的 DAG,然后通知 Airflow 更新。我们将使用以下 DAG 定义创建一个名为sklearn.py
的文件:
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import datetime, timedeltadefault_args = {
'owner': 'Airflow',
'depends_on_past': False,
'email': 'bgweber@gmail.com',
'start_date': **datetime**(2019, 11, 1),
'email_on_failure': True,
}dag = **DAG**('games', default_args=default_args,
schedule_interval="* * * * *")t1 = **BashOperator**(
task_id='sklearn_pipeline',
bash_command='sudo docker run sklearn_pipeline',
dag=dag)
这个 Python 脚本中有几个步骤需要调用。该脚本使用一个Bash
操作符来定义要执行的动作。Bash 操作符被定义为脚本中的最后一步,它指定要执行的命令。DAG 用许多定义工作流设置的输入参数来实例化,例如当任务失败时向谁发送电子邮件。cron 表达式被传递给 DAG 对象来定义任务的调度,DAG 对象被传递给 Bash 操作符来将任务与这个操作图相关联。
在将 DAG 添加到 airflow 之前,检查代码中的语法错误是很有用的。我们可以从终端运行以下命令来检查 DAG 的问题:
python3 sklearn.py
此命令不会运行 DAG,但会标记脚本中存在的任何语法错误。要使用新的 DAG 文件更新 Airflow,请运行以下命令:
airflow list_dags-------------------------------------------------------------------
DAGS
-------------------------------------------------------------------
games
此命令会将 DAG 添加到 Airflow 中的工作流程列表。要查看 Dag 列表,请导航到 Airflow web 服务器,如图 5.4 所示。web 服务器将显示 DAG 的时间表,并提供工作流过去运行的历史记录。要检查 DAG 是否真的在工作,请浏览 BigQuery UI 并检查新的模型输出。
FIGURE 5.4: The sklearn DAG scheduled on Airflow.
我们现在已经启动并运行了一个气流服务,我们可以用它来监控工作流的执行。这种设置使我们能够跟踪工作流的执行情况,填补数据集中的任何空白,并为关键工作流启用警报。
Airflow 支持各种操作,许多公司编写了供内部使用的自定义操作符。在我们的第一个 DAG 中,我们使用 Bash 操作符来定义要执行的任务,但是其他选项也可用于运行 Docker 映像,包括 Docker 操作符。下面的代码片段展示了如何将 DAG 改为使用 Docker 操作符而不是 Bash 操作符。
from airflow.operators.docker_operator import DockerOperatort1 = **DockerOperator**(
task_id='sklearn_pipeline',
image='sklearn_pipeline',
dag=dag)
我们定义的 DAG 没有任何依赖关系,因为容器执行模型管道中的所有步骤。如果我们有一个依赖项,比如在运行模型管道之前运行一个sklearn_etl
容器,我们可以使用如下所示的set_upstrean
命令。这个配置设置了两个任务,其中管道任务将在 etl 任务完成后执行。
t1 = **BashOperator**(
task_id='sklearn_etl',
bash_command='sudo docker run sklearn_etl',
dag=dag)t2 = **BashOperator**(
task_id='sklearn_pipeline',
bash_command='sudo docker run sklearn_pipeline',
dag=dag)**t2.set_upstream**(t1)
Airflow 提供了一组丰富的功能,我们只是触及了该工具所提供功能的皮毛。虽然我们已经能够通过托管和托管云产品来安排模型管道,但通过气流来安排任务对于改进监控和版本控制非常有用。随着时间的推移,工作流工具的前景将会改变,但是许多气流的概念将会转化为这些新的工具。
5.4 结论
在本章中,我们探索了一个批处理模型管道,用于将机器学习模型应用于一组用户,并将结果存储到 BigQuery。为了使管道可移植,以便我们可以在不同的环境中执行它,我们创建了一个 Docker 映像来定义管道所需的库和凭证。然后,我们使用批处理命令、cron 和 Airflow 在 EC2 实例上运行管道。我们还使用 GKE 和 Cloud Composer 通过 Kubernetes 运行容器。
工作流工具的设置可能很繁琐,尤其是在安装集群部署时,但是它们提供了许多优于手动方法的优点。其中一个主要优势是能够将 DAG 配置作为代码进行处理,从而支持工作流的代码审查和版本控制。获得配置为代码的经验是很有用的,因为这是对另一个概念“基础架构为代码”的介绍,我们将在第 10 章中探讨。
本·韦伯是 Zynga 的一名杰出的数据科学家。我们正在招聘!
从远程机器上处理 Databricks 集群
简单的方法。
Databricks.com
想象一下下面的场景,您有一台专用的机器,并且希望在 Databricks 集群上远程运行您的作业。如果您在 Databricks 平台上工作,通常在 Databricks 集群上运行作业是相当容易的,因为集群已经配置好了。但是,从远程机器上运行作业需要一些设置。在这篇文章中,我将解释如何成功地远程运行集群作业。
就可用性而言,配置很简单,以前我必须在我的机器上安装 PySpark,这需要在 shell 中进行大量的修改。此外,这并没有给我在 Databricks 集群上运行作业的能力。
以下是使用 Databricks 文档的总结。它几乎被埋没了,没有立即在谷歌上出现。所以,希望这个帖子有所帮助。
安装和配置
1.pip 卸载 pyspark
2。pip 安装-用户数据块-cli
3。pip install-user-U data bricks-connect = = 5.5。*
确保你安装的版本和你的集群一样,对我来说,是 5.5。您可以在集群页面上查看它们,查看运行时列,如图 1 所示。
Figure 1: Clusters page, Logs monitoring is using runtime version 3.1.
注意:如果您的运行时是如图 3 所示的用户 toke。
3.集群 ID:您创建的集群的 ID。您可以从 URL 获取集群 ID。这里,橙色框 中的集群 ID 是 ,如图 4 所示。
Figure 2: special configuration for runtime<5.3.
- 安装
配置data bricks-connect客户端将非常容易,您需要接受协议,输入 url(包括 https://),,)输入令牌,输入集群 ID 并按两次 enter 键以接受 Org ID 和端口问题的默认值。
Figure 3: User Token Creation, Databricks Documentation.
你接受上述协议吗?[y/N] y
设置新的配置值(将输入留空以接受默认值):
数据块主机[无当前值,必须以 https://]开头:<数据块-url >
数据块令牌[无当前值]: <数据块-令牌>
集群 id(例如 0221-009411-jello 819)[无当前值]: <集群 id >
组织 IDo = URL 中的 orgId)[0]:
Port【15001】:
Figure 4: Cluster ID
下一步是测试连接客户机。
数据块-连接配置
对我来说,这导致了一个错误:
/home/username/。local/lib/python 3.5/site-packages/pyspark/bin/spark-class:第 71 行:/usr/lib/java/bin/java:没有这样的文件或目录
我通过添加安装 java 8 并在~/中添加下面一行来解决这个问题。bashrc
sudo 安装 openjdk-8-jdk
导出 JAVA_HOME=/usr/
然后:
来源~/。bashrc
测试
接下来,您需要运行以下命令:
数据块连接测试
如果一切工作正常,它将参与集群,在启动它并进行几次测试后,您应该准备好从您的机器向您的集群发送作业。
密码
从 pyspark.sql 导入 spark session
spark = spark session . builder . getor create()
从 IPython.core.magic 导入 line_magic,line_cell_magic,magics_class
@ Magics _ class
class databrickconnectmagics(Magics):
@ line _ cell _ magic
def SQL(self,Line,cell = None):
if cell and Line:
raise value error(" Line 必须为空才能进行单元格魔术",Line)
try:
from autovizwidget . widget . utils import display _ data frame
import error:
print(“请运行pip install autovizwidget
以启用可视化小部件。”)
display _ data frame = lambda x:x
返回 display _ data frame(self . get _ spark()。sql(单元格或行)。toPandas())def get _ spark(self):
user _ ns = get _ ipython()。user_ns
如果 user_ns 中的" spark “:
返回 user_ns[“spark”]
else:
from pyspark . SQL 导入 spark session
user _ ns[” spark “]= spark session . builder . getorcreate()
返回 user _ ns[” spark "]IP = get _ ipython()
IP . register _ magics(databrickconnectmagics)从 pyspark.sql 导入 spark session
spark = spark session
。构建器
。getOrCreate()print(" Testing simple count ")
Spark 代码将在 Databricks 集群上执行。
打印(spark.range(1000)。count())
输出应该是:
测试简单计数
1000非常感谢你阅读这篇文章,希望它能帮助你设置你的系统而不会有太多的问题。
参考
数据库认证
- 所以
- 安装 java 8
- 找到 java 主页
- Ori Cohen 博士拥有计算机科学博士学位,主要研究机器学习。他是 TLV 新遗迹公司的首席数据科学家,从事 AIOps 领域的机器和深度学习研究。
- install java 8
- Find java home
Dr. Ori Cohen has a Ph.D. in Computer Science with a focus on machine-learning. He is a lead data-scientist at New Relic TLV, doing machine and deep learning research in the field of AIOps.