词向量训练skipgram的python实现

skipgram的原理及公式推倒就不详细说了,主要记录一下第一个正向传播和反向传播都自己写的神经网络,也终于体验了一把负采样对于词向量训练速度的惊人提升,感人!虽然最终的时间复杂度依然较高,不过我正在研究同样使用python的gensim为啥这么快的原因!

(明天有时间会把)数据和代码放在本人的github里,写的比较搓,待改进...

1.工具介绍

python: 3.6

电脑:mac本地跑

数据集: text8的英文语料

2. 数据预处理

  • 替换文本中特殊符号
  • 将文本分词
  • 去除文本中的低频词
def preprocess(text, freq=5):
    '''
    对文本进行预处理

    参数
    ---
    text: 文本数据
    freq: 词频阈值
    '''
    # 替换文本中特殊符号
    text = text.lower()
    text = text.replace('.', ' <PERIOD> ')
    text = text.replace(',', ' <COMMA> ')
    text = text.replace('"', ' <QUOTATION_MARK> ')
    text = text.replace(';', ' <SEMICOLON> ')
    text = text.replace('!', ' <EXCLAMATION_MARK> ')
    text = text.replace('?', ' <QUESTION_MARK> ')
    text = text.replace('(', ' <LEFT_PAREN> ')
    text = text.replace(')', ' <RIGHT_PAREN> ')
    text = text.replace('--', ' <HYPHENS> ')
    text = text.replace('?', ' <QUESTION_MARK> ')
    text = text.replace(':', ' <COLON> ')
    words = text.split()

    # 删除低频词,减少噪音影响
    word_counts = Counter(words)
    trimmed_words = [word for word in words if word_counts[word] > freq]

    return trimmed_words

3. 训练样本构建

  • 获取vocabulary,即id->word,和word->id这两个单词映射表。
  • 将文本序列转化为id序列。
  • 剔除停用词:停用词可能频率比较高,采用以下公式来计算每个单词被删除的概率大小。

                                     P \left( w _ { i } \right) = 1 - \sqrt { \frac { t } { f \left( w _ { i } \right) } }

                 其中

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Skip-gram 是一种常用的词向量训练方法,它通过预测一个词周围的词来学习每个词的向量表示。下面是使用 Python 实现 Skip-gram 训练的简单示例。 首先,我们需要导入必要的库: ```python import numpy as np import tensorflow as tf from collections import Counter import random ``` 然后,我们需要定义一些参数: ```python # 语料库文件路径 corpus_file = 'corpus.txt' # 词向量维度 embedding_size = 128 # 跳跃窗口大小 window_size = 5 # 负样本数 num_neg_samples = 64 # 学习率 learning_rate = 0.1 # 迭代次数 num_iterations = 10000 # 每隔多少步输出一次日志 log_interval = 1000 ``` 接下来,我们需要读取语料库文件,并将其中的词转换成数字编码: ```python with open(corpus_file, 'r', encoding='utf-8') as f: corpus = f.read().split() # 统计词频并按照词频从高到低排序 word_counts = Counter(corpus) sorted_vocab = sorted(word_counts, key=word_counts.get, reverse=True) # 生成词汇表和词汇表的反向映射表 vocab_to_int = {word: idx for idx, word in enumerate(sorted_vocab)} int_to_vocab = {idx: word for idx, word in enumerate(sorted_vocab)} # 将语料库中的词转换成数字编码 corpus_int = [vocab_to_int[word] for word in corpus] ``` 之后,我们需要定义 Skip-gram 模型的输入和输出: ```python inputs = tf.placeholder(tf.int32, [None], name='inputs') labels = tf.placeholder(tf.int32, [None, 1], name='labels') ``` 然后,我们需要定义词向量矩阵,这个矩阵的维度是词汇表大小 × 词向量维度: ```python vocab_size = len(vocab_to_int) embedding = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0)) ``` 接下来,我们需要定义损失函数。具体来说,我们用负对数似然损失函数来最小化预测概率和真实值之间的距离,同时使用负样本来训练模型: ```python nce_weights = tf.Variable(tf.truncated_normal([vocab_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size))) nce_biases = tf.Variable(tf.zeros([vocab_size])) embed = tf.nn.embedding_lookup(embedding, inputs) loss = tf.reduce_mean(tf.nn.nce_loss(nce_weights, nce_biases, labels, embed, num_neg_samples, vocab_size)) ``` 最后,我们需要使用梯度下降优化器来最小化损失函数,并在训练过程中输出日志: ```python optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(num_iterations): # 生成训练样本 batch_inputs, batch_labels = generate_batch(corpus_int, window_size, num_neg_samples) # 训练模型 feed_dict = {inputs: batch_inputs, labels: batch_labels} _, loss_val = sess.run([optimizer, loss], feed_dict=feed_dict) # 输出日志 if (i + 1) % log_interval == 0: print('Iteration {}: Loss = {:.4f}'.format(i + 1, loss_val)) ``` 完整代码如下: ```python import numpy as np import tensorflow as tf from collections import Counter import random # 语料库文件路径 corpus_file = 'corpus.txt' # 词向量维度 embedding_size = 128 # 跳跃窗口大小 window_size = 5 # 负样本数 num_neg_samples = 64 # 学习率 learning_rate = 0.1 # 迭代次数 num_iterations = 10000 # 每隔多少步输出一次日志 log_interval = 1000 def generate_batch(corpus, window_size, num_neg_samples): # 遍历整个语料库 for i in range(window_size, len(corpus) - window_size): # 输入词 center_word = corpus[i] # 输出词 context_words = [] for j in range(i - window_size, i + window_size + 1): if j != i: context_words.append(corpus[j]) # 负样本 neg_samples = [] while len(neg_samples) < num_neg_samples: samp = random.randint(0, len(corpus) - 1) if samp != center_word and samp not in context_words: neg_samples.append(samp) yield center_word, context_words + neg_samples with open(corpus_file, 'r', encoding='utf-8') as f: corpus = f.read().split() # 统计词频并按照词频从高到低排序 word_counts = Counter(corpus) sorted_vocab = sorted(word_counts, key=word_counts.get, reverse=True) # 生成词汇表和词汇表的反向映射表 vocab_to_int = {word: idx for idx, word in enumerate(sorted_vocab)} int_to_vocab = {idx: word for idx, word in enumerate(sorted_vocab)} # 将语料库中的词转换成数字编码 corpus_int = [vocab_to_int[word] for word in corpus] inputs = tf.placeholder(tf.int32, [None], name='inputs') labels = tf.placeholder(tf.int32, [None, 1], name='labels') vocab_size = len(vocab_to_int) embedding = tf.Variable(tf.random_uniform([vocab_size, embedding_size], -1.0, 1.0)) nce_weights = tf.Variable(tf.truncated_normal([vocab_size, embedding_size], stddev=1.0 / np.sqrt(embedding_size))) nce_biases = tf.Variable(tf.zeros([vocab_size])) embed = tf.nn.embedding_lookup(embedding, inputs) loss = tf.reduce_mean(tf.nn.nce_loss(nce_weights, nce_biases, labels, embed, num_neg_samples, vocab_size)) optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) for i in range(num_iterations): # 生成训练样本 batch_inputs, batch_labels = generate_batch(corpus_int, window_size, num_neg_samples) # 训练模型 feed_dict = {inputs: batch_inputs, labels: batch_labels} _, loss_val = sess.run([optimizer, loss], feed_dict=feed_dict) # 输出日志 if (i + 1) % log_interval == 0: print('Iteration {}: Loss = {:.4f}'.format(i + 1, loss_val)) ``` 注意,这只是一个简单的示例,实际上 Skip-gram 模型中还可以加入很多其他的优化和技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值