当前位置:   article > 正文

Tensorflow实战学习(三十四)【实现Word2Vec】_word2vec skip-gram模型的简单实现text8.zip

word2vec skip-gram模型的简单实现text8.zip

卷积神经网络发展趋势。Perceptron(感知机),1957年,Frank Resenblatt提出,始祖。Neocognitron(神经认知机),多层级神经网络,日本科学家Kunihiko fukushima,20世纪80年代提出,一定程度视觉认知功能,启发卷积神经网络。LeNet-5,CNN之父,Yann LeCun,1997年提出,首次多层级联卷积结构,手写数字有效识别。2012年,Hinton学生Alex,8层卷积神经网络,ILSVRC 2012比赛冠军。AlexNet 成功应用ReLU激活函数、Dropout、最大覆盖池化、LRN层、GPU加速,启发后续技术创新,卷积神经网络研究进入快车道。

AlexNetx后,卷积神经网络,一类网络结构改进调整,一类网络深度增加。

  1. Perceptron(1957)
  2. Neocognitron(198x)
  3. NIN(2013) VGG(2014)
  4. Incepiton V1(2014) MSRANet(2014)
  5. Incepiton V2(2015) ResNet(2015)
  6. Incepiton V3(2015) ResNet V2(2015)
  7. Inception ResNet V2(2016)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2013年,颜水成教授,Network in Network首次发表,优化卷积神经网络结构,推广1x1卷积结构。2014年,Google Incepiton Net V1,Inception Module,反复堆叠高效卷积网络结构,ILSVRC 2014冠军。2015年初,Incepiton V2,Batch Normalization,加速训练过程,提升网络性能。2015年末,Inception V3,Factorization in Small Convolutions思想,分解大尺寸卷积为多个小卷积或一维卷积。

2014年,ILSVRC亚军,VGGNet,全程3x3卷积,19层网络。季军MSRA-Net(微软)也是深层网络。2015年,微软ResNet,152层网络,ILSVRC 2015冠军,top-5错误率3.46%。ResNet V2,Batch Normalization,去除激活层,用Identity Mapping或Preactivation,提升网络性能。Inception ResNet V2,融合Inception Net网络结构,和ResNet训练极深网络残差学习模块。

GPU计算资源,开源工具。

循环神经网络(RNN),NLP(Nature Language Processing,自然语言处理)最常用神经网络结构。Word2Vec,语言字词转化稠密向量(Dense Vector)。

Word2Vec,Word Embeddings,词向量或词嵌入。语言字词转向量形式表达(Vector Representations)模型。图片,像素点稠密矩阵,音频,声音信号频谱数据。

One-Hot Encoder,字词转离散单独符号。一个词对应一个向量,整篇文章对应一个稀疏矩阵。文本分类模型,Bag of Words,稀疏矩阵合并为一个向量,每个词对应向量计数,统计词出现次数,作为特征。特征编码随机,没有关联信息,没有字词关系。稀疏向量需要更多数据训练,训练效率低,计算麻烦。

向量表达(Vector Representations),向量空间模型(Vector Space Models),字词转连续值向量表达,意思相近词映射向量空量空间相近位置。向量空间模型在NLP依赖假设Distributional Hypothesis,相同语境词语义相近。向量空间模型,分两类,计数模型(Latent Semantic Analysis),预测模型(Neural Probabilistic Language Models)。计数模型统计语料库相邻词频率,计数统计结果转小稠密矩阵,预测模型根据词周围相邻词推测出这个词和空间向量。

Word2Vec,计算非常高效,从原始语料学习字词空间向量预测模型。CBOW(Continuous Bag of Words)模式从原始语句推测目标字词,适合小型数据。Skip-Gram从目标字词推测原始语句,适合大型语料。意思相近词向量空间位置接近。

预测模型(Neural Probabilistic Language Models),用最大似然方法,给定前语句h,最大化目标词汇Wt概率。计算量大,需计算词汇表所有单词出现可能性。Word2Vec CBOw模型,只需训练二元分类模型,区分真实目标词汇、编造词汇(噪声)两类。少量噪声词汇估计,类似蒙特卡洛模拟。

模型预测真实目标词汇高概率,预测其他噪声词汇低概率,训练学习目标最优化。编造噪声词汇训练,Negative Sampling,计算loss fuction效率非常高,只需计算随机选择k个词汇,训练速度快。Noise_contrastive Estimation(NCE) Loss,TensorFlow tf.nn.nce_loss。

Word2Vec Skip-Gram模式。构造语境与目标词汇映射关系。语境包括单词左边和右边词汇。滑窗尺寸 1。Skip-Gram模型,从目标词汇预测语境。制造随机词汇作负样本(噪声)。预测概率分布,正样本尽可能大,随机产生负样本尺可能小。优化算法(SGD)更新模型Word Embedding参数,概率分布损失函数(NCE Loss)尽可能小。单词Embedded Vector随训练过程调整,直到最适合语料空间位置。损失函数最小,最符合语料,预测正确单词概率最高。

载入依赖库。

定义下载广西数据函数,urllib.request.urlretrieve下载数据压缩文件核文件尺寸。已下载跳过。

解压下载压缩文件,tf.compat.as_str 数据转单词列表。数据转为17005207单词列表。

创建vocabulary词汇表,collections.Counter统计单词列表单词频数,most_common方法取top 50000频数单词作vocabulary。创建dict,top 50000词汇vocabulary放入dictionary,快速查询。Python dict查询复杂度O(1),性能好。全部单词转编号(频数排序编号)。top50000以外单词,认定为Unkown(未知),编号0,统计数量。遍历单词列表,每个单词,判断是否出现在dictionary,是转编号,不是编0。返回转换编码(data)、单词频数统计count、词汇表(dictionary)、反转形式(reverse_dictionary)。

删除原始单词列表,节约内存。打印vocabulary最高频词汇、数量(包括Unknow词汇)。“UNK”类418391个。“the”1061396个。“of”593677个。data前10单词[‘anarchism’,’originated’,’as’,’a’,’term’,’of’,’abuse’,’first’,’used’,’against’],编号[5235,3084,12,6,195,2,3137,46,59,156]。

生成Word2Vec训练样本。Skip-Gram模式(从目标单词反推语境)。定义函数generate_batch生成训练batch数据。参数batch_size为batch大小。skip_window单词最远可联系距离,设1只能跟紧邻两个单词生成样本。num_skips单词生成样本个数,不能大于skip_window两倍,batch_size是它的整数倍,确保batch包含词汇所有样本。

单词序号data_index为global变量,反复调用generate_batch,确保data_index可以在函数genetate_batch修改。assert确保num_skips、batch_size满足条件。np.ndarray初始化batch、labels为数组。定义span 单词创建相关样本单词数量,包括目标单词和前后单词,span=2*skip_window+1。创建最大容量span deque,双向队列,deque append方法添加变量,只保留最后插入span个变量。

从序号data_index开始,span个单词顺序读入buffer作初始值。buffer容量为span deque,已填满,后续数据替换前面数据。

第一层循环(次数batch_size//num_skips),循环内目标单词生成样本。buffer目标单词和所有相关单词,定义target-skip_window,buffer第skip_window个变量为目标单词。定义生成样本需避免单词列表,tagets_to_avoid,列表开始包括第skip_window个单词(目标单词),预测语境单词,不包括目标单词。

第二层循环(次数num_skips),循环语境单词生成样本,先产生随机数,直到随机数不在targets_to_avoid中,代表可用语境单词,生成样本,feature目标词汇buffer[skip_window],label是buffer[target]。语境单词使用,添加到targets_to_avoid过滤。目标单词所有样本生成完(num_skips个),读入下一个单词,抛掉buffer第一个单词,滑窗向后移动一位,目标单词向后移动一个,语境单词整体后移,开始生成下一个目标单词训练样本。

两层循环完成,获得batch_size个训练样本。返回batch、labels。

调用generate_batch函数测试。参数batch_size设8,num_skips设2,skip_window设1,执行generate_batch获得batch、labels,打印。

定义训练batch_size 128,embedding_size 128。embedding_size,单词转稠密向量维度,50〜1000。skip_window单词间最远联系距离设1,num_skips目标单词提取样本数设2.生成验证数据valid_examples。随机抽取频数最高单词,看向量空间最近单词是否相关性高。valid_size设16抽取验证单词数。valid_window设100验证单词频为最高100个单词抽取。np.random.choice函数随机抽取。num_sampled训练负样本噪声单词数量。

定义Skip_Gram Word2Vec模型网络结构。创建f.Graph,设置为默认graph。创建训练数据inputs、labels placeholder,随机产生valid_examples转TensorFlow constant。with tf.device(‘/cpu:0’)限定所有计算在CPU执行。tf.random_uniform随机生成所有单词词向量embeddings,单词表大小50000,向量维度128,tf.nn.embedding_lookup查找输入train_inputs对应赂理embed。tf.truncated_normal初始化训练优化目标NCE Loss的权重参数nce_weights,nce_biases初始化0。tf.nn.nce_loss计算学习词向量embedding训练数据loss,tf.reduce_mean汇总。

定义优化器SGD ,学习速率1.0。计算嵌入向量embeddings L2范数norm,embeddings除L2范数得标准化normalized_embeddings。tf.nn.embedding_lookup查询验证单词嵌入向量,计算验证单词嵌入同与词汇表所有单词相似性。tf.global_variables_initializer初始化所有模型参数。

定义最大迭代次数10万次,创建设置默认session,执行参数初始化。迭代中,generate_batch生成batch inputs、labels数据,创建feed_dict。session.run()执行优化器运算(参数更新)和损失计算,训练loss累积到avegage_loss。

每2000次循环,计算平均loss,显示。

每10000次循环,计算验证单词和全部单词相似度,验证单词最相似8个单词展示。

训练模型对名词、动词、形容词类型单词相似词汇识别非常准确。Skip-Gram Word2Vec 向量空间表达(Vetor Representations)质量非常高,近义词在向量空间位置非常靠近。

定义可视化Word2Vec效果函数。low_dim_embs降给到2维单词空间向量,图表展示单词位置。plt.scatter(matplotlib.pyplot)显示散点图(单词位置),plt.annotate展示单词本身。plt.savefig保存图片到本地文件。

sklearn.manifold.TSNe实现降维,原始128维嵌入同量降到2维,plot_sith_labels函数展示。只展示词频最高100个单词可视化结果。

距离相近单词,语义高相似性。左上角单个字母聚集地。冠词聚集在左边中部。Word2Vec性能评价,可视化观察,Analogical Reasoning直接预测语义、语境关系。回答填空问题。大规模语料库,参数调试选取最适合值。

  1. import collections
  2. import math
  3. import os
  4. import random
  5. import zipfile
  6. import numpy as np
  7. import urllib
  8. import tensorflow as tf
  9. # Step 1: Download the data.
  10. url = 'http://mattmahoney.net/dc/'
  11. def maybe_download(filename, expected_bytes):
  12. if not os.path.exists(filename):
  13. filename, _ = urllib.request.urlretrieve(url + filename, filename)
  14. statinfo = os.stat(filename)
  15. if statinfo.st_size == expected_bytes:
  16. print('Found and verified', filename)
  17. else:
  18. print(statinfo.st_size)
  19. raise Exception(
  20. 'Failed to verify ' + filename + '. Can you get to it with a browser?')
  21. return filename
  22. filename = maybe_download('text8.zip', 31344016)
  23. # Read the data into a list of strings.
  24. def read_data(filename):
  25. with zipfile.ZipFile(filename) as f:
  26. data = tf.compat.as_str(f.read(f.namelist()[0])).split()
  27. return data
  28. words = read_data(filename)
  29. print('Data size', len(words))
  30. # Step 2: Build the dictionary and replace rare words with UNK token.
  31. vocabulary_size = 50000
  32. def build_dataset(words):
  33. count = [['UNK', -1]]
  34. count.extend(collections.Counter(words).most_common(vocabulary_size - 1))
  35. dictionary = dict()
  36. for word, _ in count:
  37. dictionary[word] = len(dictionary)
  38. data = list()
  39. unk_count = 0
  40. for word in words:
  41. if word in dictionary:
  42. index = dictionary[word]
  43. else:
  44. index = 0 # dictionary['UNK']
  45. unk_count += 1
  46. data.append(index)
  47. count[0][1] = unk_count
  48. reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
  49. return data, count, dictionary, reverse_dictionary
  50. data, count, dictionary, reverse_dictionary = build_dataset(words)
  51. del words # Hint to reduce memory.
  52. print('Most common words (+UNK)', count[:5])
  53. print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])
  54. data_index = 0
  55. # Step 3: Function to generate a training batch for the skip-gram model.
  56. def generate_batch(batch_size, num_skips, skip_window):
  57. global data_index
  58. assert batch_size % num_skips == 0
  59. assert num_skips <= 2 * skip_window
  60. batch = np.ndarray(shape=(batch_size), dtype=np.int32)
  61. labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
  62. span = 2 * skip_window + 1 # [ skip_window target skip_window ]
  63. buffer = collections.deque(maxlen=span)
  64. for _ in range(span):
  65. buffer.append(data[data_index])
  66. data_index = (data_index + 1) % len(data)
  67. for i in range(batch_size // num_skips):
  68. target = skip_window # target label at the center of the buffer
  69. targets_to_avoid = [ skip_window ]
  70. for j in range(num_skips):
  71. while target in targets_to_avoid:
  72. target = random.randint(0, span - 1)
  73. targets_to_avoid.append(target)
  74. batch[i * num_skips + j] = buffer[skip_window]
  75. labels[i * num_skips + j, 0] = buffer[target]
  76. buffer.append(data[data_index])
  77. data_index = (data_index + 1) % len(data)
  78. return batch, labels
  79. batch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1)
  80. for i in range(8):
  81. print(batch[i], reverse_dictionary[batch[i]],
  82. '->', labels[i, 0], reverse_dictionary[labels[i, 0]])
  83. # Step 4: Build and train a skip-gram model.
  84. batch_size = 128
  85. embedding_size = 128 # Dimension of the embedding vector.
  86. skip_window = 1 # How many words to consider left and right.
  87. num_skips = 2 # How many times to reuse an input to generate a label.
  88. valid_size = 16 # Random set of words to evaluate similarity on.
  89. valid_window = 100 # Only pick dev samples in the head of the distribution.
  90. valid_examples = np.random.choice(valid_window, valid_size, replace=False)
  91. num_sampled = 64 # Number of negative examples to sample.
  92. graph = tf.Graph()
  93. with graph.as_default():
  94. # Input data.
  95. train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
  96. train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
  97. valid_dataset = tf.constant(valid_examples, dtype=tf.int32)
  98. # Ops and variables pinned to the CPU because of missing GPU implementation
  99. with tf.device('/cpu:0'):
  100. # Look up embeddings for inputs.
  101. embeddings = tf.Variable(
  102. tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
  103. embed = tf.nn.embedding_lookup(embeddings, train_inputs)
  104. # Construct the variables for the NCE loss
  105. nce_weights = tf.Variable(
  106. tf.truncated_normal([vocabulary_size, embedding_size],
  107. stddev=1.0 / math.sqrt(embedding_size)))
  108. nce_biases = tf.Variable(tf.zeros([vocabulary_size]))
  109. loss = tf.reduce_mean(
  110. tf.nn.nce_loss(weights=nce_weights,
  111. biases=nce_biases,
  112. labels=train_labels,
  113. inputs=embed,
  114. num_sampled=num_sampled,
  115. num_classes=vocabulary_size))
  116. # Construct the SGD optimizer using a learning rate of 1.0.
  117. optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)
  118. # Compute the cosine similarity between minibatch examples and all embeddings.
  119. norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
  120. normalized_embeddings = embeddings / norm
  121. valid_embeddings = tf.nn.embedding_lookup(
  122. normalized_embeddings, valid_dataset)
  123. similarity = tf.matmul(
  124. valid_embeddings, normalized_embeddings, transpose_b=True)
  125. # Add variable initializer.
  126. init = tf.global_variables_initializer()
  127. # Step 5: Begin training.
  128. num_steps = 100001
  129. with tf.Session(graph=graph) as session:
  130. init.run()
  131. print("Initialized")
  132. average_loss = 0
  133. for step in range(num_steps):
  134. batch_inputs, batch_labels = generate_batch(
  135. batch_size, num_skips, skip_window)
  136. feed_dict = {train_inputs : batch_inputs, train_labels : batch_labels}
  137. _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)
  138. average_loss += loss_val
  139. if step % 2000 == 0:
  140. if step > 0:
  141. average_loss /= 2000
  142. # The average loss is an estimate of the loss over the last 2000 batches.
  143. print("Average loss at step ", step, ": ", average_loss)
  144. average_loss = 0
  145. # Note that this is expensive (~20% slowdown if computed every 500 steps)
  146. if step % 10000 == 0:
  147. sim = similarity.eval()
  148. for i in range(valid_size):
  149. valid_word = reverse_dictionary[valid_examples[i]]
  150. top_k = 8 # number of nearest neighbors
  151. nearest = (-sim[i, :]).argsort()[1:top_k+1]
  152. log_str = "Nearest to %s:" % valid_word
  153. for k in range(top_k):
  154. close_word = reverse_dictionary[nearest[k]]
  155. log_str = "%s %s," % (log_str, close_word)
  156. print(log_str)
  157. final_embeddings = normalized_embeddings.eval()
  158. # Step 6: Visualize the embeddings.
  159. def plot_with_labels(low_dim_embs, labels, filename='tsne.png'):
  160. assert low_dim_embs.shape[0] >= len(labels), "More labels than embeddings"
  161. plt.figure(figsize=(18, 18)) #in inches
  162. for i, label in enumerate(labels):
  163. x, y = low_dim_embs[i,:]
  164. plt.scatter(x, y)
  165. plt.annotate(label,
  166. xy=(x, y),
  167. xytext=(5, 2),
  168. textcoords='offset points',
  169. ha='right',
  170. va='bottom')
  171. plt.savefig(filename)
  172. #%%
  173. try:
  174. from sklearn.manifold import TSNE
  175. import matplotlib.pyplot as plt
  176. tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000)
  177. plot_only = 200
  178. low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only,:])
  179. labels = [reverse_dictionary[i] for i in range(plot_only)]
  180. plot_with_labels(low_dim_embs, labels)
  181. except ImportError:
  182. print("Please install sklearn, matplotlib, and scipy to visualize embeddings.")

参考资料: 
《TensorFlow实战》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/367128?site
推荐阅读
相关标签
  

闽ICP备14008679号