精华内容
下载资源
问答
  • 1、word2vector简介 2013年,Google团队发表了word2vec工具。word2vec工具主要包含两...2、词向量 比如有一个城市的词汇表(北京,上海,宁夏,纽约,巴黎,,,,,南京),One-Hot Encoder按照如下方式表示: 杭州

    1、word2vector简介

    2013年,Google团队发表了word2vec工具。word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW),以及两种高效训练的方法:负采样(negative sampling)和层序softmax(hierarchical softmax)。

    2、词向量

    比如有一个城市的词汇表(北京,上海,宁夏,纽约,巴黎,,,,,南京),One-Hot Encoder按照如下方式表示:

    杭州 [0,0,0,0,0,0,0,1,0,……,0,0,0,0,0,0,0]
    
    上海 [0,0,0,0,1,0,0,0,0,……,0,0,0,0,0,0,0]
    
    宁波 [0,0,0,1,0,0,0,0,0,……,0,0,0,0,0,0,0]
    
    北京 [1,0,0,0,0,0,0,0,0,……,0,0,0,0,0,0,0]
    

    比如上面的这个例子,在语料库中,杭州、上海、宁波、北京各对应一个向量,向量中只有一个值为1,其余都为0。但是使用One-Hot Encoder有以下几个问题。一方面,城市编码是随机的,向量之间相互独立,看不出城市之间可能存在的关联关系。其次,向量维度的大小取决于语料库中字词的多少。如果将世界所有城市名称对应的向量合为一个矩阵的话,那这个矩阵过于稀疏,并且会造成维度灾难。使用分布式词向量(distributed word Vector Representations)可以有效解决这个问题。Word2Vec可以将One-Hot Encoder转化为低维度的连续值,也就是稠密向量,并且其中意思相近的词将被映射到向量空间中相近的位置。

    分布式词向量是一个固定大小的实数向量,事前确定它的大小比如N=300维或者N=1000维,每个元素都是一个实数,实数的具体值是词库里面每个词通过不同的贡献得来的,所以叫分布式的。而word2vec就是一种学习这个分布式词向量的算法。向量的余弦夹角可以代表词语之间的相似度。这种方法相较于One-hot方式另一个区别是维数下降极多,对于一个10W的词表,我们可以用n维(n可以随意设置,比如:n=10)的实数向量来表示一个词,而One-hot得要10W维。

    3、模型简介

    one-hot向量作为word2vec的输入,通过word2vec训练低维词向量(word embedding)。

    word2vec模型其实就是简单化的神经网络。如图:
    在这里插入图片描述
    输入层:One-Hot Vector
    隐藏层:没有激活函数,也就是线性的单元。
    输出层:维度跟输入层的维度一样,用的是Softmax回归。

    4、CBOW

    CBOW(Continuous Bag-of-Word Model)又称连续词袋模型,是一个三层神经网络。如下图所示,该模型的特点是输入已知上下文,输出对当前单词的预测。如图:
    在这里插入图片描述
    更详细的图:
    在这里插入图片描述
    网络计算步骤:

    1. 输入层:上下文单词的onehot。(假设单词向量空间dim为V,上下文单词个数为C)
    2. 所有onehot分别乘以共享的输入权重矩阵W(W为V*N矩阵,N为自己设定的数,需要初始化权重矩阵W)
    3. 所得的向量 (注意onehot向量乘以矩阵的结果) 相加求平均作为隐层向量, size为1*N.
    4. 乘以输出权重矩阵W’ {N*V}
    5. 得到向量 {1*V} 激活函数处理得到V-dim概率分布 {PS: 因为是onehot嘛,其中的每一维都代表着一个单词},概率最大的index所指示的单词为预测出的中间词(target word)
    6. 与true label的onehot做比较,误差越小越好。loss function(一般为交叉熵代价函数)

    说明:w是输入层到隐藏层的权重矩阵,维度是{V*N},W’是隐藏层到输出层的权重矩阵,维度是{N * V}.

    所以,需要定义loss function(一般为交叉熵代价函数),采用梯度下降算法更新W和W’。训练完毕后,输入层的每个单词与矩阵W相乘得到的向量的就是我们想要的词向量(word embedding),这个矩阵(所有单词的word embedding)也叫做look up table(其实这个look up table就是矩阵W自身),也就是说,任何一个单词的onehot乘以这个矩阵都将得到自己的词向量。有了look up table就可以免去训练过程直接查表得到单词的词向量了。

    看个例子:

    句子:I drink coffee everyday!
    在这里插入图片描述
    softmax公式:
    softmax公式
    这里,drink稀疏的表示[0 1 0 0]经过embedding之后变为了稠密的矩阵[2 2 1].

    5、skip-gram

    Skip-gram与CBOW恰恰相反,即已知当前词语,预测上下文。如图:
    在这里插入图片描述
    详细图:
    在这里插入图片描述

    eg: 句子:“The quick brown fox jumps over lazy dog”,我们设定skip_window的参数,它代表着我们从当前input word的一侧(左边或右边)选取词的数量,设定我们的窗口大小为2(skip_window=2),也就是说我们仅选输入词前后各两个词和输入词进行组合。下图中,蓝色代表input word,方框内代表位于窗口内的单词。Training Samples(输入, 输出)。
    在这里插入图片描述
    比如:训练样本取(The,quick),根据句子[The,quick, brown ,fox ,jumps, over,the, lazy, dog],它们被编码成one-hot向量后,The是(1,0,0,0,0,0,0,0,0),quick是(0,1,0,0,0,0,0,0,0)。因此输入是1 * 9维的one-hot向量The(1,0,0,0,0,0,0,0,0),乘以9 * 5(9是单词个数,5是随机取的数字)的输入层到隐藏层的权重矩阵W,得到1 * 5维的隐藏层神经元向量,该神经元向量乘以5 * 9的权重矩阵,得到1*9的向量,对该向量的每个元素值做softmax函数运算,得到另一个1 * 9的向量,该向量的每个值代表每个词的概率,而且之和为1,每个值的大小是什么意思呢?这个向量是the这个词经过训练得到的输出,该输出是一个包含9个概率值分布的向量,向量中的每个概率值代表着对应词汇表中9个单词的概率大小,理想情况是这个向量等于给定的labels向量quick,但由于softmax函数的特性,这种情况永远达不到,所以只能通过反向传播的过程让它们不断逼近。

    具体步骤如下:
    第一步,输入层到隐藏层:
    在这里插入图片描述

    该图输入的The的one-hot向量称为x,乘以9*5维的权重矩阵W,得到5维的隐藏层神经单元,每个值代表一个神经元,看下计算过程,计算后得到的隐藏层神经元的值其实就是W矩阵的第1行。因为每次输入都是像The这样的向量,one-hot向量中第几列值为1,隐藏层就是W矩阵的第几行。因此对任何输入而言,隐藏层就是W矩阵的某一行,所以:每个词的one-hot向量输入到隐藏层后,隐藏层的值就是权重矩阵W某一行的值,该行的值也就是该词的词向量,因此我们要更新迭代的模型就是W矩阵(即每个词的词向量),w矩阵即是我们模型输出的最终结果
    第二步,隐藏层到输出层:
    在这里插入图片描述

    步骤1计算得到的1 * 5维矩阵,作为隐藏层神经元的值[3,0,5,2,4],再乘以一个5 * 9维的权重矩阵Q,得到上述等式右边1 * 9维的矩阵Z[z1,z2,…,z9],对该矩阵的每个值作softmax函数运算,得到Z’[z’1,z’2,…,z’9],其中z’1+z’2+…+z’9 = 1, 这9个z’值,最大那个,就对应着The这个词本应该的输出,而The的labels是quick,quick这个词的one-hot向量为(0,1,0,0,0,0,0,0,0),那么我们训练并且迭代W权重矩阵的目的就是使z’2这个值最大。同理对应其他单词输入输出对(The, brown),(quick,The)等等,采用同样的训练过程,可以不断的调整输入层到隐藏层的W向量9 * 5中每行的值,一共9行9个主要词汇,因此得到9个词向量。

    小结:无论是CBOW还是skip-gram,最终我们需要的是训练出来的输入层到隐藏层的权重矩阵w,w每行对应每个词的词向量。

    6、训练及优化

    在第一部分讲解完成后,我们会发现Word2Vec模型是一个超级大的神经网络(权重矩阵规模非常大)。

    举个栗子,我们拥有10000个单词的词汇表,我们如果想嵌入300维的词向量,那么我们的输入-隐层权重矩阵和隐层-输出层的权重矩阵都会有 10000 x 300 = 300万个权重,在如此庞大的神经网络中进行梯度下降是相当慢的。更糟糕的是,你需要大量的训练数据来调整这些权重并且避免过拟合。百万数量级的权重矩阵和亿万数量级的训练样本意味着训练这个模型将会是个灾难。

    下面主要介绍两种方法优化训练过程。
    1.负采样(negative sampling)
    负采样(negative sampling)解决了这个问题,它是用来提高训练速度并且改善所得到词向量的质量的一种方法。不同于原本每个训练样本更新所有的权重,负采样每次让一个训练样本仅仅更新一小部分的权重,这样就会降低梯度下降过程中的计算量。至于具体的细节我在这里就不在介绍了。
    2.层序softmax(Hierarchical Softmax)也是解决这个问题的一种方法。

    参考:
    https://blog.csdn.net/lilong117194/article/details/81979522
    https://blog.csdn.net/free356/article/details/79445895
    https://blog.csdn.net/mylove0414/article/details/61616617
    https://blog.csdn.net/yu5064/article/details/79601683
    https://zhuanlan.zhihu.com/p/29020179

    展开全文
  • 向量语义模型

    2021-02-05 12:43:14
    上下文(context)对于计算词(word)的相关性来说是一个很重要的概念。出现在相似上下文的词更倾向具有相似的含义。词的分布相似性和含义相似性之间的关联称为分布假设(distributional ...本文重点阐述向量语义(vector s

    上下文(context)对于计算词(word)的相关性来说是一个很重要的概念。出现在相似上下文的词更倾向具有相似的含义。词的分布相似性和含义相似性之间的关联称为分布假设(distributional hypothesis)。这个假设是于19世纪50年代语言学家们提出来的。他们发现同义词(如oculist和eye-doctor)更容易出现在相同环境中(附近的词如eye和examined)。并且(Harris,1954)认为两个词间的含义差异值大致等于其环境中的差异值。

    本文重点阐述向量语义(vector semantics)模型,通过从文本的分布中直接学习词义表示来实现分布假设。词表示(word representation)也是表示学习(representation learning)的一个例子,从输入文本中无监督地自动学习有用的表示,而不是借助特征工程(feature engeneering)手动创建这些表示。尽管特征工程也是近年来NLP研究的一个重要关注点。这种表示方法可以用在所有利用语义的NLP应用中,并且是更强大的contextualized word representations如ELMo和BERT的基础。下面首先介绍中词义(word sense)的本质是什么,从而更好理解向量语义(vector semantics)模型及其拓展。

    Mind Map

    所有NLP任务的首要共同点是我们将词进行表示作为模型的输入。大量早期的NLP工作都是将词看作原子性的符号。为了使NLP任务表现的更好,我们首先表示词之间的相同和不同。而通过词向量(word vectors/word embeddings)就可以很好的刻画出来。下面是本文所述内容(由于篇幅原因,除阴影部分外)。
    在这里插入图片描述

    Lexical Semantics

    **在许多传统的NLP应用中,单词的唯一表示形式是字符串,或者是词汇表中的索引。**这种表达方式与哲学中的传统并没有太大的不同,也许在逻辑入门课上见过,单词的意思通常只是用大写字母拼写单词;表示“dog”是DOG,“cat”是CAT的意思)。但是这远远不够,我们需要一个词义模型来刻画词义之间的关系,从而帮助处理含义相关(meaning-related)的工作,比如问题回答(question-answersing)、总结(summarization)、释义(paraphrase)、抄袭检测(plagiarism)和对话(dialogue)等。

    本部分详细地从语言学的角度去了解词义(word meaning)的相关研究结果,也就是lexical semantics。如果觉得本部分对于自己可以不用去了解,可以只粗看本部分列出的标题或者直接跳过就可以了。

    1. Lemmas and Senses
      mouse: 词条(lemma or citation form)
      mice: 词条的特殊形式如单复数、过去式等称为单词形式(wordforms)
      rodent/cursor control device: 一个词条可有多个词义(word sense)
    2. Relationships between senses
      同义词(synonyms): 我们都知道含义相同或基本相同为同义词。语言学中更正式的定义是两个词在任意句子中可相互替代且不改变句子的真值,则这两个词具有相同的命题含义(propositional meaning)。但事实上没有含义绝对相同的两个词。语义学中的一个基本原则叫对比原则(principle of contrast):语言形式的差异至少与含义上的差异有关。比如 H 2 H_2 H2O虽然和water都是“水”的意思,但前者更多用于科学资料中,用在某份远行指南中就不合适了。因此我们常说的同义词只是去通常描述词义大致相同的情况。
      反义词(antonym)
      上义词(hypernym)
      下义词(hyponym):和上义词一起,其实描述的是一种IS-A的词等级关系。
    3. Relationships between words
      ♦ Word Similarity
      尽管词没有很多同义词,但是大多数词都有很多相似词(similar words)。比如cat和dog虽然不是同义词但是却是相似词。从同义词到相似性,从讨论词义之间的关系(如同义词)到讨论词与词之间的关系(如相似性)是很有帮助的。处理单词时避免了对词义的特定表示,这将简化我们的任务。从词相似性到短语相似性到句子相似性,这对处理大型的语义任务是很有帮助的。
      词相似性描述共有某些特征(share some features)的词。
      比如在SimLex-999数据集中(Hill,2015)给出了0-10的范围值来判定词相似度。
      ♦ Word Relatedness
      词关联性描述
      共同出现在同一语境中或相同语义场(co-participate in a shared environment or the semantic field)中

      一个semantic field是一组包含特定语义域的词,它们之间具有结构化关系。比如hospital的语义场包含的词有surgeon、nurse、scalpel等。
      一个semantic frame是一组表示特定类型事件中的角度或语义框架参与者的单词。比如commercial transaction的semantic frame中包含的词有buyer、seller、goods、money等。
    4. Connotation
      即情感含义(affective meaning)。
      早期关于情感含义的研究(Osgood,1957)发现,词汇在情感含义的三个重要维度上是不同的——valence、arousal和dominance,定义如下:
      valence: the pleasantness of the stimulus
      arousal: the intensity of emotion provoked by the stimulus
      dominance: the degree of control exerted by the stimulus
      另外,Osgood还提出一个很有进展性的想法————可以用一串数字表示词的含义,并且可以表示为空间中的一个点。
      在这里插入图片描述

    Vector Semantics

    如何建立一个计算模型,成功地处理我们在上一部分中看到的单词含义的不同方面(word senses、word similarity and relatedness、lexical fields and frames、connotation)?
    找到一个完全处理上述每个层面的模型是很难的。但目前最好的是向量语义(vector semantics)模型。向量语义模型其实是结合了从1950s的语言学家们的分布假设和Osgood的向量假设。目前为止有很多实现形式的向量语义模型,每种都以不同的方式去定义向量中的数字,但每种都以某种程度上基于**临近词的计数(counts of neighboring words)**来定义的。向量语义模型是目前NLP中标准的词义表示方法

    Words and Vectors

    向量语义模型通常基于共现矩阵(co-occurrence matrix)来表示词共同出现的频数。

    1. document vectors
      其实就是以字典中的词作为行,语料库中的文档作为列构建的term-document co-occurrence matrix。最初用于文档信息检索中的查找相似文档的任务,两个相似的文档会有相似的单词,如果两个文档有相似的单词,它们的列向量也会相似。这时一个文档用一个列向量去表示。可以想见这种matrix是稀疏且庞大的。
      在这里插入图片描述

    2. word vectors
      以字典中的词作为行和列构建|V|*|V|term-context matrix,每个矩阵元素记录row(target) word和column(context) word在某训练语料中某一上下文中共同出现的次数。这时,一个词用一个行向量去表示。注意,向量的长度通常是字典的大小,通常是训练语料中最频繁的10000~50000词。同样,这种matrix也是稀疏和耗费存储空间的。
      在这里插入图片描述

    3. cosine for measuring similarity
      此方法是计算词向量相似度最常用的方法。
      向量点积(dot product)/内积(inner product)的计算公式为:
      v ⃗ ⋅ w ⃗ = ∑ i = 1 N v i w i = v 1 w 1 + v 2 w 2 + . . . + v N w N = ∣ v ⃗ ∣ ∣ w ⃗ ∣ c o s θ \vec{v}\cdot\vec{w}=\sum_{i=1}^Nv_iw_i=v_1w_1+v_2w_2+...+v_Nw_N=|\vec{v}||\vec{w}|cos\theta v w =i=1Nviwi=v1w1+v2w2+...+vNwN=v w cosθ
      因此,计算两个向量cosine相似性的公式为:
      c o s i n e ( v ⃗ , w ⃗ ) = v ⃗ ⋅ w ⃗ ∣ v ⃗ ∣ ∣ w ⃗ ∣ = ∑ i = 1 N v i w i ∑ i = 1 N v i 2 ∑ i = 1 N w i 2 cosine(\vec{v},\vec{w})=\frac{\vec{v}\cdot\vec{w}}{|\vec{v}||\vec{w}|}=\frac{\sum_{i=1}^Nv_iw_i}{\sqrt{\sum_{i=1}^Nv_i^2}\sqrt{\sum_{i=1}^Nw_i^2}} cosine(v ,w )=v w v w =i=1Nvi2 i=1Nwi2 i=1Nviwi
      也就是说,两个词向量的相似度可以用其cosine值来表示,在0~1之间。值越大,两向量距离越小,说明两个词向量越相似。举例如下:
      在这里插入图片描述

    TF-IDF:Weighing terms in the vector

    上述co-occurrence matrix记录的raw frequency不是词之间关系的最好表示方法,容易造成偏斜(very skewed)并且没有太大辨别性(not very discriminative)。因为频繁出现在context中的词比仅出现一次两次的词更重要,但太频繁出现的词是不重要的。比如如果一个关键词只在很少的文档中出现,通过它就容易锁定目标,它的权重也就应该大。反之,如果一个词在大量网页中出现,看到它仍然不很清楚要找什么内容,它的权重就应该小。再比如上述的term-document co-occurence matrix中,一般认为出现频率高的词对文章主题贡献度高(battle对Julius Caesar和Henry V的贡献度就比As you kike it高),但good这个词在4个文档中出现频率都很高。

    TF-IDF就是为了解决这个矛盾(paradox),度量关键词权重,且必须满足两个条件:一个词预测主题的能力越强,权重越大,反之,权重越小;通用词的权重为0;
    TF-IDF是一种用于信息检索与文本挖掘的常用加权技术,并公认为是信息检索中最重要的发明。tf-idf是一种统计方法,用以评估一个词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。

    1. 词频term frequency(Luhn,1957):the frequency of the word in the doc.
      t f w t , d = c o u n t ( w t , d ) c o u n t ( w , d ) tf_{w_t,d}=\frac{count(w_t,d)}{count(w,d)} tfwt,d=count(w,d)count(wt,d)
      其中, c o u n t ( w t , d ) count(w_t,d) count(wt,d)为词 w t w_t wt在文档d中出现的次数, c o u n t ( w , d ) count(w,d) count(w,d)为文档d的总词数。
    2. 逆文档频率inverse document frequency(Sparck Jones,1972)
      i d f w t = l o g ( D D w t + 1 ) idf_{w_t}=log(\frac{D}{D_{w_t}+1}) idfwt=log(Dwt+1D)
      其中,D为文档总数, D w t D_{w_t} Dwt为包含词 w t w_t wt的文档数。
      这里解释下为什么用对数:若是简单的取逆处理,通用词的权重会非常小,稀缺词权重过大,因此采用取对数。
    3. 计算tf-idf
      t f − i d f = t f w t , d × i d f w t tf-idf=tf_{w_t,d} \times idf_{w_t} tfidf=tfwt,d×idfwt

    ♦ 不足
    TF-IDF由于其简单结构造成对权值调整不是很好,精度并不是很高;此外在TF-IDF中并没有体现出单词的位置信息,把文档中的词都看作独立的个体进行处理,忽略了词的意义、词和词之间的关联关系。比如对于Web文档而言,权重的计算方法应该体现出HTML的结构特征。特征词在不同的标记符中对文章内容的反映程度不同,其权重的计算方法也应不同。因此应该对于处于网页不同位置的特征词分别赋予不同的系数,然后乘以特征词的词频,以提高文本表示的效果。(引自维基百科https://zh.wikipedia.org/wiki/Tf-idf)
    ♦ 注意
    计算TF-IDF的数学公式有不少其他的实现方法。

    Pointwise Mutual Information(PMI) or Positive PMI(PPMI)

    替代TF-IDF的另一个weighting function是PPMI(Positive Pointwise mutual information)。PPMI认为衡量两个单词之间的关联最好的方法是,这两个单词在我们的语料库中同时出现的次数比我们预期的偶然出现的次数多多少。

    1. PMI(Fano,1961)
      逐点互信息是NLP中最重要的概念之一,衡量的是两个事件x和y发生的频率,与它们独立时的期望值相比,即:
      I ( X , Y ) = l o g 2 P ( x , y ) P ( x ) P ( y ) I(X,Y)=log_2\frac{P(x,y)}{P(x)P(y)} I(X,Y)=log2P(x)P(y)P(x,y)
      于是,中心词(target word) w w w和上下文词(context word) c c c之间的逐点互信息(Church and Hanks 1989)定义为: P M I ( w , c ) = l o g 2 P ( w , c ) P ( w ) P ( c ) PMI(w,c)=log_2\frac{P(w,c)}{P(w)P(c)} PMI(w,c)=log2P(w)P(c)P(w,c)
      分子告诉我们观察到的两个单词同时出现的频率(假设我们使用MLE计算概率)。分母告诉我们,如果这两个单词各自独立出现,我们期望它们同时出现的频率;两个独立事件同时发生的概率是两个事件概率的乘积。因此,这个比例给了我们一个估计值,即这两个词同时出现的概率比我们预期的要高多少。PMI是找到强关联词的一个有用工具。
    2. PPMI(Church and Hanks 1989, Dagan et al.1993, Niwa and Nitta 1994)
      PMI的取值是( − ∞ , + ∞ -\infty,+\infty ,+)。首先,PMI取负值表示的是两个词同时出现的频率比我们期望它们同时出现的频率少。这个结果除非是语料库很大否则是很不可靠的。其次,PMI取负值说明的是两个词的不相关程度,我们还不清楚是否有可能用人类的判断来评估这种“不相关”的分数。所以,最常用的是Postive PMI(PPMI),也就是用0替代所有PMI的负值:
      P P M I ( w , c ) = m a x ( l o g 2 P ( w , c ) P ( w ) P ( c ) , 0 ) PPMI(w,c)=max(log_2\frac{P(w,c)}{P(w)P(c)},0) PPMI(w,c)=max(log2P(w)P(c)P(w,c),0)
      假如有 W W W行(words)和 C C C列(contexts)的共现矩阵 F F F f i j f_{ij} fij为中心词 w i w_i wi和上下文词 c j c_j cj同时出现的次数。转化为PPMI矩阵,其中 p p m i i j ppmi_{ij} ppmiij给出上下文词 c j c_j cj下中心词 w i w_i wi的PPMI值为:
      p i j = f i j ∑ i = 1 W ∑ j = 1 C f i j , p i ∗ = ∑ j = 1 C f i j ∑ i = 1 W ∑ j = 1 C f i j , p ∗ j = ∑ i = 1 W f i j ∑ i = 1 W ∑ j = 1 C f i j p_{ij}=\frac{f_{ij}}{\sum_{i=1}^W\sum_{j=1}^Cf_{ij}},p_{i*}=\frac{\sum_{j=1}^Cf_{ij}}{\sum_{i=1}^W\sum_{j=1}^Cf_{ij}},p_{*j}=\frac{\sum_{i=1}^Wf_{ij}}{\sum_{i=1}^W\sum_{j=1}^Cf_{ij}} pij=i=1Wj=1Cfijfij,pi=i=1Wj=1Cfijj=1Cfij,pj=i=1Wj=1Cfiji=1Wfij
      因此, P P M I i j = m a x ( l o g 2 p i j p i ∗ p ∗ j , 0 ) PPMI_{ij}=max(log_2\frac{p_{ij}}{p_{i*}p_{*j}},0) PPMIij=max(log2pipjpij,0)
    3. Example
      基于上文的term-context matrix,我们计算PPMI(w=information,c=data):
      P ( w = i n f o r m a t i o n , c = d a t a ) = 6 19 = . 316 P(w=information,c=data)=\frac{6}{19}=.316 P(w=information,c=data)=196=.316
      P ( w = i n f o r m a t i o n ) = 11 19 = . 579 P(w=information)=\frac{11}{19}=.579 P(w=information)=1911=.579
      P ( c = d a t a ) = 7 19 = . 368 P(c=data)=\frac{7}{19}=.368 P(c=data)=197=.368
      p p m i ( w = i n f o r m a t i o n , c = d a t a ) = l o g 2 ( . 316 / ( . 368 ∗ . 579 ) ) = . 568 ppmi(w=information,c=data)=log_2(.316/(.368*.579))=.568 ppmi(w=information,c=data)=log2(.316/(.368.579))=.568
      以此类推,可得
      在这里插入图片描述

    在这里插入图片描述

    1. Extensions:
      PMI存在着偏斜不频繁事件的问题;非常罕见的词汇往往具有非常高的PMI值。
      ♦ 减少这种倾向于低频率的事件的一个方法是稍微改变 P ( c ) P(c) P(c)的计算,使用不同的函数 P ( c ) P(c) P(c),提出了上下文 P α ( c ) P_{\alpha}(c) Pα(c):
      P P M I α ( w , c ) = m a x ( l o g 2 P ( w , c ) P ( w ) P α ( c ) , 0 ) PPMI_{\alpha}(w,c)=max(log_2\frac{P(w,c)}{P(w)P_{\alpha}(c)},0) PPMIα(w,c)=max(log2P(w)Pα(c)P(w,c),0)
      其中,
      P α ( c ) = c o u n t ( c ) α ∑ c c o u n t ( c ) α P_{\alpha}(c)=\frac{count(c)^{\alpha}}{\sum_{c}count(c)^{\alpha}} Pα(c)=ccount(c)αcount(c)α
      Levy(2015)发现α= 0.75时,在很多任务中表现有明显提高。因为α= 0.75增加概率分配到罕见的context上,因此降低了其PMI ( P α ( c ) P_{\alpha}(c) Pα(c)> P ©,当c是rare context)。
      ♦ 另一个可能的解决方法是拉普拉斯平滑(Laplace smoothing):在计算PMI之前,在每个计数中添加一个小的常数k(通常为0.1-3),收缩所有的非零值。k越大,非零值的折扣就越大。
      在这里插入图片描述
    展开全文
  • 求矩阵的:function count = juZhenDeMo(a,b)[r,c] = size(a);%求a的行列[r1,c1] = size(b);%求b的行列count = 0;for j=1:r-r1+1%所求的行数中取for i=1:c-c1+1%所有的列数中取d = a(j:j+r1-1,i:i+c1-1);e = ...

    求矩阵的模:

    function count = juZhenDeMo(a,b)

    [r,c] = size(a);%求a的行列

    [r1,c1] = size(b);%求b的行列

    count = 0;

    for j=1:r-r1+1%所求的行数中取

    for i=1:c-c1+1%所有的列数中取

    d = a(j:j+r1-1,i:i+c1-1);

    e = double(d==b);

    if(sum(e(:))==r1*c1)

    count = count + 1;

    end

    end

    end

    clc;

    clear;

    a = eye(6)

    b = [1 0;0 1]

    disp('a矩阵中b的模的个数是:');

    count = juZhenDeMo(a,b)

    end

    求向量的模:

    function count = sta_submatrix1(a,b)

    count = 0;

    for i = 1:length(a)-length(b)+1

    c = a(i:i+length(b)-1);

    e = double(c==b);

    if(sum(e) == length(b))

    count = count + 1;

    end

    end

    end

    clc;

    clear;

    a = [0 0 0 1 0 0 1  0 0 1 0 0 1 0 0]

    b = [0 0 ]

    disp('b在a中的模的个数是:')

    count = sta_submatrix1(a,b)

    展开全文
  • 我们在文章https://blog.csdn.net/lockhou/article/details/113883940已经实现了在Win上的将一系列的c文件转化生成对应的AST文件,并且通过AST文件经过节点匹配生成文本向量,从而构建一个c文件对应一个存储AST的txt...

    实现思路

    环境:

    我们在文章https://blog.csdn.net/lockhou/article/details/113883940已经实现了在Win上的将一系列的c文件转化生成对应的AST文件,并且通过AST文件经过节点匹配生成文本向量,从而构建一个c文件对应一个存储AST的txt文件对应一个存储文本向量的txt文件,且对应的三个文件同名,因为我们判断一个文件是否有漏洞是从文件名字当中体现的。

    思路:

    我们原理是现将文件分类为Train,Test,Validation,之后直接读取.c文件做去空处理,去停用词处理并将转化后的数据存为pickle文件,用于提供后面词向量转化,模型训练,模型测试,模型验证的数据需求。我们既然要利用文本向量表示结构信息,我们可以不再直接读取文件,而是直接读取每个c文件的对应文本向量txt文件做相同操作,从而提供给后面词向量转化,模型训练,模型测试,模型验证的数据是具有结构信息的,从而完成工作。

    从win移到linux过程

    step1 java上安装jdk

    具体步骤见文章:https://blog.csdn.net/lockhou/article/details/113904085

    step2 修改movefiles.py

    我最后决定在移动后c文件所在的每一个目录的同级目录建立文件夹用于存储从c文件提取的AST文件(存在Preprocessed文件夹下)和转化得到的文本向量文件(存在processed文件夹下)。所以我们在建立Train,Test,Validation文件夹以及其内部文件夹是要在每一种组合的Non_vulnerable_functions和Vulnerable_functions文件夹下都建立Preprocessed和processed文件夹,所以在46-55添加代码如下:

    saveDir = tempDir
            tempDir =  saveDir + '/'+ "Preprocessed"
            if not os.path.exists(tempDir):
                #Non_vulnerable_functions/Non_vulnerable_functions/Preprocessed
                os.mkdir(tempDir)
            tempDir =  saveDir + '/'+ "processed"
            if not os.path.exists(tempDir):
                #Non_vulnerable_functions/Non_vulnerable_functions/processed
                os.mkdir(tempDir)
    

    step2 修改ProcessCFilesWithCodeSensor.py和ProcessRawASTs_DFT.py

    我们现在有了存储AST和文本向量的位置,所以我们只要反复调用ProcessCFilesWithCodeSensor.py和ProcessRawASTs_DFT.py文件即可,所以为了方便调用我们将两个文件组织成函数的形式,并且将需要的参数作为形参在调用的时候传递。

    ProcessCFilesWithCodeSensor.py参数:

    1)CodeSensor_OUTPUT_PATH:将每个.c文件提取出来AST保存为.txt文件所存储的地址
    “G:\论文\论文\ast\function_representation_learningmaster\FFmpeg\Vulnerable_functions\Preprocessed\”
    2)CodeSensor_PATH:codesensor.java所在位置
    “D:\codesensor\CodeSensor.jar”(位置固定不需传入,即不需作为参数)
    3)PATH :.c文件所存储的目录
    “G:\论文\论文\ast\function_representation_learning-master\FFmpeg\Vulnerable_functions”

    ProcessRawASTs_DFT.py参数:

    1)FILE_PATH :存储AST的TXT所在目录
    “G:\论文\论文\ast\function_representation_learning-master\” + Project_Name + “\Vulnerable_functions\Preprocessed\”
    2)Processed_FILE : 存储文本向量的txt文件
    “G:\论文\论文\ast\function_representation_learning-master\” + Project_Name + “\Vulnerable_functions\Processed\”

    根据上面参数需求,我们将文件内容组织成函数如下:

    #ProcessCFilesWithCodeSensor.py
    
    def codesensor(CodeSensor_OUTPUT_PATH,PATH):
    	CodeSensor_PATH = "./Code/codesensor-codeSensor-0.2/CodeSensor.jar"
    	Full_path = ""
    
    	for fpathe,dirs,fs in os.walk(PATH):
      		for f in fs:
        			if (os.path.splitext(f)[1]=='.c'): # Get the .c files only
            			file_path = os.path.join(fpathe,f) # f is the .c file, which will be processed by CodeSensor
            
            # With each .c file open, CodeSensor will process the opened file and output all the processed files to a specified directory.
            # Full_path = CodeSensor_OUTPUT_PATH + "_" + f + ".txt"
            			Full_path = CodeSensor_OUTPUT_PATH + os.path.splitext(f)[0] + ".txt"
            			with open(Full_path, "w+") as output_file:
                				Popen(['/home/jdk1.8.0_65/bin/java', '-jar', CodeSensor_PATH, file_path], stdout=output_file, stderr=STDOUT)
                				output_file.close()
    
    
    
    # ProcessRawASTs_DFT.py
    
    def DepthFirstExtractASTs(file_to_process, file_name):
        
        lines = []
        subLines = ''
        
        f = open(file_to_process)
        try:
            original_lines = f.readlines()
            print(original_lines)
            #lines.append(file_name) # The first element is the file name.
            for line in original_lines:
                if not line.isspace(): # Remove the empty line.
                    line = line.strip('\n')
                    str_lines = line.split('\t')   
                    #print (str_lines)
                    if str_lines[0] != "water": # Remove lines starting with water.
                        #print (str_lines)
                        if str_lines[0] == "func":
                            # Add the return type of the function
                            subElement = str_lines[4].split() # Dealing with "static int" or "static void" or ...
                            if len(subElement) == 1:
                                lines.append(str_lines[4])
                            if subElement.count("*") == 0: # The element does not contain pointer type. If it contains pointer like (int *), it will be divided to 'int' and '*'.
                                if len(subElement) == 2:
                                    lines.append(subElement[0])
                                    lines.append(subElement[1]) 
                                if len(subElement) == 3:
                                    lines.append(subElement[0])
                                    lines.append(subElement[1])    
                                    lines.append(subElement[2])
                            else:
                                lines.append(str_lines[4])
                            #lines.append(str_lines[5]) # Add the name of the function
                            lines.append("func_name") # Add the name of the function
                        if str_lines[0] == "params":
                            lines.append("params")                    
                        if str_lines[0] == "param":
                            subParamElement = str_lines[4].split() # Addd the possible type of the parameter
                            if len(subParamElement) == 1:
                                lines.append("param")
                                lines.append(str_lines[4]) # Add the parameter type
                            if subParamElement.count("*") == 0:
                                if len(subParamElement) == 2:
                                    lines.append("param")
                                    lines.append(subParamElement[0])
                                    lines.append(subParamElement[1]) 
                                if len(subParamElement) == 3:
                                    lines.append("param")
                                    lines.append(subParamElement[0])
                                    lines.append(subParamElement[1])    
                                    lines.append(subParamElement[2])
                            else:
                                lines.append("param")
                                lines.append(str_lines[4]) # Add the parameter type                           
                        if str_lines[0] == "stmnts":
                            lines.append("stmnts")                    
                        if str_lines[0] == "decl":
                            subDeclElement = str_lines[4].split() # Addd the possible type of the declared veriable
                            #print (len(subDeclElement))
                            if len(subDeclElement) == 1:
                                lines.append("decl")
                                lines.append(str_lines[4]) # Add the type of the declared variable
                            if subDeclElement.count("*") == 0:
                                if len(subDeclElement) == 2:
                                    lines.append("decl")
                                    lines.append(subDeclElement[0])
                                    lines.append(subDeclElement[1]) 
                                if len(subDeclElement) == 3:
                                    lines.append("decl")
                                    lines.append(subDeclElement[0])
                                    lines.append(subDeclElement[1])    
                                    lines.append(subDeclElement[2])
                            else:
                                lines.append("decl")
                                lines.append(str_lines[4]) # Add the type of the declared variable
                        if str_lines[0] == "op":
                            lines.append(str_lines[4])
                        if str_lines[0] == "call":
                            lines.append("call")
                            lines.append(str_lines[4])
                        if str_lines[0] == "arg":
                            lines.append("arg")
                        if str_lines[0] == "if":
                            lines.append("if")
                        if str_lines[0] == "cond":
                            lines.append("cond")
                        if str_lines[0] == "else":
                            lines.append("else")
                        if str_lines[0] == "stmts":
                            lines.append("stmts")
                        if str_lines[0] == "for":
                            lines.append("for") 	
                        if str_lines[0] == "forinit":
                            lines.append("forinit")
                        if str_lines[0] == "while":
                            lines.append("while")
                        if str_lines[0] == "return":
                            lines.append("return")
                        if str_lines[0] == "continue":
                            lines.append("continue")
                        if str_lines[0] == "break":
                            lines.append("break")
                        if str_lines[0] == "goto":
                            lines.append("goto")
                        if str_lines[0] == "forexpr":
                            lines.append("forexpr")
                        if str_lines[0] == "sizeof":
                            lines.append("sizeof")
                        if str_lines[0] == "do":
                            lines.append("do")   
                        if str_lines[0] == "switch":
                            lines.append("switch")   
                        if str_lines[0] == "typedef":
                            lines.append("typedef")
                        if str_lines[0] == "default":
                            lines.append("default")
                        if str_lines[0] == "register":
                            lines.append("register")
                        if str_lines[0] == "enum":
                            lines.append("enum")
                        if str_lines[0] == "union":
                            lines.append("union")
                        
            print(lines)
            subLines = ','.join(lines)
            subLines = subLines + "," + "\n"
        finally:
            f.close()
            return subLines
     
    def text_vector(FILE_PATH,Processed_FILE):  
    	big_line = []
    	total_processed = 0
    
    	for fpathe,dirs,fs in os.walk(FILE_PATH):
      		for f in fs:
        			if (os.path.splitext(f)[1]=='.txt'): # Get the .c files only
            			file_path = os.path.join(fpathe,f) # f is the .c file, which will be processed by CodeSensor
            			temp = DepthFirstExtractASTs(FILE_PATH + f, f)
            			print(temp)
            
            			f1 = open(Processed_FILE + os.path.splitext(f)[0]+".txt", "w")
            			f1.write(temp)
            			f1.close()
            			# big_line.append(temp)
    
           			#time.sleep(0.001)
            			total_processed = total_processed + 1
    
    	print ("Totally, there are " + str(total_processed) + " files.")
    

    step3 修改movefiles.py

    我们现在已经建立好存储AST文件和文本向量文件的位置,我们只需要将每一个含有c文件的目录下所有c文件经过codesensor函数调用产生AST文件并存在对应目录中的Preprocesses文件夹之下,并且在通过调用text_vector函数将每个Preprocessed目录下的AST文件转化为文本向量文件存储在相应目录的procesed文件夹之下,所以我们在movefiles.py的最后,即建立完所有的文件夹之后加入下列代码:

    from  ProcessCFilesWithCodeSensor import *
    from  ProcessRawASTs_DFT import *
    
    for i in range(len(FirstDir)):
        codesensor(Non_vul_func_trainDir[i]+"/Preprocessed/",Non_vul_func_trainDir[i])
        codesensor(Non_vul_func_testDir[i]+"/Preprocessed/",Non_vul_func_testDir[i])
        codesensor(Non_vul_func_validationDir[i]+"/Preprocessed/",Non_vul_func_validationDir[i])
        codesensor(Vul_func_trainDir[i]+"/Preprocessed/",Vul_func_trainDir[i])
        codesensor(Vul_func_testDir[i]+"/Preprocessed/",Vul_func_testDir[i])
        codesensor(Vul_func_validationDir[i]+"/Preprocessed/",Vul_func_validationDir[i])
        text_vector(Non_vul_func_trainDir[i]+"/Preprocessed/",Non_vul_func_trainDir[i]+"/processed/")
        text_vector(Non_vul_func_testDir[i]+"/Preprocessed/",Non_vul_func_testDir[i]+"/processed/")
        text_vector(Non_vul_func_validationDir[i]+"/Preprocessed/",Non_vul_func_validationDir[i]+"/processed/")
        text_vector(Vul_func_trainDir[i]+"/Preprocessed/",Vul_func_trainDir[i]+"/processed/")
        text_vector(Vul_func_testDir[i]+"/Preprocessed/",Vul_func_testDir[i]+"/processed/")
        text_vector(Vul_func_validationDir[i]+"/Preprocessed/",Vul_func_validationDir[i]+"/processed/")
        
    

    step4 修改removeComments_Blanks.py和LoadCFilesAsText.py文件

    因为我们使想用生成的文本向量文件替代c文件,而在removeComments_Blanks.py和LoadCFilesAsText.py文件中是直接读取c文件并且对文件中的内容进行去空格,去停用词的操作之后转存为pickle文件。所以我们现在用生成的文本向量文件替代c文件,我们需要读取processed文件夹下的文本向量文件,并且读取txt文件其他的操作不变。
    所以我们要把所有removeComments_Blanks.py和LoadCFilesAsText.py文件中的所有代表读取c文件的目录扩展到与c文件同目录的processesed文件夹下让其读取文本向量文件,并且在判断文件类型的时候不再寻找c文件改为寻找txt文件即可。

    step5 接下来正常运行词向量文件以及训练和测试文件即可

    展开全文
  • 向量与句向量模型

    2021-05-06 11:56:22
    如要预测的term(足球)的编码长度4,则可以把预测’足球’,转换为4次二分类问题,在每个二分类上用二元逻辑回归的方法(sigmoid); 3)逻辑回归的二分类中,sigmoid函数导数有很好的性质,′()=()(1−()) 4...
  • 支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;SVM还包括核技巧,这使它成为实质上的非线性分类器。SVM的的学习...
  • 在Keras模型中使用预训练的词向量文章信息通过本教程,你可以掌握技能:使用预先训练的词向量和卷积神经网络解决一个文本分类问题本文代码已上传到Github本文作者:Francois Chollet什么是词向量?”词向量”(词嵌入)...
  • 一、Unity 中的向量1、向量的长度public class sc03 : MonoBehaviour{// Update is called once per framevoid Update () {Demo1();}void Demo1(){// 获取当前物体的...//计算当前向量模长的三种方法float m01 = ...
  • 欧拉角转旋转矩阵对于两个三维点,,由点经过旋转矩阵旋转到,则有:任何一个旋转可以表示依次绕着三个旋转轴旋三个角度的组合。这三个角度称为欧拉角。 对于在三维空间里的一个参考系,任何坐标系的取向,都可以...
  • Python实现支持向量机SVM回归模型(SVR算法)项目实战。
  • 将原词汇数据转换为字典映射,求三大参数,即word2index,index2word,word2one-hot 3. skip-gram模型 建立一个扫描器 4.建立并训练 skip-gram 模型 5.开始训练模型 6.结果可视化 """ import numpy as np import ...
  • 3.4-complete-no-antlrv2下载网址) 学习过程: step1:读论文 了解将代码转化为ast后再转化为文本向量的基本过程和所使用的基本工具 first: DeepBalance: Deep-Learning and FuzzyOversampling for Vulnerability ...
  • 支持向量机(Support vector machine, SVM)是一种二分类模型,是按有监督学习方式对数据进行二元分类的广义线性分类器。 支持向量机经常应用于模式识别问题,如人像识别、文本分类...**SVM 可以转化为求解凸二次规划的
  • 可以将其通俗的理解前人为了解决类似问题所创造出来的一个模型,有了前人的模型,当我们遇到新的问题时,便不再需要从零开始训练新模型,而可以直接用这个模型入手,进行简单的学习便可解决该新问题。
  • fasttext训练的bin格式词向量转换为vec格式词向量 #加载的fasttext预训练词向量都是vec格式的,但fasttext无监督训练后却是bin格式,因此需要进行转换 # 以下代码fasttext官方推荐: # 请将以下代码保存在bin_to_...
  • 学校自然语言处理第二次大作业,训练中英文语料获得词向量,那我们开始吧~、 目录 一、CBOW模型 二、程序说明 ...1.cbow模型与词向量是什么关系 ...5.什么中文语料要加载停用词 作业要求:.
  • ----------------------------大纲--------------------------1 随着模型不断更新2 直接使用预先训练好的词向量如word2vec, glove--------------------------------------------------------------省去数据读取以及...
  • 但是,要把模型坐标系下的法向量转换到世界坐标系,却不能直接使用model矩阵。 我们用二维平面的变换来说明: 图中的线段AB经过了缩放变换。左图中点A=(0,1)B=(1,0),法向量N=(1,1);右图中经过y坐标值放大两倍...
  • 本文介绍了向量的定义、向量、负向量、单位向量、零向量以及向量加减法的三种实现方法。
  • 向量自回归模型估计的先决条件之一是被分析的时间序列是平稳的。但是,经济理论认为,经济变量之间在水平上存在着均衡关系,可以使这些变量差分而平稳。这就是所谓的协整关系。由于知道这种关系可以改善分析的结果,...
  • word2vec模型进行词向量训练方法 一、打开语料库官网 搜狗实验室的搜狗新闻语料库官方链接:点击打开官方链接 二、下载语料库数据,首先下拉找到迷你版(样例数据, 110KB),然后点击第一个红色箭头指向的红色框内容...
  • 十一、词向量模型

    2021-10-13 16:44:11
    在英文中称作One-Hot code,直观来说就是有多少个状态就有多少比特,而且只有一个比特1,其他全为0的一种码制。 假如有三种颜色特征:红、黄、蓝。红=1,黄=2,蓝=3;红<黄<蓝; 即红色:1 0 0 ,黄色: 0 1 ...
  • 1.支持向量机简介 支持向量机是一种二类分类模型,定义在特征空间上的间隔最大的线性分类器,间隔最大使其有别于感知机。 即求解凸二次规划的最优化算法,包括线性可分支持向量机,线性支持向量机以及非线性支持向量...
  • 2.基于空间向量的余弦算法2.1算法步骤预处理→文本特征项选择→加权→生成向量空间模型后计算余弦。2.2步骤简介2.2.1预处理预处理主要是进行中文分词和去停用词,分词的开源代码有:ICTCLAS。然后按照停用词表中的...
  • 使用 TF-IDF 加权的空间向量模型实现句子相似度计算字符匹配层次计算句子相似度计算两个句子相似度的算法有很多种,但是对于从未了解过这方面算法的人来说,可能最容易想到的就是使用字符串匹配相关的算法,来检查两...
  • 文本向量化的原理

    2021-03-05 11:35:31
    中文则需通过分词工具分隔之后,把词之间加上空格)二、去停用词在文本中可以发现类似”the”、”a”等词的词频很高,但是这些词并不能表达文本的主题,我们称之停用词。对文本预处理的过程中,我们希望能够尽可能...
  • 导读马尔科夫区制转移向量自回归模型可以进行实时(real-time)预测分析扩展容纳混合频率和锯齿数据可以看作是MF-VAR模型的马尔科夫区制转移(Markov-switching)扩展从经验上讲,该模型能够非常准确地捕捉到美国的经济...
  • 词的信息可以转换为向量表示 向量表示可以计算词与词之间的相似度(欧式距离、余弦距离等) 维度越高,向量表示的信息越多,从而计算结果的可靠性更高。 词向量中的数值通过热度图直观比较 man与boy之间的词向量有...
  • 本发明涉及一种中文字词向量和方面词向量联合嵌入CNN-LSTM情感分析方法。背景技术:近年来,越来越多的用户习惯在网络上发自己对某一事物的看法与评论...在自然语言处理领域,深度学习方法首先将文本转化为一组向量...
  • 简称RVM)是Tipping在2001年在贝叶斯框架的基础上提出的,它有着与支持向量机(Support vector machine,简称SVM)一样的函数形式,与SVM一样基于核函数映射将低维空间非线性问题转化为高维空间的线性问题。RVM原理步骤...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 156,085
精华内容 62,434
关键字:

向量怎么转化为向量的模