TensorFlow study notes 4

In the third study note, we implemented two simple models, linear regression and logistic regression. For networks with simple model structures, we do not need to deal with their structural relationships, but in complex models, we need more The structure of the model is arranged well, which is convenient for us to debug and visualize. Next, let's discuss how to structure our model.


Structured Models in TensorFlow

Generally, our model is composed of the following two steps. The first step is to construct the calculation graph, and the second step is to execute the calculation graph. Let's take a look at how to structure the model in these two steps.


Build computational graphs

In constructing the calculation graph, it is generally divided into the following 5 steps:

1. Define placeholders for input and output

2. Define the weights that need to be used in the model

3. Define the inference model and build the network

4. Define the loss function as the optimization object

5. Define the optimizer to optimize


Execute computational graph

After defining the calculation graph, we can build a session to perform operations, which are generally divided into the following 5 steps:

1. When the first operation is performed, initialize all the parameters of the model

2. Incoming training data, you can shuffle the order

3. Network forward propagation, calculate the network output under the current parameters

4. Calculate loss based on network output and target

5. Update parameters in the network through loss direction propagation


Below is a visual diagram


Example introduction

The above is a basic general description. Let's use the specific example of word vector and skip-gram to introduce how to structure the model. If you are not familiar with word vector, you can check this article of mineA brief introduction, more detailed introduction can read this blog postOr the courseware of cs224n


A brief introduction to word vectors

词向量简单来说就是用一个向量去表示一个词语,但是这个向量并不是随机的,因为这样并没有任何意义,所以我们需要对每个词有一个特定的向量去表示他们,而有一些词的词性是相近的,比如"(love)喜欢"和"(like)爱",对于这种词性相近的词,我们需要他们的向量表示也能够相近,如何去度量和定义向量之间的相近呢?非常简单,就是使用两个向量的夹角,夹角越小,越相近,这样就有了一个完备的定义。

虽然我们知道了如何定义词向量的相似性,但是我们仍然不知道如何得到词向量,因为这显然不可能人为去赋值,为了得到词向量,需要介绍skip-gram模型。


skip-gram模型的简单介绍

skip-gram模型简单来讲就是在一大段话中,我们给定其中一个词语,希望预测它周围的词语,将词向量作为参数,通过这种方式来训练词向量,最后能够得到满足要求的词向量。而一般来讲,skip-gram模型都是比较简单的线性模型。另外cs224n中还介绍了Noise Contrastive Estimation(不知道怎么翻译)的方法,这里就不再详细介绍了,这只是一种负样本的取样方法。


TensorFlow实现

下面使用tensorflow的实现来具体讲解一下如何结构化模型,首先我们会实现一个非结构化版本,看看他的局限性和不足性,然后讲解一下如何结构化模型。


数据集

这里使用的是text8数据集,这是一个大约100 MB的清理过的数据集,当然这个数据集非常小并不足以训练词向量,但是我们可以得到一些有趣的结果。


构建计算图

首先定义好一些超参数。

VOCAB_SIZE = 50000
BATCH_SIZE = 128
EMBED_SIZE = 128 # dimension of the word embedding vectors
SKIP_WINDOW = 1 # the context window
NUM_SAMPLED = 64 # Number of negative examples to sample.
LEARNING_RATE = 1.0
NUM_TRAIN_STEPS = 20000
SKIP_STEP = 2000 # how many steps to skip before reporting the loss

1. 建立输入和输出的占位符(placeholder)

首先,我们将数据集中的所有语句按顺序排在一起,那么我们输入的是其中一个词语,比如说是第300个,那么要预测的就是他周围的词,比如第301个词,或者299个词,当然这个范围并不一定是1,一般来讲可以预测左边3个词和右边3个词中的任何一个,所以输入和输出的占位符定义如下。

center_word = tf.placeholder(tf.int32, [BATCH_SIZE], name='center_words')
y = tf.placeholder(tf.int32, [BATCH_SIZE, SKIP_WINDOW], name='target_words')

这里SKIP_WINDOW表示预测周围词的数目,超参数里面取值为1。


2. 定义词向量矩阵

接下来需要定义词向量,使用下面的代码。

embed_matrix = tf.get_variable(
                 "WordEmbedding", [VOCAB_SIZE, EMBED_SIZE],
                  tf.float32,
                  initializer=tf.random_uniform_initializer(-1.0, 1.0))

这里相当于新建一个Variable,维数分别是总的词数x词向量的维度。


3. 构建网络模型

我们可以通过下面的操作取到词向量矩阵中所需要的每一个词的词向量。

embed = tf.nn.embedding_lookup(embed_matrix, center_word, name='embed')

这里embed_matrix和center_word分别表示词向量矩阵和需要提取词向量的单词,我们都已经定义过了。


4. 定义loss函数

NCE已经被集成进了tensorflow,所以我们可以非常方便地进行使用,下面就是具体的api。

tf.nn.nce_loss(weights, biases, labels, inputs, num_sampled,
               num_classes, num_true=1, sampled_values=None, 
               remove_accidental_hits=False, partition_strategy='mod', 
               name='nce_loss')

labels和inputs分别是target和输入的词向量,前面有两个参数分别时weights和biases,因为词向量的维度一般不等于分类的维度,需要将词向量通过一个线性变换映射到分类下的维度。有了这个定义之后,我们就能够简单地进行实现了。

nce_weight = tf.get_variable('nce_weight', [VOCAB_SIZE, EMBED_SIZE],
                             initializer=tf.truncated_normal_initializer(
                                           stddev=1.0 / (EMBED_SIZE**0.5)))

nce_bias = tf.get_variable('nce_bias', [VOCAB_SIZE], 
                          initializer=tf.zeros_initializer())

nce_loss = tf.nn.nce_loss(nce_weight, nce_bias, y, embed,
                         NUM_SAMPLED,
                         VOCAB_SIZE)
loss = tf.reduce_mean(nce_loss, 0)


5. 定义优化函数

接下来我们就可以定义优化函数了,非常简单,我们使用随机梯度下降法。

optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)


执行计算图

构建完成计算图之后,我们就开始执行计算图了,下面就不分开讲了,直接放上整段session里面的内容。

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    total_loss = 0.0 
    # we use this to calculate the average loss in the last SKIP_STEP steps0
    writer = tf.summary.FileWriter('./graphs/no_frills/', sess.graph)
    for index in range(NUM_TRAIN_STEPS):
        centers, targets = next(batch_gen)
        train_dict = {center_word: centers, y: targets}
        _, loss_batch = sess.run([optimizer, loss], feed_dict=train_dict)
        total_loss += loss_batch
        if (index + 1) % SKIP_STEP == 0:
        print('Average loss at step {}: {:5.1f}'.format(
               index, total_loss / SKIP_STEP))
        total_loss = 0.0
    writer.close()

通过阅读代码,也能看到非常清晰的结构,一步一步去运行结果。


最后放上tensorboard中网络结构的示意图。


可以发现整体的网络结构是非常混乱的,所以我们需要结构化我们的模型。


结构化网络

结构化网络非常简单,只需要加入Name Scope,下面是一个简单的事例。

with tf.name_scope(name_of_taht_scope):
# declare op_1
# declare op_2
# ...


举一个例子,比如我们定义输入输出的占位符的时候,可以如下方式定义

with tf.name_scope('data'):
   center_word = tf.placeholder(
           tf.int32, [BATCH_SIZE], name='center_words')
   y = tf.placeholder(
           tf.int32, [BATCH_SIZE, SKIP_WINDOW], name='target_words')


然后我们运行相同的代码,就能够在tensorboard里面得到下面的结果。


是不是结构非常的清楚,所以我们平时需要结构化我们的模型,以便于更好的可视化和debug。






词向量可视化

最后在介绍一下词向量的可视化,现在tensorboraad也支持词向量的可视化了,进行一系列复杂的操作,就能够在tensorboard中得到下面的结果。



输入每个词,都能够在右边看到与之词性相近的词语分别是什么,特别方便,这个可视化的代码在这个文件中。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326010124&siteId=291194637