[Dict2vec]论文实现:Dict2vec : Learning Word Embeddings using Lexical Dictionaries

论文:Dict2vec : Learning Word Embeddings using Lexical Dictionaries
作者:Julien Tissier, Christophe Gravier, Amaury Habrard
时间:2017

一、完整代码

# 完整代码在这里

二、论文解读

Dict2vec从字典条目构建新的单词对,使语义相关的单词移动得更近,负采样过滤掉字典中不相关的单词对。

2.1 方法介绍

     无监督学习的词向量有一个经典缺陷:在一个单词和那些在相关上下文中出现的单词之间缺乏监督。例如,近义词无法在一句话中同时出现,这里使用dict2vec通过字典中词的定义来优化这一步骤;
     单词的定义是一组解释其意义的单词或句子。字典是针对几个单词的一组元组(单词、定义)。例如,你可以在字典中找到:

car: A road vehicle, typically with four wheels, powered by an internal combustion engine and able to carry a small number of people.

从定义中我们可以发现car中有vehicle,road,engine等等词语;通过这样的词的出现,可以说明使用词定义来获得弱监督的相关性,允许我们得到语义上相关的词对是可行的;这里我们定义两个东西,weak pairsstrong pairs

  • weak pairs:如果A和B的定义中,只有一方有对方,那就是weak pairs
  • strong pairs:如果A和B的定义中,双方都有对方词语,那就是strong pairs

The word “vehicle” is in the definition of “car” and “car” is in the definition of “vehicle”. Hence, (car–vehicle) is a strong pair. The word “road” is in the definition of “car”, but “car” is not in the definition of “road”. Therefore, (car–road) is a weak pair.
“车辆”一词在“汽车”的定义中,“汽车”一词在“车辆”的定义中。因此,(汽车-汽车)是强有力的一对。“路”一词是在“汽车”的定义中,而“车”则不在“道路”的定义中。因此,(汽车-道路)是一个弱对。

为了把weak pairs和strong pairs与损失函数联系起来,同时为了避免影响运算速度,我们可以通过正采样和负采样结合的方式,首先是正采样,如下所示: J p o s ( w t ) = β s ∑ w i ∈ V s ( w t ) l ( v t ⋅ v i ) + β w ∑ w j ∈ V w ( w t ) l ( v t ⋅ v j ) J_{pos}(w_t)=\beta_s\sum_{w_i \in V_s(w_t)}l(v_t·v_i) +\beta_w\sum_{w_j \in V_w(w_t)}l(v_t·v_j) Jpos(wt)=βswiVs(wt)l(vtvi)+βwwjVw(wt)l(vtvj)其中 S ( w ) S(w) S(w)表示与 w w w相关的所有strong pairs组成的集合; W ( w ) W(w) W(w)表示与 w w w相关的所有weak pairs组成的集合; V s ( w ) V_s(w) Vs(w)表示从 S ( w ) S(w) S(w)中抽出的pairs组成的集合; V w ( w ) V_w(w) Vw(w)表示从 W ( w ) W(w) W(w)中抽出的pairs组成的集合; β s \beta_s βs β w \beta_w βw是两个系数;抽取的个数可以自定义;

接下来是负采样,首先定义随机采样的集合如下: F ( w t ) = { w i } k , w i ∈ V − { w t } F(w_t)=\{w_i\}^k, w_i \in V - \{w_t\} F(wt)={wi}k,wiV{wt}接下来可以得到负采样如下: J n e g ( w t ) = ∑ w i ∈ F ( w t ) w i ∉ S ( w t ) w i ∉ W ( w t ) l ( − v t ⋅ v i ) J_{neg}(w_t)=\sum_{w_i \in F(w_t) \quad wi \notin S(w_t) \quad w_i \notin W(w_t)}l(-v_t·v_i) Jneg(wt)=wiF(wt)wi/S(wt)wi/W(wt)l(vtvi)

     负采样用负数是为了尽可能的让他们不在一起,正采样用正数是为了尽可能的让他们在一起;得到最后的损失函数如下: J = ∑ t = 1 C ∑ c = − n n J ( w t , w t + c ) = ∑ t = 1 C ∑ c = − n n [ l ( v t , v c ) + J p o s ( w t ) + J n e g ( w t ) ] J=\sum_{t=1}^{C}\sum_{c=-n}^{n}J(w_t,w_{t+c})=\sum_{t=1}^{C}\sum_{c=-n}^{n}[l(v_t,v_c)+J_{pos}(w_t)+J_{neg}(w_t)] J=t=1Cc=nnJ(wt,wt+c)=t=1Cc=nn[l(vt,vc)+Jpos(wt)+Jneg(wt)]

模型介绍完毕!

2.2 参数设置事项

对于正抽样,经验网格搜索显示,βs和βw之间的比率为1:2 是调整这些超参数的一个很好的经验法则。我们还注意到,当这些系数过低时(βs≤0.5和βw≤0.2),结果会变得更糟,因为该模型没有考虑到来自强对和弱对的信息。另一方面,当它们过高时(βs≥1.2和βw≥0.6),模型会从上下文中丢弃太多的信息,而支持来自对的信息。当强对和弱对的数量过低或过高(ns,nw≤2或ns,nw≥5)时,这种行为是相似的。对于负抽样,我们注意到,与不受控制的版本相比,由成对带来的控制的平均加权得分增加了0.7%。我们还观察到,增加负样本的数量并没有显著提高结果,除了RW数据集,其中使用25个负样本可以提高10%的性能。实际上,这个数据集主要由罕见的单词组成,所以嵌入必须学会区分不相关的单词,而不是更接近相关的单词。

2.3 模型效果

提升不大,使用于小语料,个人认为小语料特征不明显,需要强化,而dict2vec通过字典定义添加了信息进行强化!

三、过程实现

四、整体总结

本文提出了一种利用词汇字典学习单词嵌入的新方法Dict2vec。它基于一个Skip-gram模型,其中目标函数通过利用从定义中提取的词对的强度对进行扩展。在单词相似性任务中,我们的方法比最先进的单词嵌入方法显示了更好的结果,包括基于来自外部来源的修改的嵌入方法。我们还提供了完整的源代码来重现实验。

Word2Vec是一种常用的词向量表示方法,它通过神经网络模型将单词映射到向量空间中,从而可以直接使用向量进行文本处理和分析。下面是一个简单的Word2Vec实现代码,使用Python语言和TensorFlow框架。 首先需要准备一个文本数据集,这里使用了一个小型的英文新闻文本数据集作为示例。代码需要先对数据进行预处理,将文本中的单词转换成数值表示。 ```python import tensorflow as tf import numpy as np import collections import os # 读取数据 def read_data(filename): with open(filename, 'r') as f: data = f.read().split() return data # 构建词汇表 def build_vocab(data, vocab_size): # 统计单词出现频次 word_count = [['UNK', -1]] word_count.extend(collections.Counter(data).most_common(vocab_size - 1)) # 创建词汇表 vocab_dict = {} for word, count in word_count: vocab_dict[word] = len(vocab_dict) # 将数据集中的单词转换为数值表示 data_vocab = [] unk_count = 0 for word in data: if word in vocab_dict: index = vocab_dict[word] else: index = 0 # UNK unk_count += 1 data_vocab.append(index) word_count[0][1] = unk_count return data_vocab, vocab_dict, word_count # 生成训练数据 def generate_train_data(data, window_size): train_data = [] for i in range(len(data)): for j in range(1, window_size+1): if i-j >= 0: train_data.append([data[i], data[i-j]]) if i+j < len(data): train_data.append([data[i], data[i+j]]) return train_data # 读取数据集 data = read_data('news.txt') vocab_size = 5000 data, vocab_dict, word_count = build_vocab(data, vocab_size) train_data = generate_train_data(data, window_size=2) ``` 接下来就是Word2Vec模型的构建,这里使用了Skip-gram模型。模型的输入是一个单词的数值表示,输出是它周围的单词的数值表示,即使用一个单词预测它的上下文。模型的核心是一个嵌入层,将每个单词映射到一个向量空间中,然后使用点积计算相似度。 ```python # 定义Word2Vec模型 class Word2Vec: def __init__(self, vocab_size, embed_size): self.vocab_size = vocab_size self.embed_size = embed_size self.inputs = tf.placeholder(tf.int32, [None]) self.labels = tf.placeholder(tf.int32, [None, 1]) # 定义嵌入层 with tf.variable_scope('embed'): self.embeddings = tf.Variable(tf.random_uniform([vocab_size, embed_size], -1.0, 1.0)) embed = tf.nn.embedding_lookup(self.embeddings, self.inputs) # 定义输出层 with tf.variable_scope('output'): self.weights = tf.Variable(tf.truncated_normal([vocab_size, embed_size], stddev=1.0 / np.sqrt(embed_size))) self.biases = tf.Variable(tf.zeros([vocab_size])) self.logits = tf.matmul(embed, tf.transpose(self.weights)) + self.biases # 定义损失函数和优化器 self.loss = tf.reduce_mean(tf.nn.sampled_softmax_loss(self.weights, self.biases, self.labels, embed, num_sampled=1000, num_classes=vocab_size)) self.optimizer = tf.train.AdagradOptimizer(learning_rate=0.1).minimize(self.loss) # 定义训练函数 def train_word2vec(train_data, vocab_size, embed_size, num_epochs, batch_size, save_path): tf.reset_default_graph() model = Word2Vec(vocab_size, embed_size) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) total_loss = 0.0 for epoch in range(num_epochs): np.random.shuffle(train_data) for i in range(0, len(train_data), batch_size): batch_inputs, batch_labels = [], [] for j in range(i, min(i+batch_size, len(train_data))): batch_inputs.append(train_data[j][0]) batch_labels.append([train_data[j][1]]) loss, _ = sess.run([model.loss, model.optimizer], feed_dict={model.inputs: batch_inputs, model.labels: batch_labels}) total_loss += loss if epoch % 10 == 0: print('Epoch %d, average loss: %.4f' % (epoch, total_loss / len(train_data))) total_loss = 0.0 # 保存模型 if not os.path.exists(save_path): os.mkdir(save_path) model_file = os.path.join(save_path, 'word2vec.ckpt') saver = tf.train.Saver() saver.save(sess, model_file) # 训练Word2Vec模型 embed_size = 100 num_epochs = 100 batch_size = 512 save_path = 'model' train_word2vec(train_data, vocab_size, embed_size, num_epochs, batch_size, save_path) ``` 训练完成后,就可以使用训练好的模型进行单词向量的表示和相似度计算了。代码如下: ```python # 加载模型 def load_word2vec(vocab_dict, embed_size, save_path): tf.reset_default_graph() model = Word2Vec(len(vocab_dict), embed_size) with tf.Session() as sess: model_file = os.path.join(save_path, 'word2vec.ckpt') saver = tf.train.Saver() saver.restore(sess, model_file) embeddings = sess.run(model.embeddings) # 创建词向量字典 word_vectors = {} for word, index in vocab_dict.items(): word_vectors[word] = embeddings[index] return word_vectors # 计算单词相似度 def calc_similarity(word1, word2, word_vectors): vec1 = word_vectors[word1] vec2 = word_vectors[word2] sim = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2)) return sim # 加载模型并计算相似度 word_vectors = load_word2vec(vocab_dict, embed_size, save_path) print(calc_similarity('man', 'woman', word_vectors)) ``` 以上就是一个简单的Word2Vec实现代码,可以用于生成单词向量并计算相似度。实际应用中,可以根据需求对模型进行优化和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值