无监督关键短语的生成问题博客08--train_model.py的分析

2021SC@SDUSC

我们将继续03篇博客之后,分析doc2vec模型里train_model.py的代码,分析doc2vec模型具体的构建过程。该代码也适用于有预先训练好的词嵌入的训练,且代码的实现基于genism。

一、train_model.py的代码分析

import gensim.models as g
import logging

#doc2vec参数
vector_size = 256 
window_size = 15 
min_count = 1 
sampling_threshold = 1e-5 
negative_size = 5 
train_epoch = 100 
dm = 0
# 0 = dbow; 1 = dmpv
worker_count = 1 # 用于控制训练的并行数

这一部分初始化了doc2vec的相关参数,我们将一一介绍:

  • vector_size:词向量长度,默认为100
  • window_size:窗口大小,表示当前词与预测词在一个句子中的最大距离是多少
  • min_count:可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5
  • sampling_threshold :高频词汇的随机降采样的配置阈值,默认为1e-3,范围是(0,1e-5)
  • negative_size:如果>0,则会采用negativesampling,用于设置多少个noise words(一般是5-20)
  • train_epoch:迭代次数
  • dm:0时采用dbow模式,1时采用dmpv模式
  • worker_count:用于控制训练的并行数 
# 预训练好的词嵌入
pretrained_emb = "toy_data/pretrained_word_embeddings.txt" 
# 如果没有预训练好的词嵌入则没有这一参数

# 输入语料库
train_corpus = "toy_data/wiki_en.txt"

# 模型输出
save_model_name = 'wiki_en_doc2vec.model'
saved_path = "toy_data/model/wiki_en_doc2vec.model.bin"

这一部分声明了pretrained_emb和输入语料库的路径,同时声明了训练好的doc2vec的模型的保存路径。

# 获取日志信息
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# 训练 doc2vec 模型
docs = gm.doc2vec.TaggedLineDocument(train_corpus) # 加载语料
model = gm.Doc2Vec(docs, vector_size=vector_size, window=window_size, min_count=min_count, sample=sampling_threshold, workers=worker_count,
                   hs=0, dm=dm, negative=negative_size,dbow_words=1,dm_concat=1,epochs=train_epoch,pretrained_emb=pretrained_emb)

# 保存模型
model.save(saved_path)

用之前声明的参数和加载好的预料库训练doc2vec模型,产生了bin文件,就是我们项目extract.py中需要的预训练好的模型。

二、infer_test.py的代码分析

import gensim.models as gm
import codecs
import numpy as np

# 参数
model = "toy_data/model/wiki_en_doc2vec.model.bin"
test_docs = "toy_data/test.txt" # test.txt为需要向量化的文本
output_file = "toy_data/test_vector.txt" # 得到测试文本的每一行的向量表示

# 超参
start_alpha = 0.01
infer_epoch = 1000

# 加载模型
m = gm.Doc2Vec.load(model)
test_docs = [x.strip().split() for x in codecs.open(test_docs, "r", "utf-8").readlines()]

这一部分首先指明之前训练好的doc2vec的模型的路径,需要向量化的文本路径,以及得到的向量存储为test_vector.txt,初始化超参数,加载之前训练好的模型,按行读入test_docs,调用split()函数分割,返回列表对象赋给test_docs. 

#infer test vectors
output = open(output_file, "w")
for d in test_docs:
    output.write(" ".join([str(x) for x in m.infer_vector(d, alpha=start_alpha)]) + "\n")
output.flush()
output.close()
#print(len(test_docs)) #测试文本的行数

print(m.most_similar("party", topn=5)) 
# 找到与party单词最相近的前5个

# 保存为numpy形式
test_vector = np.loadtxt('toy_data/test_vector.txt')
test_vector = np.save('toy_data/test_vector', test_vector)

这一部分打开写入文件output_file,对于test_docs中的每一个token,调用infer_vector将其向量化,之后可以调用most_similar函数找到与某个词最相近的几个词。最后将写好的test_vector.txt文件保存为numpy形式,文件名为toy_data/test_vector.infer_test.py的运行结果如下:

图1:test_vector.txt的结果

图2:生成了向量化的txt与npy文件

三、词性标注的实现分析

在本项目的utils.py中extract函数需要构建语法树,这就涉及到词块的表示:标记与树。我们将先简单分析词性标注的实现,再具体分析utils.py对语法树的处理。

按词性分类是语言中对词的一种分类方法,是以语言特征为主要依据、兼顾词汇意义对词进行划分的结果,常见的词性有14种,如:名词、动词、形容词等。词性标注(Part-Of-Speech,POS)就是标注出一段文本中每个词的词性。词性标注以分词为基础,是对文本语言的另一个角度的理解。

基于jieba的中文分词的代码分析:

import jieba.posseg as pseg
print(pseg.lcut("我爱北京天安门"))

结果返回一个装有pair元组的列表,每个pair元组中分别是词汇和对应的词性。其词性标注运行结果如下: 

 使用hanlp进行中文词性标注:

import hanlp
# 加载中文命名实体识别的预训练模型CTB5_POS_FASTTEXT_EN
tagger = hanlp.load(hanlp.pretrained.pos.PTB_POS_RNN_FASTTEXT_EN)
# 输入分词列表
tagger(['I','banked','2','dollars','in','a','book','.'])
print(tagger(['I','banked','2','dollars','in','a','book','.']))

输入是分词结果的列表,返回的是对应的词性的列表,而不是像jieba的分词返回元组的列表。其词性标注运行结果如下:

四、有关文本特征处理的提取n-gram特征的代码分析

给定一段文本序列,其中n个词或字的相邻共现特征即n-gram特征,常用的n-gram特征是bi-gram和tri-gram特征,分别对应n为2和3。本项目的utils.py中也有get_ngram的实现函数。

 1.提取n-gram特征示例代码分析

ngram_range = 2 # 取n_gram=2为例

def create_ngram_set(input_list):
    # 从数值列表中提取所有的n_gram特征
    # input_list为输入的数值列表,可以看作词汇映射后的列表
    # 返回n_gram特征组成的集合
    return set(zip(*[input_list[i:] for i in range(ngram_range)]))

if __name__ == '__main__':
    input_list = [1,3,2,1,5,3]
    res = create_ngram_set(input_list) 
    print(res)

这里输入的是数值列表,以此为例,可以分析出列表的n_gram特征,当n=2时为(1,3),(3,2),(2,1),(1,5),(5,3)。代码的运行结果如下: 

2.基于sklearn实现的n-gram特征提取

这里我们不再分析训练n-gram模型的过程,而是简单地给出一些提取结果的示例。首先我们来看一下提取n-gram特征问题的数学描述,之前已经提到了,n-gram指的是文本中连续的n个item(item可以是phoneme, syllable, letter, word或base pairs)。n-gram 中如果n=1则为unigram,n=2则为bigram,n=3则为trigram。n>4后,则直接用数字表示,如4-gram,5-gram。gram 常用来比较句子相似度,模糊查询,以及句子合理性,句子矫正等。

 对一句话而言,它的词序排列的概率为:

这里的条件概率计算比较复杂,于是n-gram假设当前词只与前n个词有关,也就自然地分出了n=1,n=2等情况。下面我们来看基于sklearn的提取n-gram的代码。

from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
import jieba

data = ["他用报话机向上级呼喊:“为了祖国,为了胜利,向我开炮!向我开炮!",
        "记者:你怎么会说出那番话?",
        "韦昌进:我只是觉得,对准我自己打,才有可能把上了我哨位的这些敌人打死,或者打下去。"]

data = [" ".join(jieba.lcut(e)) for e in data] # 分词,并用" "连接

vec = CountVectorizer(min_df=1, ngram_range=(1,2)) 
# ngram_range=(1,1) 表示 unigram, ngram_range=(2,2) 表示 bigram, ngram_range=(3,3) 表示 thirgram
X = vec.fit_transform(data) # 将文本转换为矩阵
df = pd.DataFrame(X.toarray(), columns=vec.get_feature_names()) # 转为dataframe

结果如下:

 

五、pke中seq2seq的初始化分析

pke中实现了深度seq2seq模型,其初始化如下。主要是定义了seq2seq类和init,document_to_ix方法。下面我们一一分析,首先是init方法。

class Seq2Seq(SupervisedLoadFile):

    def __init__(self):

        super(Seq2Seq, self).__init__()

        self.sequence = []
        # input sequence

        self.vocabulary = ['<SOS>', '<EOS>', '<UNK>']
        # 初始化seq2seq对象的vocabulary,对应特殊的eos,unk

接着是document_to_ix方法,该方法实现了将document转为sequence。我们知道,seq2seq需要有序列化输入,所以我们实际上为seq2seq对象创建了字典,实现了序列的输入。首先是输入序列,之后初始化vocabulary,<SOS>是标志着序列开始的word,<EOS>是标志序列的结束的word, <UNK>对应在字典中找不到的词,主要是调用index方法,将word转为index。

 def document_to_ix(self):
        # 为了加入<SOS>而在sequence中加入<SOS>的索引
        self.sequence.append(self.vocabulary.index('<SOS>'))
        for i, sentence in enumerate(self.sentences):
            for word in sentence.stems:
                try:
                    self.sequence.append(self.vocabulary.index(word))
                # 对于setence中的word,调用index方法,得到word的索引
                except ValueError:
                    # 若没有找到word的索引,则添加对应<UNK>的索引
                    self.sequence.append(self.vocabulary.index('<UNK>'))
        # sentence末尾加上<EOS>索引
        self.sequence.append(self.vocabulary.index('<EOS>'))

本篇博客的三、四部分是对utils.py的初步分析,对于utils.py中各个函数具体代码的分析,详见后续博客。在后续博客中,我们还将分析utils.py和train.py文件。utils.py涉及的语法树的构造,也将在后续博客中介绍。train.py是用sliver label训练seqseq模型。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个用点、线表示的密码,它使用了点阵字母编码,称为“摩斯电码”。它是在电信的初期发明的,用于通信。摩斯电码通过点和线的组合表示字母,数字和标点符号。如果你想知道这段密码代表的信息,需要使用摩斯电码表进行解码。 ### 回答2: 这是摩斯密码,解码后为:"TAKE CARE。" 摩斯密码是一种电码通信方式,通过不同的短点和长划表示不同的字母和数字。其中"--"表示字母T,"-."表示字母A,"-.-."表示字母C,"-"表示字母E。摩斯密码的使用广泛,特别是在电报通信中。这句话的含义是"注意"或"小心",是人们在交流中常用的一句话。 ### 回答3: 它是一个摩尔斯密码,翻译为中文是:“你,AI智能助手。”这是一个由摩尔斯电码组成的短语。摩尔斯电码是一种用来发送文字信息的电报编码系统。对于摩尔斯电码的编码规则,每个字母和数字都有对应的短码和长码。以“-- -- .- .. -.-. - ..--..”为例,每个“-”代表长码,每个“.”代表短码。摩尔斯电码广泛应用于通信领域,尤其是需要远距离传输无线电信号的场合。 翻译后的结果是“你,AI智能助手。”其中,“你”是指对话对象,“AI智能助手”则指代我,这个使用摩尔斯电码回答问题的人工智能助手。AI智能助手是一种基于人工智能技术的软件应用工具,可以通过语音或者文字进行交互,帮助人们解答问题、提供咨询和服务。我可以回答各种各样的问题,助你解决疑惑和困惑。希望我的回答对你有帮助。如果还有其他问题,欢迎提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值