您的位置:

word2vec代码实现详解

一、word2vec代码实现生成器

在介绍word2vec代码实现前,我们先来认识一个能够生成word2vec代码的生成器,它可以方便我们快速生成、修改和调试word2vec代码。生成器的基本思路是根据word2vec原论文中的公式和参数来生成代码,同时提供了一些可修改的参数和选项。

以下是一个简单示例:

<html>
 <head>
   <title>word2vec代码生成器</title>
 </head>
 <body>
   <form>
     <label>Embedding size:</label>
     <input type="text" name="size" value="300"><br>
     <label>Window size:</label>
     <input type="text" name="window" value="5"><br>
     <label>Negative samples:</label>
     <input type="text" name="neg" value="5"><br>
     <label>Epochs:</label>
     <input type="text" name="epochs" value="5"><br>
     <input type="submit" value="Generate">
   </form>
   <pre><code>
     # Here goes your generated code
   </code></pre>
 </body>
</html>

上面是一个基于HTML和Python的简易生成器示例,通过修改输入框中的参数,点击“Generate”按钮可以快速生成word2vec代码,并在页面中显示。

二、word2vec代码实现

在word2vec代码实现中,主要包括以下几个部分:

1. 数据预处理

在数据预处理阶段,我们需要对原始文本进行分词、建立词表并将文本转化为数值矩阵,以便后续神经网络模型训练。

以下是一个简单的数据预处理代码示例:

import numpy as np
import pandas as pd
import jieba

def preprocess_text(text_path, stopwords_path):
    # Load text and stop words
    with open(text_path, 'r', encoding='utf-8') as f:
        text = f.read()
    with open(stopwords_path, 'r', encoding='utf-8') as f:
        stopwords = [line.strip() for line in f]
        
    # Cut text into words
    words = jieba.cut(text)
    words = [word for word in words if word not in stopwords]
    
    # Build word table
    word_set = set(words)
    word_dict = dict(zip(word_set, range(len(word_set))))
    
    # Convert text to matrix
    matrix = np.zeros((len(words), len(word_set)))
    for i, word in enumerate(words):
        matrix[i, word_dict[word]] = 1
    
    # Return word dictionary and matrix
    return word_dict, matrix

上面的代码中使用了jieba库进行中文分词,建立了一个词表并将文本转化为矩阵。

2. Skip-gram模型

Skip-gram模型是word2vec最常用的模型之一,它的基本思路是通过一个中心词预测周围的词语。在训练过程中,我们使用神经网络来最大化预测正确词语的概率。

以下是一个简单的Skip-gram模型代码示例:
import tensorflow as tf

class SkipGramModel:
    def __init__(self, vocab_size, embedding_size, num_sampled=5):
        self.vocab_size = vocab_size
        self.embedding_size = embedding_size
        self.num_sampled = num_sampled
        
        self.input_words = tf.placeholder(tf.int32, shape=[None])
        self.output_words = tf.placeholder(tf.int32, shape=[None, 1])
        
        with tf.variable_scope('embedding'):
            embedding_matrix = tf.get_variable('embedding_matrix', 
                                                shape=[self.vocab_size, self.embedding_size], 
                                                initializer=tf.contrib.layers.xavier_initializer())
            embedding = tf.nn.embedding_lookup(embedding_matrix, self.input_words)
        
        with tf.variable_scope('nsc_loss'):
            nce_weights = tf.get_variable('nce_weights', 
                                          shape=[self.vocab_size, self.embedding_size], 
                                          initializer=tf.contrib.layers.xavier_initializer())
            nce_biases = tf.get_variable('nce_biases',
                                         shape=[self.vocab_size],
                                         initializer=tf.zeros_initializer())
            self.loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weights,
                                                      biases=nce_biases,
                                                      labels=self.output_words,
                                                      inputs=embedding,
                                                      num_sampled=self.num_sampled,
                                                      num_classes=self.vocab_size))
        self.optimizer = tf.train.AdamOptimizer().minimize(self.loss)

上面的代码中,SkipGramModel类接收词表大小、嵌入维度和负样本数量作为参数,定义了两个占位符(input_words和output_words),使用tf.nn.embedding_lookup建立嵌入矩阵,同时使用tf.nn.nce_loss计算最终的损失,并采用Adam优化器进行参数更新。

3. 训练模型

训练模型时,我们需要使用预处理过的文本数据和Skip-gram模型进行训练,以最终获得每个单词的嵌入向量。

以下是一个简单的训练代码示例:
def train_model(word_dict, matrix, embedding_size=300, window_size=5, 
                num_epochs=5, num_neg_samples=5, batch_size=128, learning_rate=0.01):
    # Initialize model
    model = SkipGramModel(len(word_dict), embedding_size, num_neg_samples)
    session = tf.Session()
    session.run(tf.global_variables_initializer())
    
    # Train model
    for epoch in range(num_epochs):
        for i in range(0, len(matrix), batch_size):
            batch_matrix = matrix[i:i+batch_size]
            pos_samples = []
            neg_samples = []
            
            for j in range(len(batch_matrix)):
                input_word_idx = np.where(batch_matrix[j]==1)[0][0]
                output_word_indices = []
                
                for k in range(max(0, j-window_size), min(j+window_size+1, len(batch_matrix))):
                    if k != j:
                        output_word_indices.append(np.where(batch_matrix[k]==1)[0][0])
                
                for output_word_idx in output_word_indices:
                    pos_samples.append((input_word_idx, output_word_idx))
                    
                    for _ in range(num_neg_samples):
                        neg_samples.append((input_word_idx, np.random.randint(0, len(word_dict))))
            
            np.random.shuffle(pos_samples)
            np.random.shuffle(neg_samples)
            input_words = [sample[0] for sample in pos_samples+neg_samples]
            output_words = [[sample[1]] for sample in pos_samples+neg_samples]
            
            feed_dict = {model.input_words: input_words, model.output_words: output_words}
            loss, _ = session.run([model.loss, model.optimizer], feed_dict=feed_dict)
            
        print('Epoch {}/{}: Loss = {:.5f}'.format(epoch+1, num_epochs, loss))
            
    # Get embeddings
    embeddings = session.run(tf.get_default_graph().get_tensor_by_name('embedding/embedding_matrix:0'))
    session.close()
    
    # Return word embeddings and dictionary
    return embeddings, word_dict

上面的代码中,train_model函数采用批量学习的方式进行训练,每次从所有单词中随机选择一个并生成正样本和负样本,使用SkipGramModel类计算损失并更新参数。训练结束后,通过调用embedding_lookup函数获取每个单词的嵌入向量。

三、word2vec相关参数介绍

除了以上的核心代码实现外,word2vec还涉及到一些常用参数,下面我们将对这些参数进行介绍。

1. 嵌入维度

嵌入维度指的是每个单词嵌入向量的维度,通常在100~300之间。较小的维度可能无法完全表达一个单词的语义信息,而过大的维度则容易导致模型过拟合。

2. 窗口大小

窗口大小指的是在Skip-gram模型中,中心词左右各取几个词作为上下文。通常取值为5~10之间,太小会导致模型无法捕捉到更多上下文信息,太大则容易导致噪音的引入。

3. 负采样数

负采样数指的是在Skip-gram模型中,每个正样本要采样多少个负样本。通常取值为5~20之间。

四、结语

通过本文详细介绍,我们了解了word2vec的基本思路和代码实现,并介绍了一些常用参数和选项。在使用word2vec时,我们可以基于相关工具和代码进行快速生成和调整,以便获得更好的结果。