tensorflow学习:使用tensorflow实现word embedding

今天学习使用tensorflow实现word embedding,下面的例子来自于tensorflow的官方文档,实现word embedding本身是比较复杂的,下文只用比较简单的方法实现,限于本人刚入门,水平有限,有些细节还没有彻底搞明白,还需要再花些时间研究,现把今天的研究成果记下供日后继续完善。

文本参考:https://liusida.github.io/2016/11/14/study-embeddings/ 感谢作者的努力与奉献

程序功能:

程序下载一份英文语料库,然后使用word2vec+skip-gram实现word的embedding,最后使用t-SNE选取部分点降维可视化。

# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Basic word2vec example."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections
import math
import os
import random
import zipfile

import numpy as np
from six.moves import urllib
from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

# Step 1: Download the data.
url = 'http://mattmahoney.net/dc/'


def maybe_download(filename, expected_bytes):
  """下载数据集,文件中没有标点,全部小写,词与词之间用空格隔开."""
  if not os.path.exists(filename):
    filename, _ = urllib.request.urlretrieve(url + filename, filename)
  statinfo = os.stat(filename)
  if statinfo.st_size == expected_bytes:
    print('Found and verified', filename)
  else:
    print(statinfo.st_size)
    raise Exception(
        'Failed to verify ' + filename + '. Can you get to it with a browser?')
  return filename

filename = maybe_download('text8.zip', 31344016)


# Read the data into a list of strings.
def read_data(filename):
  """Extract the first file enclosed in a zip file as a list of words."""
  with zipfile.ZipFile(filename) as f:
    data = tf.compat.as_str(f.read(f.namelist()[0])).split()
  return data

#读取压缩包中第一个文件的全部内容
vocabulary = read_data(filename)
print('Data size', len(vocabulary))
print ('vocabulary:', vocabulary[:10])

# Step 2: Build the dictionary and replace rare words with UNK token.
vocabulary_size = 50000


def build_dataset(words, n_words):
  """Process raw inputs into a dataset."""
  count = [['UNK', -1]]
  count.extend(collections.Counter(words).most_common(n_words - 1))
  dictionary = dict()
  for word, _ in count:
    dictionary[word] = len(dictionary)
  data = list()
  unk_count = 0
  for word in words:
    if word in dictionary:
      index = dictionary[word]
    else:
      index = 0  # dictionary['UNK']
      unk_count += 1
    data.append(index)
  count[0][1] = unk_count
  reversed_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
  return data, count, dictionary, reversed_dictionary

#data:把原文中的word转化成ID后的串
#count:[word, freq]存储的是word和word对应的出现次数
#dictionary:词到ID的对应关系
#reverse_dictionary:ID到词的对应关系
data, count, dictionary, reverse_dictionary = build_dataset(vocabulary,
                                                            vocabulary_size)
del vocabulary  # Hint to reduce memory.
print('Most common words (+UNK)', count[:5])
print('Sample data', data[:10], [reverse_dictionary[i] for i in data[:10]])

data_index = 0

# Step 3: Function to generate a training batch for the skip-gram model.
#batch_size:
#num_skips:
#skip_window:取一个word周边多远的word来训练
def generate_batch(batch_size, num_skips, skip_window):
  global data_index
  assert batch_size % num_skips == 0
  assert num_skips <= 2 * skip_window
  batch = np.ndarray(shape=(batch_size), dtype=np.int32)
  labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)
  span = 2 * skip_window + 1  # [ skip_window target skip_window ]
  buffer = collections.deque(maxlen=span)
  if data_index + span > len(data):
    data_index = 0
  buffer.extend(data[data_index:data_index + span])
  data_index += span
  for i in range(batch_size // num_skips):
    target = skip_window  # target label at the center of the buffer
    targets_to_avoid = [skip_window]
    for j in range(num_skips):
      while target in targets_to_avoid:
        target = random.randint(0, span - 1)
      targets_to_avoid.append(target)
      batch[i * num_skips + j] = buffer[skip_window]
      labels[i * num_skips + j, 0] = buffer[target]
    if data_index == len(data):
      buffer[:] = data[:span]
      data_index = span
    else:
      buffer.append(data[data_index])
      data_index += 1
  # Backtrack a little bit to avoid skipping words in the end of a batch
  data_index = (data_index + len(data) - span) % len(data)
  return batch, labels

#batch:word对应的ID
#labels:skip-gram算法中word关联的周围的两个word(skip_window=1)
batch, labels = generate_batch(batch_size=8, num_skips=2, skip_window=1)
for i in range(8):
  print(batch[i], reverse_dictionary[batch[i]], '->', labels[i, 0], reverse_dictionary[labels[i, 0]])

print (dictionary['a'], dictionary['as'], dictionary['term'])

# Step 4: Build and train a skip-gram model.

batch_size = 128
embedding_size = 128  # Dimension of the embedding vector.
skip_window = 1       # How many words to consider left and right.
num_skips = 2         # How many times to reuse an input to generate a label.

# We pick a random validation set to sample nearest neighbors. Here we limit the
# validation samples to the words that have a low numeric ID, which by
# construction are also the most frequent.
valid_size = 16     # Random set of words to evaluate similarity on.
valid_window = 100  # Only pick dev samples in the head of the distribution.
#从0-99种随机选取16个数
valid_examples = np.random.choice(valid_window, valid_size, replace=False)
num_sampled = 64    # Number of negative examples to sample.

graph = tf.Graph()

with graph.as_default():

  # Input data.
  train_inputs = tf.placeholder(tf.int32, shape=[batch_size])
  train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])
  valid_dataset = tf.constant(valid_examples, dtype=tf.int32)

  # Ops and variables pinned to the CPU because of missing GPU implementation
  with tf.device('/cpu:0'):
    # Look up embeddings for inputs.
    embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))
    #根据embeddings取出与输入word(train_inputs)对应的128维的向量,内部实现原理稍后再研究
    embed = tf.nn.embedding_lookup(embeddings, train_inputs)
    
    # Construct the variables for the NCE loss
    nce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size], stddev=1.0 / math.sqrt(embedding_size)))
    nce_biases = tf.Variable(tf.zeros([vocabulary_size]))

  # Compute the average NCE loss for the batch.
  # tf.nce_loss automatically draws a new sample of the negative labels each
  # time we evaluate the loss.
  loss = tf.reduce_mean(
      tf.nn.nce_loss(weights=nce_weights,
                     biases=nce_biases,
                     labels=train_labels,
                     inputs=embed,
                     num_sampled=num_sampled,
                     num_classes=vocabulary_size))

  # Construct the SGD optimizer using a learning rate of 1.0.
  optimizer = tf.train.GradientDescentOptimizer(1.0).minimize(loss)

  # Compute the cosine similarity between minibatch examples and all embeddings.
  # embeddings的二范数,就是向量的长度
  norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keep_dims=True))
  # 对向量标准化成单位向量
  normalized_embeddings = embeddings / norm
  # 根据normalized_embeddings取出与输入word(valid_dataset)对应的128维的向量
  valid_embeddings = tf.nn.embedding_lookup(normalized_embeddings, valid_dataset)
  # 计算valid_embeddings和normalized_embeddings的cosine(两个向量都是单位向量)
  # 估计是从normalized_embeddings中挑选和valid_embeddings最相似的word
  similarity = tf.matmul(valid_embeddings, normalized_embeddings, transpose_b=True)

  # Add variable initializer.
  init = tf.global_variables_initializer()

# Step 5: Begin training.
num_steps = 40001

with tf.Session(graph=graph) as session:
  # We must initialize all variables before we use them.
  init.run()
  print('Initialized')

  average_loss = 0
  for step in xrange(num_steps):
    batch_inputs, batch_labels = generate_batch(batch_size, num_skips, skip_window)
    feed_dict = {train_inputs: batch_inputs, train_labels: batch_labels}

    # We perform one update step by evaluating the optimizer op (including it
    # in the list of returned values for session.run()
    _, loss_val = session.run([optimizer, loss], feed_dict=feed_dict)
    average_loss += loss_val

    if step % 2000 == 0:
      if step > 0:
        average_loss /= 2000
      # The average loss is an estimate of the loss over the last 2000 batches.
      print('Average loss at step ', step, ': ', average_loss)
      average_loss = 0

    # Note that this is expensive (~20% slowdown if computed every 500 steps)
    # 将最相似的八个词输出到屏幕
    if step % 10000 == 0:
      sim = similarity.eval()
      for i in xrange(valid_size):
        valid_word = reverse_dictionary[valid_examples[i]]
        top_k = 8  # number of nearest neighbors
        nearest = (-sim[i, :]).argsort()[1:top_k + 1]
        log_str = 'Nearest to %s:' % valid_word
        for k in xrange(top_k):
          close_word = reverse_dictionary[nearest[k]]
          log_str = '%s %s,' % (log_str, close_word)
        print(log_str)
  final_embeddings = normalized_embeddings.eval()

# Step 6: Visualize the embeddings.

def plot_with_labels(low_dim_embs, labels, filename='tsne.png'):
  assert low_dim_embs.shape[0] >= len(labels), 'More labels than embeddings'
  plt.figure(figsize=(18, 18))  # in inches
  for i, label in enumerate(labels):
    x, y = low_dim_embs[i, :]
    plt.scatter(x, y)
    plt.annotate(label,
                 xy=(x, y),
                 xytext=(5, 2),
                 textcoords='offset points',
                 ha='right',
                 va='bottom')

  plt.savefig(filename)

try:
  # 如果维度过高(比如1024维),建议先使用PCA降维到50维左右,再使用tsne继续降到2到3维
  # 因为直接使用tsne效率比较低
  # pylint: disable=g-import-not-at-top
  from sklearn.manifold import TSNE
  import matplotlib.pyplot as plt

  # perplexity:一般设置成30即可,这个值一般设置在5到50之间,这个值不少很重要
  # n_components:降到2维
  # init:可选random或者pca, pca相比random更稳健一些
  # n_iter:优化的最大迭代次数,至少要设置到200
  # method:可以取两个值:1.barnes_hut(默认):运行速度快,2.exact:运行慢,但精确
  tsne = TSNE(perplexity=30, n_components=2, init='pca', n_iter=5000, method='exact')
  plot_only = 300  #图上显示点的个数
  low_dim_embs = tsne.fit_transform(final_embeddings[:plot_only, :])
  # 每个点的label,这里取的是word的名字
  labels = [reverse_dictionary[i] for i in xrange(plot_only)]
  plot_with_labels(low_dim_embs, labels)

except ImportError:
  print('Please install sklearn, matplotlib, and scipy to show embeddings.')

运行结果:
Found and verified text8.zip
Data size 17005207
vocabulary: ['anarchism', 'originated', 'as', 'a', 'term', 'of', 'abuse', 'first', 'used', 'against']
Most common words (+UNK) [['UNK', 418391], ('the', 1061396), ('of', 593677), ('and', 416629), ('one', 411764)]
Sample data [5234, 3084, 12, 6, 195, 2, 3137, 46, 59, 156] ['anarchism', 'originated', 'as', 'a', 'term', 'of', 'abuse', 'first', 'used', 'against']
3084 originated -> 12 as
3084 originated -> 5234 anarchism
12 as -> 6 a
12 as -> 3084 originated
6 a -> 195 term
6 a -> 12 as
195 term -> 6 a
195 term -> 2 of
6 12 195
Initialized
Average loss at step  0 :  303.279144287
Nearest to which: extras, bandits, qua, kilts, kabila, blum, america, benedict,
Nearest to but: colonizing, moseley, raphaelite, probabilistic, mei, evil, anaximenes, peek,
Nearest to been: advocacy, bateson, corpus, capitolina, blasts, prostitution, gillian, adolescence,
Nearest to world: shoshone, secondary, galicia, bengalis, privations, palms, ziegler, misconception,
Nearest to with: argues, bd, nagy, olof, greg, fuego, astros, ltcm,
Nearest to all: herod, lehmann, availability, dogmatic, similarities, vanquished, dagger, sae,
Nearest to so: euboea, abridgment, matriculation, hydrates, graphite, replace, ipcc, nutrients,
Nearest to their: shaking, ankara, savior, luigi, musculoskeletal, retaliation, deity, fhm,
Nearest to people: gasolines, compute, filter, herr, gothic, predicted, hortense, rhetoricians,
Nearest to not: hawthorn, nuggets, alabaster, arian, analysis, imagination, skewed, curtiss,
Nearest to from: instances, tess, bypass, christ, abbe, griswold, reconnaissance, puzzle,
Nearest to up: pir, senator, fades, hungarian, battlecruiser, diogo, anatolian, duplications,
Nearest to in: spy, guoyu, juggalo, wasted, plank, dreadful, smelting, setback,
Nearest to these: reprimanded, withholding, vacations, gru, toile, geneticist, bourke, successfully,
Nearest to one: fortunes, sombre, crispin, independents, electrically, override, hg, defendants,
Nearest to system: sparingly, blish, exchequer, soa, blimp, anhydrous, postscript, mauchly,
Average loss at step  2000 :  113.633764172
Average loss at step  4000 :  52.7582999108
Average loss at step  6000 :  33.5904548576
Average loss at step  8000 :  23.1999923706
Average loss at step  10000 :  17.9230210255
Nearest to which: and, inc, course, var, serve, maintain, one, trench,
Nearest to but: and, aberdeen, var, explicit, probabilistic, moseley, illness, decade,
Nearest to been: advocacy, organizations, bateson, manual, patents, acts, adolescence, his,
Nearest to world: secondary, bckgr, names, placing, sanctioned, major, axiom, anime,
Nearest to with: in, and, of, about, around, by, on, bodies,
Nearest to all: similarities, ontario, learn, defendants, two, albania, restless, algorithms,
Nearest to so: leading, euboea, nutrients, zeus, appendages, canada, indicated, afghanistan,
Nearest to their: ankara, deity, bank, agave, tuna, the, ngc, ads,
Nearest to people: compute, predicted, gothic, maintaining, four, ian, transcontinental, push,
Nearest to not: portuguese, dominion, analysis, hawthorn, org, online, space, persecute,
Nearest to from: in, and, of, as, instances, walls, ltd, by,
Nearest to up: senator, hungarian, anatolian, socioeconomic, heuvelmans, economists, prize, fades,
Nearest to in: and, of, by, on, with, nine, at, from,
Nearest to these: successfully, bckgr, hilly, markov, sub, commands, vacations, unaids,
Nearest to one: two, nine, bckgr, molinari, zero, UNK, five, archie,
Nearest to system: holding, cia, hooker, moon, polynomial, center, antisemitism, sleep,
Average loss at step  12000 :  14.0672037274
Average loss at step  14000 :  11.8982646112
Average loss at step  16000 :  9.82810585904
Average loss at step  18000 :  8.32750001115
Average loss at step  20000 :  8.05992223346
Nearest to which: and, that, inc, dtp, salmon, course, many, agouti,
Nearest to but: and, suebi, thoreau, dtp, dye, var, however, agouti,
Nearest to been: advocacy, prostitution, had, by, as, krebs, would, patents,
Nearest to world: secondary, bckgr, names, placing, operatorname, palms, galicia, axiom,
Nearest to with: in, and, for, of, by, about, from, as,
Nearest to all: similarities, algorithms, ontario, learn, the, agouti, defendants, dogmatic,
Nearest to so: euboea, nutrients, aleksander, leading, graphite, zeus, appendages, helsinki,
Nearest to their: his, the, ankara, dasyprocta, agave, tuna, deity, bank,
Nearest to people: compute, four, gothic, predicted, dasyprocta, dtp, maintaining, agouti,
Nearest to not: it, dominion, alabaster, they, portuguese, analysis, circ, agouti,
Nearest to from: in, and, by, with, subkey, on, nine, to,
Nearest to up: senator, hungarian, anatolian, arrogant, localities, vessels, latinus, prize,
Nearest to in: and, at, of, with, on, from, for, nine,
Nearest to these: the, successfully, sanskrit, bats, some, mathrm, bckgr, acacia,
Nearest to one: two, three, six, seven, nine, agouti, eight, dasyprocta,
Nearest to system: hbox, hepburn, postscript, mauchly, holding, alem, cia, polynomial,
Average loss at step  22000 :  7.00414496851
Average loss at step  24000 :  6.88763291979
Average loss at step  26000 :  6.72134333861
Average loss at step  28000 :  6.38215904641
Average loss at step  30000 :  5.92981643927
Nearest to which: that, this, and, it, agouti, one, dtp, inc,
Nearest to but: and, however, suebi, agouti, when, dye, thoreau, var,
Nearest to been: advocacy, prostitution, be, had, by, was, krebs, patents,
Nearest to world: trinomial, secondary, bckgr, names, placing, sponsors, axiom, ziegler,
Nearest to with: in, and, mishnayot, by, from, for, around, six,
Nearest to all: similarities, algorithms, many, agouti, availability, dogmatic, faster, archie,
Nearest to so: euboea, hopwood, crandall, helsinki, appendages, leading, nutrients, aleksander,
Nearest to their: his, the, its, ankara, dasyprocta, ngc, a, tuna,
Nearest to people: compute, gothic, predicted, dtp, push, dasyprocta, maintaining, paired,
Nearest to not: it, they, dominion, also, circ, to, agouti, vaccines,
Nearest to from: in, by, with, and, of, to, nine, subkey,
Nearest to up: hungarian, senator, anatolian, lossy, pir, arrogant, vessels, localities,
Nearest to in: at, and, on, with, of, from, by, for,
Nearest to these: the, some, successfully, spines, sanskrit, many, bats, reprimanded,
Nearest to one: two, seven, eight, four, agouti, six, dasyprocta, circ,
Nearest to system: hbox, hepburn, postscript, alem, cia, mauchly, holding, hooker,
Average loss at step  32000 :  5.96737474769
Average loss at step  34000 :  5.70978498816
Average loss at step  36000 :  5.78236852288
Average loss at step  38000 :  5.49960520446
Average loss at step  40000 :  5.25752883768
Nearest to which: that, this, and, it, agouti, one, also, who,
Nearest to but: and, however, suebi, when, or, agouti, dye, thoreau,
Nearest to been: be, advocacy, had, prostitution, was, by, organizations, were,
Nearest to world: trinomial, secondary, bckgr, placing, names, axiom, status, weston,
Nearest to with: in, mishnayot, around, and, from, between, by, as,
Nearest to all: many, similarities, algorithms, agouti, orion, availability, manipulating, archie,
Nearest to so: euboea, crandall, hopwood, helsinki, appendages, maidens, leading, nutrients,
Nearest to their: his, its, the, vma, dasyprocta, ankara, ngc, some,
Nearest to people: compute, gasolines, gothic, predicted, dtp, push, paired, maintaining,
Nearest to not: it, they, dominion, also, there, vaccines, circ, to,
Nearest to from: in, and, on, with, of, subkey, nine, by,
Nearest to up: senator, hungarian, lossy, arrogant, anatolian, localities, pir, fades,
Nearest to in: at, and, on, sponsors, from, nine, zero, with,
Nearest to these: some, many, spines, the, successfully, bats, both, three,
Nearest to one: two, four, six, three, zero, eight, seven, agouti,
Nearest to system: hepburn, hbox, alem, cia, postscript, holding, hooker, mauchly,
tensorflow学习:使用tensorflow实现word embedding_第1张图片

你可能感兴趣的:(tensorflow,深度学习)