目录
2.4.1、keyedvectors.load_word2vec_format() 报错
2.5、中文训练自定义类(生成 embedding tabel、vocab_2_idx、idx_2_vocab)
2.5、Facebook Fasttext 进行有监督模型训练
4.1.1、gensim LDA 模型 API 以及 模型数据格式要求
4.2.1、sklearn LDA 模型 API 以及 模型数据格式要求
6.2、Keras 中 text 相关 process 基本用法
八、pytorch 基于transformers使用Bert家族
8.2、Transformers 基本使用(pytorch)
8.2.3、transformers 中 bert 参数文件 config.json
8.2.4、使用BertTokenizer对文档进行token id、attention mask id、segment id 编码
8.2.6、基于 transformers 的 Bert 模型简单的案例
一、用sklearn训练TF-idf
1.1、sklearn 中 tf-idf 数据格式要求
输入的数据:可迭代对象iter,且每一个样本需要以空格分隔词的字符串,如下所示:
中文(二个样本):['我 的 手机 在 哪 ?',
'你 的 家乡 是 哪里 ?']
英文(二个样本):['I am liu',
'he is li lei']
1.2、sklearn tf-idf 参数解析
sklearn: TfidfVectorizer 中文处理及一些使用参数
以下给出常用的参数:
analyzer:特征分隔的方式:‘word’, ‘char’, ‘char_wb’, default:word
stop_words:停止词,自带英文停止词 'english',也可以自定义停止词的列表
token_patternstr: default=r”(?u)\b\w\w+\b”,默认是只会保留长度 >= 2的字符,但是中文一个字符也是有意义的,中文
通常修改:r”(?u)\b\w+\b”
ngram_range:tuple (min_n, max_n), default=(1, 1),min_n <= n <= max_n,(1, 1) means only unigrams,
(1, 2) means unigrams and bigrams, and (2, 2) means only bigrams
max_df:float or int, default=1.0,单词在所有文档中出现的频率高于该值时忽略该词
min_df:float or int, default=1,单词在所有文档中出现的频率低于该值时忽略该词
max_feature:在大规模语料上训练TFIDF会得到非常多的词语,如果再使用了n-gram的设置加入了词组,那么我们词表的大小就会爆
炸。出于时间和空间效率的考虑,可以限制最多多少个特征,模型会优先选取词频高的词语留下。通常配合max_df与min_df使用
norm:{‘l1’, ‘l2’}, default=’l2’,正则化的方式
1.3、英文 tf-idf 训练
#coding=utf-8
from sklearn.feature_extraction.text import TfidfVectorizer
document = ["I have a pen .",
"I have an apple ."
"he has a pen !"]
tfidf_model = TfidfVectorizer(analyzer='word', # 默认
stop_words=None, # 默认
token_pattern=r"(?u)\b\w\w+\b", # 默认忽略 标点符号 与 长度小于2 的单词
ngram_range=(1, 1), # 默认
max_df=1.0, # 默认
min_df=1, # 默认
max_features=None, # 默认全部保留
norm='l2' # 默认 l2 正则
).fit(document)
# 获得模型列名字典,数字代表列的索引
print('列名字典索引:\n',tfidf_model.vocabulary_)
# {'have': 3, 'pen': 5, 'an': 0, 'apple': 1, 'he': 4, 'has': 2} 可以看到由于 a 的长度小于2,所以被忽略了
# 获取被max_features 与 max_df 与 min_df 这三个参数过滤掉的词,注意 stop_words 过滤的词不包含在其中
print('停止的词:\n',tfidf_model.stop_words_)
# set()
# transform 将样本转化为 tf-idf 2D 向量
sparse_result = tfidf_model.transform(document) # 得到tf-idf矩阵,稀疏矩阵表示法
print('稀疏矩阵:\n',sparse_result)
# (0, 5) 0.7071067811865475 第一个样本在第五列的tf-idf的值为 0.7071067811865475
# (0, 3) 0.7071067811865475
# (1, 5) 0.31779953783628945
# (1, 4) 0.4466561618018052
# (1, 3) 0.31779953783628945
# (1, 2) 0.4466561618018052
# (1, 1) 0.4466561618018052
# (1, 0) 0.4466561618018052
print("结果:\n",sparse_result.todense()) # 转化为更直观的一般矩阵
# [[0. 0. 0. 0.70710678 0. 0.70710678]
# [0.44665616 0.44665616 0.44665616 0.31779954 0.44665616 0.31779954]]
# TODO 当新样本中的词不在tf-idf的特征表里面时,会忽略该词
doc = ['she has a pen',]
# [[0. 0. 0.81480247 0. 0. 0.57973867]]
print("结果:\n",tfidf_model.transform(doc).toarray())
1.4、中文tf-idf 训练
#coding=utf-8
from sklearn.feature_extraction.text import TfidfVectorizer
document = ["我 的 家庭 ! 。 L",
"我 真的 很 喜欢 家 的 感觉",
"真的 很"]
stop_word = ['&','①',]
tfidf_model = TfidfVectorizer(analyzer='word',
stop_words=stop_word, # 停止词
token_pattern=r"(?u)\b\w+\b|。", # 中文需要调整长度大于等于1的词都会保留,且保留 "。"
ngram_range=(1, 2), # word 级别 unigram 与 bigram
max_df= 0.6, # 单词 / 包含单词的文档数 高于这个值忽略该词
min_df= 0.1, # 单词 / 包含单词的文档数 低于这个值忽略该词
max_features=None, # 默认全部保留
norm='l2' # 默认 l2 正则
).fit(document)
# 获得模型列名字典,数字代表列的索引
print('列名字典索引:\n',tfidf_model.vocabulary_)
# {'家庭': 7, '。': 1, 'l': 0, '我 的': 11, '的 家庭': 13, '家庭 。': 8, '。 l': 2, '喜欢': 3, '家': 5, '感觉': 10, '我 真的': 12, '很 喜欢': 9, '喜欢 家': 4, '家 的': 6, '的 感觉': 14}
# 获取被max_features 与 max_df 与 min_df 这三个参数过滤掉的词,注意 stop_words 过滤的词不包含在其中
print('停止的词:\n',tfidf_model.stop_words_)
# {'真的', '我', '的', '很', '真的 很'}
# transform 将样本转化为 tf-idf 2D 向量
sparse_result = tfidf_model.transform(document) # 得到tf-idf矩阵,稀疏矩阵表示法
print('稀疏矩阵:\n',sparse_result) # 稀疏矩阵
print("结果:\n",sparse_result.todense()) # 稠密矩阵,也可以用 toarray()
# TODO 当新样本中的词不在tf-idf的特征表里面时,会忽略该词
sparse_result = tfidf_model.transform(['家 的 感觉 走',]) # 新词进行tf-idf转化时会被忽略
print("结果:\n",sparse_result.toarray())
import joblib
# tf-idf 模型保存与加载,使用joblib
# 保存
joblib.dump(tfidf_model,'./tf_idf.model')
# 加载
tfidf_model = joblib.load('./tf_idf.model')
print(tfidf_model.transform(['家 的 感觉 走',]).toarray())
1.5、训练TF-IDF遇到的问题
1.5.1、stop_word关键词警告信息如下:
UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words
generated tokens XXXXXXXX not in stop_words.
原因:因为tf-idf的参数 token_pattern 在加载数据时会对数据进行预处理,同时stop_words的词也会进行预处理,因此处理后的停止词有可能就不在原本的停止词中了,故会发出这样的警告
解决方法:可以在分词的时候自定义一个dataProcess的类,先进行stop_words去除,然后再进行训练tf-idf,这时就不需要指定stop_words参数了,自然不会发出警告
二、gensim 训练word2vec
注意:以下 API 的使用需要要求gensim >= 4.0.0
2.1、gensim word2vec 数据格式要求
1、iter 类型数据要求,2D可迭代对象,必须是分词好的数据,例如:
corpus = [['我','喜欢','你'],
['我','喜爱','看书'],
['他','想','踢','足球']]
2、file 类型的数据,格式须符合:一行一个样本,样本是以空格分隔的单词组成,例如:
我 喜欢 你
我 喜欢 看书
它 想 踢 足球
2.2、gensim word2vec 参数解析
# 常见的参数如下:
w2v = word2vec.Word2Vec(sentences=corpus, # 语料库输入
vector_size=300, # embedding 的维度
alpha=0.025,
window=5,
min_count=1, # 词频最小的频率
max_vocab_size=?, # 词汇表最大的维度,默认使用min_count后所有的词
sample=6e-5, # 高频词 subsampling 的阈值
workers=4,
min_alpha=0.0001, # 学习率衰减最小值
sg=1, # 0: CBOW 1: skip-gram,默认使用 CBOW
hs=0, # 0: negative samping 1:分层霍夫曼树
negative=5, # 负采样"负例"的个数
epochs=5, # 迭代次数
sorted_vocab=1, # 1 表示词频排序,默认 vocab 词频从高到低进行排列#
)
2.3、gensim word2vec 中文训练【无监督】
使用 KeyedVectors.load_word2vec_format 加载预训练的腾讯800w词向量的方法
from gensim.models import word2vec
from gensim.models import KeyedVectors
import numpy as np
import jieba
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。")
]
print('语料库:\n',corpus)
w2v = word2vec.Word2Vec(sentences=corpus, # 语料库输入
vector_size=8, # embedding 的维度
alpha=0.025,
window=5,
min_count=1, # 词频最小的频率
max_vocab_size=None, # 词汇表最大的维度
sample=1e-3, # 高频词 subsampling 的阈值
workers=3,
min_alpha=0.0001, # 学习率衰减最小值
sg=1, # 0: CBOW 1: skip-gram
hs=0, # 0: negative samping 1:分层霍夫曼树
negative=5, # 负采样"负例"的个数
epochs=5, # 迭代次数
sorted_vocab=1, # 1 表示词频排序,默认 vocab 词频从高到低进行排列#
)
# 获取 vocab,embedding tabel
print('获得embedding tabel:\n',w2v.wv.vectors)
print('获得vocab dict:',w2v.wv.key_to_index)
print('获得id_to_vocab的列表:\n',w2v.wv.index_to_key)
print(w2v.wv.vectors.shape) # embedding table size
word2vec添加一对新的key:vector
# 使用 add_vector 可以添加一个新的 key:vector,这是为了解决测试集单词 UNK 的问题
print(w2v.wv.add_vector('UNK',vector= np.random.uniform(-1,1,(8,)))) # 添加UNK向量
# 查看是否加载成功
print(w2v.wv.key_to_index)
print(w2v.wv.index_to_key)
word2vec获取某个词的向量&相似度
# 获取向量
print('获得单词的索引:\n',w2v.wv.get_index('的'))
print('获得单词的向量:\n',w2v.wv.get_vector('的'))
print('获得单词的向量的第二种方式:\n',w2v.wv['的']
print('获得embedding table l2 正则的格式:\n',w2v.wv.get_normed_vectors())
# 计算相似度
print('获得最相近的topn个单词:\n',w2v.wv.similar_by_key('的',topn=10))
print('获得最相近的topn个单词第二种方式:\n',w2v.wv.most_similar(positive='的',topn=10))
print('计算2个单词的余弦相似度:\n',w2v.wv.similarity('的','是'))
word2vec 模型保存与加载
一共有三种保存方式:
1、.save() & load
2、.save_word2vec_format() & .load_word2vec_format
3、np.save() 或者 np.savetxt()
tip:
save和save_format 都是用来保存训练模型的
相同点就是:都可以复用,即载入之后可以得到对应单词的词向量;
不同点是:save保存的模型,载入之后可以继续在此基础上接着训练(后文会介绍),而format_save保存的模型不能,但有个好
处就是如果s设置binary=False则保存后的结果可以直接打开查看
# 保存为c语言格式,当然也可以直接保存模型【百度即可】
print(w2v.wv.save_word2vec_format('w2v.model',binary=True)) # binary=True,以2进制的形式保存为 C语言格式。建议用二进制方式,速度快,且不会存在bug,写代码时可以将binary置为True,可以看到词向量的具体值
# 加载c语言格式
print('load....')
w2v2 = KeyedVectors.load_word2vec_format('./w2v.model',binary=True)
print('获得vocab dict:',w2v2.key_to_index)
print('获得id_to_vocab的列表:\n',w2v2.index_to_key)
print('获得embedding tabel:\n',w2v2.vectors)
# 获得某个单词的词向量
print(w2v2.get_vector(key='的'))
print(w2v2['的'])
2.4、gensim word2vec 中文训练遇到的问题
2.4.1、keyedvectors.load_word2vec_format() 报错
原因:w2v.wv.save_word2vec_format('w2v.model',binary=False),当binary==False时,如果vocab中有"空格"作为单词,keyedvectors.load_word2vec_format()可能会报错
解决方案:
# 保存时用 二进制形式进行保存【当然debug阶段可以先保存为txt观察结果,之后再保存为 二进制格式
w2v.wv.save_word2vec_format('w2v.model',binary=True)
# 同样的,加载的时候也要使用二进制格式加载
KeyedVectors.load_word2vec_format('./w2v.model',binary=True)
2.5、中文训练自定义类(生成 embedding tabel、vocab_2_idx、idx_2_vocab)
弥补 word2vec 没有 PAD UNK BOS EOS 标签的问题,且将这些标签放在最前面
# gensim == 4.0.0
import gensim
from gensim.models import word2vec
from gensim.models import KeyedVectors
import numpy as np
np.random.seed(1)
import jieba
import copy
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。")
]
class word_2_vec():
def __init__(self,tags:list = None):
# tags 是为 word2vec 模型添加 <PAD> <UNK> <BOS> <EOS> 标签,PAD必须放在最前面,例如:['<PAD>','<UNK>']
self.tags = tags
self.w2v = self._init_model()
def _init_model(self):
w2v = word2vec.Word2Vec( # 初始化模型先不给定语料库
vector_size=8, # embedding 的维度
alpha=0.025,
window=5,
min_count=1, # 词频最小的频率
max_vocab_size=None, # 词汇表最大的维度
sample=1e-3, # 高频词 subsampling 的阈值
workers=3,
min_alpha=0.0001, # 学习率衰减最小值
sg=1, # 0: CBOW 1: skip-gram
hs=0, # 0: negative samping 1:分层霍夫曼树
negative=5, # 负采样"负例"的个数
epochs=5, # 迭代次数
sorted_vocab=1, # 1 表示词频排序,默认 vocab 词频从高到低进行排列#
)
return w2v
def train_(self,sentences):
""" 训练 """
self.w2v.build_vocab(sentences) # updata= True ,允许模型后续更新训练,默认为 False
self.w2v.train(sentences,total_examples=self.w2v.corpus_count,epochs=self.w2v.epochs)
if self.tags is not None:
self._add_pad_unk_for_w2v()
def _add_pad_unk_for_w2v(self):
#训练时 为 word2vec 添加 PAD UNK BOS EOS
for tag in self.tags:
self.w2v.wv.add_vector(tag,np.random.uniform(-1,1,self.w2v.wv.vector_size)) # 默认会放在 vocab 最后面
# 将 PAD UNK BOS EOS 放到最前面
def sort_pad_unk(vectors, key_to_index, index_to_key):
""" 将word2vec后面的tag """
vectors = copy.deepcopy(vectors)
key_to_index = copy.deepcopy(key_to_index)
index_to_key = copy.deepcopy(index_to_key)
tags_vectors = vectors[-len(self.tags):]
vectors = np.concatenate([tags_vectors, vectors[:-len(self.tags)]], axis=0)
key_to_index_new = dict(zip(self.tags,range(len(self.tags))))
for key in key_to_index:
if key not in key_to_index_new:
key_to_index_new[key] = len(key_to_index_new)
key_to_index = key_to_index_new
index_tags = index_to_key[-len(self.tags):]
other_tags = index_to_key[:-len(self.tags)]
index_tags.extend(other_tags)
index_to_key = index_tags
return vectors, key_to_index, index_to_key
vectors, key_to_index, index_to_key = sort_pad_unk(self.w2v.wv.vectors,self.w2v.wv.key_to_index,self.w2v.wv.index_to_key)
# 更新 循序
self.w2v.wv.vectors = vectors
self.w2v.wv.key_to_index = key_to_index
self.w2v.wv.index_to_key = index_to_key
def save_(self,path,binary = True):
self.w2v.wv.save_word2vec_format(path,binary=binary)
def load_(self,path,binary=True,limit=None):
self.w2v = KeyedVectors.load_word2vec_format(path,binary=binary,limit=limit)
if __name__ == '__main__':
# 训练模型
obj = word_2_vec(tags=['<PAD>','<UNK>',])
obj.train_(corpus)
obj.save_('./w2v.model2',True)
print(obj.w2v.wv.vectors)
print(obj.w2v.wv.key_to_index)
print(obj.w2v.wv.index_to_key)
# # 加载 模型
# obj = word_2_vec()
# obj.load_('./w2v.model2',True)
# print(obj.w2v.vectors)
# print(obj.w2v.key_to_index)
# print(obj.w2v.index_to_key)
三、gensim 训练Fasttext
注意:以下 API 的使用需要要求gensim >= 4.0.0
fasttext 是 facebook 提出的有监督学习模型,gensim中它是无监督模型,是 Word2vec 的升级版
2.1、gensim Fasttext 数据格式要求
同是gensim的模型,Fasttext与word2vec数据格式相同
2.2、gensim Fasttext 参数解析
同是gensim的模型,Fasttext仅仅是word2vec的升级版,很多参数是共用的,常见的参数如下:
# Gensim 4.0.0 Fasttext 常见的参数
fasttext.FastText(
# word2vec 共有的参数
sentences=None, # 语料库,可以仅仅初始化fasttext模型不给定预料,后续使用 train 进行训练
sg=0, # skip-gram or cbow ,1: skip_gram 0:cbow
hs=0, # 层次化softmax or negative softmax , 1:层次化softmax 0:negative softmax
vector_size=100, # embedding dim
alpha=0.025, # 学习率
window=5, # 窗口的大小
min_count=5, # 词频低于该值不计入 vocab
max_vocab_size=None, # 根据词频强制确定 vocab的大小,默认使用 min_count后全部词
sample=1e-3, # 高频词 subsampling 阈值
workers=3, # 进线程数
min_alpha=0.0001, # 学习率衰减最低值
negative=5, # negative softmax 负例的个数
ns_exponent=0.75, # 负采样启发式公式的值,默认即可
epochs=5, # 迭代次数
sorted_vocab=1, # 使用使用词频从高到低进行排列,默认进行排列
# fasttext 参数
min_n=3, # char级别的n-gram最小值
max_n=6, # char级别的n-gram最大值
bucket=2000000, # n-gram bucket 数目
# 额外参数
word_ngrams=1, # 1 or 0,1:使用 char级别的 sub n-gram,0:与普通的
)
2.3、gensim Fastext 模型的保存方式
1、gensim 提供了 save & load 方法,推荐使用该方法进行保存
① 该方式可以对后续的语料进行 再次训练
② 该方式可以保存 sub_ngram 的信息
2、和 gensim 中的 word2vec 一样,Fasttext 也可以使用 save_word2vec_format &
load_word2vec_format 进行保存,但是这种保存方式会将 fasttext 单向转化为 普通的word2vec
① 后续不可以进行新语料进行再次训练
② 会丢失 sub_ngram 信息
2.4、gensim Fasttext 中文训练【无监督】
import gensim
from gensim.models import fasttext
from gensim.models import KeyedVectors
import numpy as np
np.random.seed(1)
import jieba
import copy
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。")
]
print("预料:\n",corpus)
"""
fasttext 是 facebook 提出的有监督学习模型,gensim中它是无监督模型,是 Word2vec 的升级版
"""
fasttext.FastText(sentences=None, # 语料库,可以仅仅初始化fasttext模型不给定预料,后续使用 train 进行训练
sg=0, # skip-gram or cbow ,1: skip_gram 0:cbow
hs=0, # 层次化softmax or negative softmax , 1:层次化softmax 0:negative softmax
vector_size=100, # embedding dim
alpha=0.025, # 学习率
window=5, # 窗口的大小
min_count=5, # 词频低于该值不计入 vocab
max_vocab_size=None, # 根据词频强制确定 vocab的大小,默认使用 min_count后全部词
word_ngrams=1, # 1 or 0,1:使用 char级别的 sub n-gram,0:与普通的
sample=1e-3, # subsampling 阈值
workers=3, # 进线程数
min_alpha=0.0001, # 学习率衰减最低值
negative=5, # negative softmax 负例的个数
ns_exponent=0.75, # 负采样启发式公式的值,默认即可
epochs=5, # 迭代次数
min_n=3, # char级别的n-gram最小值
max_n=6, # char级别的n-gram最大值
sorted_vocab=1, # 使用使用词频从高到低进行排列
bucket=2000000, ) # n-grma bucket
class Fast_Text():
def __init__(self):
# tags 是为 fasttext 模型添加 <PAD> <BOS> <EOS> 标签,fasttext 通常不需要添加 <UNK>标签 ,PAD必须放在最前面,例如:['<PAD>','<BOS>']
self.ft = self._init_model()
def _init_model(self):
ft = fasttext.FastText(
sg=1, # skip-gram or cbow ,1: skip_gram 0:cbow
hs=0, # 层次化softmax or negative softmax , 1:层次化softmax 0:negative softmax
vector_size=8, # embedding dim
alpha=0.025, # 学习率
window=5, # 窗口的大小
min_count=1, # 词频低于该值不计入 vocab
max_vocab_size=None, # 根据词频强制确定 vocab的大小,默认使用 min_count后全部词
word_ngrams=1, # 1 or 0,1:使用 char级别的 sub n-gram,0:与普通的word2vec相同
sample=1e-3, # subsampling 阈值
workers=3, # 进线程数
min_alpha=0.0001, # 学习率衰减最低值
negative=5, # negative softmax 负例的个数
ns_exponent=0.75, # 负采样启发式公式的值,默认即可
epochs=5, # 迭代次数
min_n=1, # char级别的n-gram最小值
max_n=4, # char级别的n-gram最大值
sorted_vocab=1, # 使用使用词频从高到低进行排列
bucket=2000000, ) # n-grma bucket
return ft
def train_(self,sentences,update=False):
""" 训练 """
self.ft.build_vocab(sentences,update=update) # updata= True ,允许模型后续更新训练,默认为 False
self.ft.train(sentences,total_examples=self.ft.corpus_count,epochs=self.ft.epochs)
def save_(self,path):
self.ft.save(path) # save_word2vec_format 会丢失 n-gram 信息
def load_(self,path):
self.ft = fasttext.FastText.load(path)
return self.ft
if __name__ == '__main__':
# 训练模型
obj = Fast_Text()
obj.train_(corpus)
obj.save_('./ft.model3')
print(obj.ft.wv.vectors,obj.ft.wv.vectors.shape)
print(obj.ft.wv.key_to_index)
print(obj.ft.wv.index_to_key)
# 测试未登录词
print('临时1政府' in obj.ft.wv.key_to_index)
print(obj.ft.wv['临时政府'])
print(obj.ft.wv['临时1政府'])
print(obj.ft.wv.similarity('临时政府','临时1政府'))
# 加载
ft = obj.load_('./ft.model3')
print(ft.wv['临时政府'])
print(ft.wv['临时1政府'])
print(ft.wv.similarity('临时政府', '临时1政府'))
2.5、Facebook Fasttext 进行有监督模型训练
四、LDA主题模型(基于贝叶斯)
1、LDA主题模型的理解:LDA是一种基于贝叶斯公式[最大后验概率]的无监督模型,可以从朴素贝叶斯模型的计算方法去理解它的
计算过程。
2、怎么理解LDA似然函数的分布式多项式分布:
LDA模型输入一般是 词袋法特征,词袋法特征的值一个显著的特点就是离散且可数的,他属于多项式分布
3、LDA 先验概率与后验概率是同分布的,而似然函数的特征是多项分布,多项分布的共轭分布式狄利克雷分布,所以LDA是狄利
克雷分布。
4、LDA是贝叶斯模型,生成LDA主题向量前是否考虑使用PCA降维,将特征进行独立化?
4.1、基于gensim 训练LDA模型
4.1.1、gensim LDA 模型 API 以及 模型数据格式要求
1、LDA模型输入
LDA 模型输入需要多项式分布的单词特征,即输入是词袋法或者tf-idf的矩阵,通常建议使用tf-idf作为输入
2、API
from gensim import models
from gensim.models import LdaMulticore,LdaModel,tfidfmodel
from gensim import corpora
corpora ---- 获取词汇表
LdaMulticore ---- gensim 多核cpu LDA
LdaModel ---- gensim 普通 LDA
tfidfmodel ---- gensim tfidf模型
lda = LdaMulticore(corpus=None, # 语料库,需要 bow向量 或 tf-idf 向量,需要给定
num_topics=100, # 主题的个数,需要给定
id2word=None, # vocab 词汇表,需要给定
workers=None, # 线程进程数,通常给定
chunksize=2000, # 每次训练的 batchsize,通常给定
passes=1, # 训练时通过语料的次数,通常给定
batch=False, # 使用 batch 还是 online,默认即可
alpha='asymmetric', # 学习率正则化的模式,通常给定
eta=None, # 主题-单词狄利克雷分布参数,默认即可
minimum_probability= 0.01, # 占比低于该主题的阈值会被稀疏矩阵忽略,建议给定
decay=0.5,
offset=1.0,
eval_every=10,
iterations=50,
gamma_threshold=0.001,
random_state=None,
minimum_probability=0.01,
minimum_phi_value=0.01,
per_word_topics=False)
# 使用:
lda = LdaMulticore(corpus=corpus,
id2word=id2word,
num_topics=30,
workers=4,
chunksize=4000,
passes=7,
alpha='asymmetric',
minimum_probability= 1e-9,)
4.1.2、gensim 训练LDA 案例
# 基于 词袋法bow向量为输入训练LDA
from gensim import models
from gensim.models import LdaMulticore,LdaModel,TfidfModel
from gensim import corpora
import numpy as np
import pandas as pd
import jieba
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。"),
jieba.lcut('根据此前的消息,苹果此次将发布14 英寸和16 英寸版本的MacBook Pro,该系列也将是首款搭载M1X 芯片的设备。整体设计与M1一致,会使用台积电。它基于5nm工艺,但更新了规格以支持更多Lightning通道、CPU内核、GPU内核等'),
jieba.lcut('沙果属蔷薇科,仁果亚科,苹果属,别名林檎、花红果、萘子。布于西北、华北、东北以及长江以南各省。沙果性平,味甘酸,具有止渴生津、消食化滞、涩精的功效。沙果既可鲜食,又可加工。沙果香气浓郁,风味独特,营养丰富,药用价值高,深受消费者喜爱,为当下的畅销果品'),
jieba.lcut('核质硬,果肉薄,味微酸涩。果可生吃或作果脯果糕,干制后可入药,是中国特有的药果兼用树种,具有降血脂、血压、强心、抗心律不齐等作用,同时也是健脾开胃、消食化滞、活血化痰的良药,对胸膈脾满、疝气、血淤、闭经等症有很好的疗效。山楂内的黄酮类化合物牡荆素,是一种抗癌作用较强的药物,其提取物对抑制体内癌细胞生长、增殖和浸润转移均有一定的作用。')
]
print("预料:\n",corpus)
# 根据词频得到语料的词汇表
id2word = corpora.Dictionary(corpus) # Dictionary(138 unique tokens: ['“', '”', '。', '一些', '一步']...)
# doc2bow:将文章转化为词袋法向量,稀疏方式的表示
bows = [id2word.doc2bow(line) for line in corpus] # [[(0, 1), (1, 1), (2, 2), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 2)],[ ],[ ] ]
# print(bows)
lda = LdaMulticore(corpus=bows, # 语料库,需要 bow向量 或 tf-idf 向量
num_topics=4, # 主题的个数
id2word=id2word, # vocab 词汇表
workers=4, # 线程进程数
chunksize=4000, # 每次训练的 batchsize
passes=7, # 训练时通过语料的次数
alpha='asymmetric', # 学习率正则化的模式
minimum_probability= 1e-9,
)
print('模型详情:\n',lda)
# 打印top n的主题-单词的关系
for index,topic in lda.print_topics(5):
print(index,topic)
# 打印索引为 n 的主题-单词的关系
print('打印主题索引为1的主题-单词的关系:\n',lda.print_topic(1))
# 获取主题向量,需要输入 bow 或者 tf-idf 格式的数据
lda_vec = lda[bows] # 基于 bow 或 tf-idf 获得主题向量
print('获取主题向量的对象:\n',lda_vec)
print('获取样本的主体向量:\n',list(lda_vec))
# 每一个样本 主题索引及其值的稀疏表示方式
# [[(0, 0.006842906), (1, 0.0043555214), (2, 0.003230385), (3, 0.9855712)], [(0, 0.006014709), (1, 0.003839143), (2, 0.9878832), (3, 0.0022628969)],...]
# 基于tf-idf向量为输入训练lda
from gensim import models
from gensim.models import LdaMulticore,LdaModel,TfidfModel
from gensim import corpora
import numpy as np
import pandas as pd
import jieba
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。"),
jieba.lcut('根据此前的消息,苹果此次将发布14 英寸和16 英寸版本的MacBook Pro,该系列也将是首款搭载M1X 芯片的设备。整体设计与M1一致,会使用台积电。它基于5nm工艺,但更新了规格以支持更多Lightning通道、CPU内核、GPU内核等'),
jieba.lcut('沙果属蔷薇科,仁果亚科,苹果属,别名林檎、花红果、萘子。布于西北、华北、东北以及长江以南各省。沙果性平,味甘酸,具有止渴生津、消食化滞、涩精的功效。沙果既可鲜食,又可加工。沙果香气浓郁,风味独特,营养丰富,药用价值高,深受消费者喜爱,为当下的畅销果品'),
jieba.lcut('核质硬,果肉薄,味微酸涩。果可生吃或作果脯果糕,干制后可入药,是中国特有的药果兼用树种,具有降血脂、血压、强心、抗心律不齐等作用,同时也是健脾开胃、消食化滞、活血化痰的良药,对胸膈脾满、疝气、血淤、闭经等症有很好的疗效。山楂内的黄酮类化合物牡荆素,是一种抗癌作用较强的药物,其提取物对抑制体内癌细胞生长、增殖和浸润转移均有一定的作用。')
]
print("预料:\n",corpus)
# 根据词频得到语料的词汇表
id2word = corpora.Dictionary(corpus) # Dictionary(138 unique tokens: ['“', '”', '。', '一些', '一步']...)
# doc2bow:将文章转化为词袋法向量,稀疏方式的表示
doc_bows = [id2word.doc2bow(line) for line in corpus] # [[(0, 1), (1, 1), (2, 2), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 2)],[ ],[ ] ]
# 转化为 tf-idf
doc_tf_idf = models.TfidfModel(doc_bows)[doc_bows]
lda = LdaMulticore(corpus=doc_tf_idf, # 语料库,需要 bow向量 或 tf-idf 向量
num_topics=4, # 主题的个数
id2word=id2word, # vocab 词汇表
workers=4, # 线程进程数
chunksize=4000, # 每次训练的 batchsize
passes=7, # 训练时通过语料的次数
alpha='asymmetric', # 学习率正则化的模式
minimum_probability= 1e-9,
)
print('模型详情:\n',lda)
# 打印top n的主题-单词的关系
for index,topic in lda.print_topics(5):
print(index,topic)
# 打印索引为 n 的主题-单词的关系
print('打印主题索引为1的主题-单词的关系:\n',lda.print_topic(1))
# 获取主题向量,需要输入 bow 或者 tf-idf 格式的数据
lda_vec = lda[bows] # 基于 bow 或 tf-idf 获得主题向量
print('获取主题向量的对象:\n',lda_vec)
print('获取样本的主题向量:\n',list(lda_vec))
4.1.3、lda模型的小总结
1. 使用bow作为输入好还是tf-idf作为输入好?
通常来说 tf-idf好,因为tf-idf可以降低高频无用词的权重,lda是根据词特征多项分布的贝叶斯概率模型,tf-idf可以降低高频无用词对主题的影响
2. 上述lda主题训练的结果差强人意,为什么?
lda等机器学习的算法对停止词字典的要求是较高的,lda模型在训练前强烈建议加入停止词
4.2、基于sklearn 训练LDA模型
4.2.1、sklearn LDA 模型 API 以及 模型数据格式要求
1、LDA模型输入
LDA 模型输入需要多项式分布的单词特征,即输入是词袋法或者tf-idf的矩阵,通常建议使用tf-idf作为输入
2、API
bow_model = CountVectorizer(lowercase=True, # 文本全部转换为小写
stop_words=None, # 停止词
token_pattern=r"(?u)\b\w+\b", # 单词长度 >= 1 都会保留
ngram_range=(1, 1),
analyzer='word',
max_df=1.0, # 单词/所在文档树 高于该阈值忽略
min_df=1, # 单词/所在文档树 低于该阈值忽略
max_features=None, # 锁定最大的max_features 个数
)
tf_idf_model = TfidfVectorizer(lowercase=True, # 文本全部转换为小写
stop_words=None, # 停止词
token_pattern=r"(?u)\b\w+\b", # 单词长度 >= 1 都会保留
ngram_range=(1, 1),
analyzer='word',
max_df=1.0, # 单词/所在文档树 高于该阈值忽略
min_df=0.0, # 单词/所在文档树 低于该阈值忽略
max_features=None, # 锁定最大的max_features 个数
)
lda = LatentDirichletAllocation(n_components=10, # 主题个数,需要给定
doc_topic_prior=None, # 文档-主题 狄利克雷参数,默认即可
topic_word_prior=None, # 主题-单词 狄利克雷参数,默认即可
learning_method='batch', # 训练的方式:batch online,默认为batch,默认即可
max_iter=10, # 迭代次数,可以给定
batch_size=128, # 仅仅在 online 有效,用更新 EM 的batchsize,默认即可
n_jobs=None, # 线程进程数
random_state=None # 随机数种子
)
4.2.2、sklearn 训练lda
# 基于 bow 词袋法 训练lda
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer
import jieba
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。"),
jieba.lcut('根据此前的消息,苹果此次将发布14 英寸和16 英寸版本的MacBook Pro,该系列也将是首款搭载M1X 芯片的设备。整体设计与M1一致,会使用台积电。它基于5nm工艺,但更新了规格以支持更多Lightning通道、CPU内核、GPU内核等'),
jieba.lcut('沙果属蔷薇科,仁果亚科,苹果属,别名林檎、花红果、萘子。布于西北、华北、东北以及长江以南各省。沙果性平,味甘酸,具有止渴生津、消食化滞、涩精的功效。沙果既可鲜食,又可加工。沙果香气浓郁,风味独特,营养丰富,药用价值高,深受消费者喜爱,为当下的畅销果品'),
jieba.lcut('核质硬,果肉薄,味微酸涩。果可生吃或作果脯果糕,干制后可入药,是中国特有的药果兼用树种,具有降血脂、血压、强心、抗心律不齐等作用,同时也是健脾开胃、消食化滞、活血化痰的良药,对胸膈脾满、疝气、血淤、闭经等症有很好的疗效。山楂内的黄酮类化合物牡荆素,是一种抗癌作用较强的药物,其提取物对抑制体内癌细胞生长、增殖和浸润转移均有一定的作用。')
]
# 转化为 sklearn bow 或 tf-idf 接受的格式
corpus = [' '.join(_) for _ in corpus]
print("预料:\n",corpus)
# 获得 bow
bow_model = CountVectorizer(lowercase=True, # 文本全部转换为小写
stop_words=None, # 停止词
token_pattern=r"(?u)\b\w+\b", # 单词长度 >= 1 都会保留
ngram_range=(1, 1),
analyzer='word',
max_df=1.0, # 单词/所在文档树 高于该阈值忽略
min_df=1, # 单词/所在文档树 低于该阈值忽略
max_features=None, # 锁定最大的max_features 个数
).fit(corpus)
doc_bows = bow_model.transform(corpus)
# 稀疏矩阵
print(doc_bows)
lda = LatentDirichletAllocation(n_components=10, # 主题个数,需要给定
doc_topic_prior=None, # 文档-主题 狄利克雷参数,默认即可
topic_word_prior=None, # 主题-单词 狄利克雷参数,默认即可
learning_method='batch', # 训练的方式:batch online,默认为batch,默认即可
max_iter=10, # 迭代次数,可以给定
batch_size=128, # 仅仅在 online 有效,用更新 EM 的batchsize,默认即可
n_jobs=None, # 线程进程数
random_state=None # 随机数种子
).fit(doc_bows)
# 获取 主题向量 表示
topic_vec = lda.transform(doc_bows)
print(topic_vec)
# 获取每个主题单词 表示
print(lda.components_)
# 基于tf-idf训练ida
# TODO TF-idf 作为输入
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer
import jieba
corpus = [jieba.lcut('汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'),
jieba.lcut("中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。"),
jieba.lcut("海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。"),
jieba.lcut('根据此前的消息,苹果此次将发布14 英寸和16 英寸版本的MacBook Pro,该系列也将是首款搭载M1X 芯片的设备。整体设计与M1一致,会使用台积电。它基于5nm工艺,但更新了规格以支持更多Lightning通道、CPU内核、GPU内核等'),
jieba.lcut('沙果属蔷薇科,仁果亚科,苹果属,别名林檎、花红果、萘子。布于西北、华北、东北以及长江以南各省。沙果性平,味甘酸,具有止渴生津、消食化滞、涩精的功效。沙果既可鲜食,又可加工。沙果香气浓郁,风味独特,营养丰富,药用价值高,深受消费者喜爱,为当下的畅销果品'),
jieba.lcut('核质硬,果肉薄,味微酸涩。果可生吃或作果脯果糕,干制后可入药,是中国特有的药果兼用树种,具有降血脂、血压、强心、抗心律不齐等作用,同时也是健脾开胃、消食化滞、活血化痰的良药,对胸膈脾满、疝气、血淤、闭经等症有很好的疗效。山楂内的黄酮类化合物牡荆素,是一种抗癌作用较强的药物,其提取物对抑制体内癌细胞生长、增殖和浸润转移均有一定的作用。')
]
# 转化为 sklearn bow 或 tf-idf 接受的格式
corpus = [' '.join(_) for _ in corpus]
print("预料:\n",corpus)
# 获得 tf-idf
tf_idf_model = TfidfVectorizer(lowercase=True, # 文本全部转换为小写
stop_words=None, # 停止词
token_pattern=r"(?u)\b\w+\b", # 单词长度 >= 1 都会保留
ngram_range=(1, 1),
analyzer='word',
max_df=1.0, # 单词/所在文档树 高于该阈值忽略
min_df=0.0, # 单词/所在文档树 低于该阈值忽略
max_features=None, # 锁定最大的max_features 个数
).fit(corpus)
tf_idf = tf_idf_model.transform(corpus)
# 稀疏矩阵
print(tf_idf)
lda = LatentDirichletAllocation(n_components=10, # 主题个数,需要给定
doc_topic_prior=None, # 文档-主题 狄利克雷参数,默认即可
topic_word_prior=None, # 主题-单词 狄利克雷参数,默认即可
learning_method='batch', # 训练的方式:batch online,默认为batch,默认即可
max_iter=10, # 迭代次数,可以给定
batch_size=128, # 仅仅在 online 有效,用更新 EM 的batchsize,默认即可
n_jobs=None, # 线程进程数
random_state=None # 随机数种子
).fit(tf_idf)
# 获取主题向量表示
topic_vec = lda.transform(tf_idf)
print(topic_vec)
# 获取主题-单词表示
print(lda.components_)
4.1.3、lda模型的小总结
1. 使用bow作为输入好还是tf-idf作为输入好?
通常来说 tf-idf好,因为tf-idf可以降低高频无用词的权重,lda是根据词特征多项分布的贝叶斯概率模型,tf-idf可以降低高频无用词对主题的影响
2. 上述lda主题训练的结果差强人意,为什么?
lda等机器学习的算法对停止词字典的要求是较高的,lda模型在训练前强烈建议加入停止词
五、Glove 静态词向量的训练
windows下python3安装glove(终极无坑解决方案)
glove 相对于 gensim 中的 cbow、skip-gram、fasttext的优点?
① 采用类似 LSA 全局共现矩阵,感知窗口更大
② 不再使用”词袋法“看待上下文,采用具有距离感知的attention加权看待上下文
glove 存在的问题?
glove 以词作为基本单元,没有char-sub-ngram的过程,所以存在oov问题
5.1、Glove 模型数据格式
glove 数据格式要求与 gensim 中 word2vec 数据格式相同
5.2、Glove 训练中文词向量
import gensim
import numpy as np
from gensim.models import KeyedVectors
from glove import Glove
from glove import Corpus
import jieba
corpus = [jieba.lcut(
'汪文斌:中方重视阿富汗塔利班方面宣布成立临时政府和一些重要人士的安排,这结束了阿富汗长达三周多的“无政府状态”,是阿恢复国内秩序与战后重建的必要一步。我们也注意到阿塔方面表示,成立临时政府是为了尽快恢复社会和经济秩序。'.replace(' ','')),
jieba.lcut(
"中方在阿富汗问题上的立场是一贯和明确的,我们尊重阿富汗主权独立和领土完整,不干涉阿富汗内政,支持阿富汗人民自主选择符合本国国情的发展道路。希望阿富汗能构建广泛包容的政治架构,奉行温和稳健的内外政策,坚决打击各类恐怖势力,同各国特别是周边国家友好相处。".replace(' ','')),
jieba.lcut(
"海通证券股份有限公司研究员张一弛、徐柏乔、曾彪发布研报《阳光电源(300274):逆变器海外提升结构优化 储能快速增长》称,根据公司半年报,上半年公司逆变器业务实现收入35.91亿元,同比增长54.51%,毛利率达到38.15%,同比增长3.83个百分点。".replace(' ','')),
jieba.lcut(
'根据此前的消息,苹果此次将发布14 英寸和16 英寸版本的MacBook Pro,该系列也将是首款搭载M1X 芯片的设备。整体设计与M1一致,会使用台积电。它基于5nm工艺,但更新了规格以支持更多Lightning通道、CPU内核、GPU内核等'.replace(' ','')),
jieba.lcut(
'沙果属蔷薇科,仁果亚科,苹果属,别名林檎、花红果、萘子。布于西北、华北、东北以及长江以南各省。沙果性平,味甘酸,具有止渴生津、消食化滞、涩精的功效。沙果既可鲜食,又可加工。沙果香气浓郁,风味独特,营养丰富,药用价值高,深受消费者喜爱,为当下的畅销果品'.replace(' ','')),
jieba.lcut(
'核质硬,果肉薄,味微酸涩。果可生吃或作果脯果糕,干制后可入药,是中国特有的药果兼用树种,具有降血脂、血压、强心、抗心律不齐等作用,同时也是健脾开胃、消食化滞、活血化痰的良药,对胸膈脾满、疝气、血淤、闭经等症有很好的疗效。山楂内的黄酮类化合物牡荆素,是一种抗癌作用较强的药物,其提取物对抑制体内癌细胞生长、增殖和浸润转移均有一定的作用。'.replace(' ',''))
]
print("预料:\n", corpus)
# 语料创建
corpus_model = Corpus()
corpus_model.fit(corpus=corpus, # 语料,与gensim Wordvec 格式相同
window=15, # 用于共现矩阵的上下文窗口,比 gensim word2vec 拥有更长的窗口
ignore_missing=False # OOV 的单词是否被忽略
)
print('vocab 【未排序】:\n',corpus_model.dictionary)
print('vocab 大小:\n',len(corpus_model.dictionary))
# 训练 glove
glove_model = Glove( no_components=30, # embedding dim
learning_rate=0.05, # 学习率
random_state=0
)
glove_model.fit(matrix = corpus_model.matrix, # 训练的参数
epochs=40, # epochs
no_threads=2, # 线程进程数
verbose=True # 打印信息
)
glove_model.add_dictionary(corpus_model.dictionary)
# 模型保存与加载
corpus_model.save('corpus.model')
glove_model.save('glove.model')
corpus_model = Corpus.load('corpus.model')
glove_model = Glove.load('glove.model')
# 还可以利用 gensim 中 load_word2vec_farmat() 进行加载 为word2vec格式
# w2v = KeyedVectors.load_word2vec_format(glove 模型的保存地址)
# 获得词近似向量的 topn
print('获得近似词向量:\n',glove_model.most_similar('安排',number=10))
# 获取词向量
print('vocab:\n',glove_model.dictionary)
print('embedding tabel \n',glove_model.word_vectors)
print('获取单词的词向量:\n',glove_model.word_vectors[glove_model.dictionary['一定']])
# 保存 为gensim save_word2vec_format() 格式, TODO 保存的时候需要将空格单词删除,否则 load_word2vec_format 可能报错
with open('glove.w2v','w',encoding='utf-8') as w:
w.write(str(glove_model.word_vectors.shape[0]) + ' ' + str(glove_model.word_vectors.shape[1]))
w.write('\n')
for word in glove_model.dictionary:
w.write(word)
w.write(' ')
w.write(' '.join([str(line.astype(np.float32)) for line in glove_model.word_vectors[glove_model.dictionary[word]]]))
w.write('\n')
# 使用 KeyedVectors.load_word2vec_format 加载为 word2vec 格式
w2v = KeyedVectors.load_word2vec_format('glove.w2v',binary=False)
# 获取向量
print('获取vocab:\n',w2v.vocab)
print('获取id2word:\n',w2v.index2word)
print('获取embeding:\n',w2v.vectors)
print('获取单词的embedding:\n',w2v['一定'])
六、特征提取器---autoencoder
6.1、Keras 中 lstm 相关 api 基本用法
from tensorflow.keras.layers import Input,Dense,Embedding,Bidirectional,LSTM
from tensorflow.keras import regularizers
x = Input(shape=(200,),batch_size=None,name='input',dtype=None)
"""
shape: tuple, input输入shape,注意:这里面不包含batch size
batch_size:默认为None,与tensorflow一样,None表示batch size不确定
name:与tensorflow 一样,name表示tensor名
dtype:默认为None,数据类型
"""
print(x)
x = Embedding(input_dim = 10000, # 词汇表最大的大小
output_dim = 40, # embedding dim
embeddings_initializer='uniform', # 默认即可,字面意思
embeddings_regularizer=None, # 默认即可,字面意思
input_length=None, # 序列的step数,由于 Input 会指定length,所以这里默认即可
)(x) # ---- 与 pytorch 类似,(x)表示执行
print(x)
x = Bidirectional(LSTM(units = 35, # hidden size
dropout=0., # input drop out 率
recurrent_dropout=0., # 递归阶段 drop out 率
return_sequences=True, # True 表示输出所有时刻的输出值
return_state=False, # True 表示输出递归状态
activity_regularizer=None, # 输出到下一层正则
))(x)
print(x)
x = Bidirectional(LSTM(units = 20, # hidden size
dropout=0., # input drop out 率
recurrent_dropout=0., # 递归阶段 drop out 率
return_sequences=True, # True 表示输出所有时刻的输出值
return_state=False, # True 表示输出递归状态
activity_regularizer=regularizers.l1(1e-4), # 输出到下一层正则
))(x)
print(x)
out:
Tensor("input:0", shape=(None, 200), dtype=float32)
Tensor("embedding/Identity:0", shape=(None, 200, 40), dtype=float32)
Tensor("bidirectional/Identity:0", shape=(None, 200, 70), dtype=float32)
Tensor("bidirectional_1/Identity:0", shape=(None, 200, 40), dtype=float32)
6.2、Keras 中 text 相关 process 基本用法
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
import jieba
corpus = [' '.join(jieba.lcut('之前提到用keras的Tokenizer进行文本预处理,序列化,向量化等,然后进入一个simple的LSTM模型中跑')),
' '.join(jieba.lcut('大地春又回,长空裂惊雷。万物生欲动,无为自有为。 —— 诗人,余世存'))]
tokenizer = Tokenizer(num_words=None, # 根据词频所保留词汇表的最大的个数,None 表示全部保存
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', # 过滤词集合,默认为 '!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n'
lower=True, # 所有的单词转为小写
split=' ', # 分割符
)
# 构建词汇表
# 1. 数据格式要求与sklearn中的 tf-idf相同
tokenizer.fit_on_texts(corpus)
print('vocab:\n',tokenizer.word_index)
# 利用vocab将corpus进行id化
corpus_id = tokenizer.texts_to_sequences(corpus)
print('语料库id化:\n',corpus_id)
# 进行 pad 填充截取固定长度
corpus_id_pad = pad_sequences(sequences = corpus_id, # id化的语料
maxlen=50, # 固定长度
dtype='int32', # 数据类型,默认即可
padding='pre', # 默认在前面进行pad
value=0.) # 默认 pad 的id为0
print('pad后的语料id:\n',corpus_id_pad)
out:
vocab:
{',': 1, '的': 2, '。': 3, '—': 4, '之前': 5, '提到': 6, '用': 7, 'keras': 8, 'tokenizer': 9, '进行': 10, '文本': 11, '预处理': 12, '序列化': 13, '向': 14, '量化': 15, '等': 16, '然后': 17, '进入': 18, '一个': 19, 'simple': 20, 'lstm': 21, '模型': 22, '中跑': 23, '大地': 24, '春': 25, '又': 26, '回': 27, '长空': 28, '裂': 29, '惊雷': 30, '万物': 31, '生欲动': 32, '无为': 33, '自有': 34, '为': 35, '诗人': 36, '余世存': 37}
语料库id化:
[[5, 6, 7, 8, 2, 9, 10, 11, 12, 1, 13, 1, 14, 15, 16, 1, 17, 18, 19, 20, 2, 21, 22, 23], [24, 25, 26, 27, 1, 28, 29, 30, 3, 31, 32, 1, 33, 34, 35, 3, 4, 4, 36, 1, 37]]
pad后的语料id:
[[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 5 6 7 8 2 9 10 11 12 1 13 1 14 15 16 1 17 18 19 20 2 21
22 23]
[ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 24 25 26 27 1 28 29 30 3 31 32 1 33 34 35 3 4 4 36
1 37]]
6.3、Keras 中 lstm 实现 ae
七、人工构造basic feature
八、pytorch 基于transformers使用Bert家族
8.1、基本常识
1、transformers 下载的模型参数在哪个文件夹(Mac系统)
一般在:~/.cache
2、transformers 常见模型的下载地址?官方网址?
huggingface 的模型官网 GitHub 中文的 chiese bert wwm版本中文教程及模型下载
3、self-attention 与 BERT 网络的执行过程
4、BERT 30多种知识点:BERT 30多种为什么?
5、BERT token embedding、position embedding、segment embedding、最后一层 output维度?
- token embedding:nn.Embedding(vocab_dim,768)
- position embedding:nn.Embedding(512,768),512的长度不包含CLS SEP 这些分割符
- segment embedding:nn.Embedding(2,768)
- output维度:(B,T,D)---- (B,512,768)
6、BertTokenizer 需要提供 token id、attention mask id、segment id,但不需要提供position id,因为bert 预训练后会自动对 token 顺序进行编码
7、transformer 前馈网络 FFN层有什么作用?
我们知道transformer self-attention 的过程中没有进行非线性激活,FFN 的目的是为transformer结构提供非线性激活,FFN一共有两层 FC,第一层FC用gelu激活,第二层FC不进行激活
8、bert 相对于 RNN和word2vec时有哪些优势?
- transformer 结构加入position embedding的概念,可以并行多时刻训练,计算速度更快
- transformer 空间提取重构特征的能力远高于RNN
- bert 加入 MLM 掩码损失函数,相对于word2vec可以解决一词多义的问题
- bert 是预训练模型,有庞大的语料预训练参数,特征重构效果更好
8.2、Transformers 基本使用(pytorch)
8.2.1、第一次运行下载官方模型在默认文件夹
GIthub:huggingface transformers 官方 加载 torch & tensorfow 的方法
# 第一次运行会从官方下载 model_name 的模型(model.bin,config.json,vocab.txt)到本地默认文件
# 模型名不能随意定义,可以看上面huggingface github model 列表,当然也可以从 https://huggingface.co/models 官网离线下载并导入
To download and use any of the pretrained models on your given task, all it takes is three lines of code. Here is the PyTorch version:
>>> from transformers import AutoTokenizer, AutoModel
>>> tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
>>> model = AutoModel.from_pretrained("bert-base-uncased")
>>> inputs = tokenizer("Hello world!", return_tensors="pt")
>>> outputs = model(**inputs)
And here is the equivalent code for TensorFlow:
>>> from transformers import AutoTokenizer, TFAutoModel
>>> tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
>>> model = TFAutoModel.from_pretrained("bert-base-uncased")
>>> inputs = tokenizer("Hello world!", return_tensors="tf")
>>> outputs = model(**inputs)
8.2.2、我们离线下载模型参数,load模型
下载后的三个文件需要改名为如下格式:pytorch_model.bin、config.json、vocab.txt,并放入到 ./bert_base_chinese_wwm_ext 目录下(该目录可以自定义)
tip:如果是tensorflow2.0加载的话需要下载 后缀为 .h5的模型,并且在加载时需要添加一个参数(具体参数百度即可)
from transformers import BertModel,BertTokenizer,BertConfig,BertForMaskedLM
import os
model_path = 'bert_base_chiese_wwm_ext'
config_path = os.path.join(model_path,'bert_config.json')
tokenizer = BertTokenizer.from_pretrained(model_path)
print(tokenizer.vocab)
config = BertConfig.from_pretrained(config_path)
# 更改一些参数
config.output_hidden_states = True
config.output_attentions = True
model = BertModel.from_pretrained(model_path,config=config)
print(model)
8.2.3、transformers 中 bert 参数文件 config.json
# 最长文本长度:512,特征输出的维度 768,句子最多的个数 2 均不可随意更改
{
"attention_probs_dropout_prob": 0.1,
"directionality": "bidi", # 双向
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"max_position_embeddings": 512,
"num_attention_heads": 12,
"num_hidden_layers": 12,
"pooler_fc_size": 768,
"pooler_num_attention_heads": 12,
"pooler_num_fc_layers": 3,
"pooler_size_per_head": 128,
"pooler_type": "first_token_transform",
"type_vocab_size": 2, # 句子数最大值
"vocab_size": 21128 # 中文词汇表的大小
}
8.2.4、使用BertTokenizer对文档进行token id、attention mask id、segment id 编码
# 第一种:tokenizer.encoder() ----- 只能转化一个样本
# 利用分词器进行编码
# 仅仅返回 'input_ids’:单词在词典中的id编码,最多两个句子,最长为512(512还要去除CLS SEP标识)
print(tokenizer.encode('我不喜欢你'))
print(tokenizer.encode('我不喜欢这世界','我只喜欢你'))
out:
[101, 2769, 679, 1599, 3614, 872, 102]
[101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102, 2769, 1372, 1599, 3614, 872, 102]
# 第二种:tokenizer.encoder_plus() ----- 只能转化一个样本,结果是 token id、attention mask id、segment id 的字典
print(tokenizer.encode_plus('我不喜欢你'))
print(tokenizer.encode_plus('我不喜欢这世界','我只喜欢你','我很高兴')) # 一个样本仅仅最高支持两个句子
out:
{'input_ids': [101, 2769, 679, 1599, 3614, 872, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1]}
{'input_ids': [101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102, 2769, 1372, 1599, 3614, 872, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
# 第三种:最常用的一种,可以转化一个batch,结果是 token id、attention mask id、segment id 的字典
torkenizer.batch_encoder_plus(
batch_text_or_text_pairs: Union[
List[TextInput],
List[TextInputPair],
List[PreTokenizedInput],
List[PreTokenizedInputPair],
List[EncodedInput],
List[EncodedInputPair],
], # 给定 list类型的数据,不需要分词,每一个元素是一个样本
padding == True # True 表示 不到 max_length 会进行pading,默认用0进行pad
truncation== True # True 表示 根据 max_length 进行截断
max_length: Optional[int] = None, # 允许样本最大长度,需要小于等于 512
return_tensors == 'pt' # 表示返回数据为 pytorch 的tensor对象
)
inputs = tokenizer.batch_encode_plus(['我不喜欢这世界','我只喜欢你','我很高兴'],padding=True,truncation=True,max_length=30,return_tensors='pt')
print(inputs)
out:
{'input_ids': tensor([[ 101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102],
[ 101, 2769, 1372, 1599, 3614, 872, 102, 0, 0],
[ 101, 2769, 2523, 7770, 1069, 102, 0, 0, 0]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0]])}
# 将 input_ids 转化为 token
input_token = tokenizer.convert_ids_to_tokens(token_code['input_ids'])
print(input_token)
8.2.5、预训练的Bert获得 output 特征表征
# bert 模型的输出:
"""
Outputs: `Tuple` comprising various elements depending on the configuration (config) and inputs:
**last_hidden_state**: ``torch.FloatTensor`` of shape ``(batch_size, sequence_length, hidden_size)``
Sequence of hidden-states at the output of the last layer of the model.
**pooler_output**: ``torch.FloatTensor`` of shape ``(batch_size, hidden_size)``
Last layer hidden-state of the first token of the sequence (classification token)
further processed by a Linear layer and a Tanh activation function. The Linear
layer weights are trained from the next sentence prediction (classification)
objective during Bert pretraining. This output is usually *not* a good summary
of the semantic content of the input, you're often better with averaging or pooling
the sequence of hidden-states for the whole input sequence.
**hidden_states**: (`optional`, returned when ``config.output_hidden_states=True``)
list of ``torch.FloatTensor`` (one for the output of each layer + the output of the embeddings)
of shape ``(batch_size, sequence_length, hidden_size)``:
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
**attentions**: (`optional`, returned when ``config.output_attentions=True``)
list of ``torch.FloatTensor`` (one for each layer) of shape ``(batch_size, num_heads, sequence_length, sequence_length)``:
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.
"""
# bert forward 参数:
"""
input_ids=None, # token ids
attention_mask=None, # attention mask ids
token_type_ids=None # segment ids
"""
model.eval() # 验证模式,开启 dropout、BN层、LN层
outputs = model(input_ids=inputs['input_ids'],
attention_mask=inputs['attention_mask'],
token_type_ids=inputs['token_type_ids'])
print(output[0].shape)
print(output[1].shape)
print(output[2].shape)
print(output[3].shape)
8.2.6、基于 transformers 的 Bert 模型简单的案例
from transformers import BertModel,BertTokenizer,BertConfig,BertForMaskedLM
import torch
import torch.nn as nn
import os
model_path = 'bert_base_chiese_wwm_ext'
config_path = os.path.join(model_path,'bert_config.json')
class Bert_Model(nn.Module):
def __init__(self,bert_model_path,config_file_path):
super(Bert_Model, self).__init__()
self.bert_model_path = bert_model_path
self.config_file_path = config_file_path
self.tokenizer = BertTokenizer.from_pretrained(pretrained_model_name_or_path=self.bert_model_path)
config = BertConfig.from_pretrained(pretrained_model_name_or_path=self.config_file_path)
# 开启 output_hidden_states
config.output_hidden_states = True
# 开启 output_attention
config.output_attentions = True
self.bert = BertModel.from_pretrained(pretrained_model_name_or_path=self.bert_model_path,config=config)
# 最后一层 fc
self.fc1 = nn.Linear(768,2)
def forward(self,input_ids,attention_mask_ids,segment_ids):
outputs = self.bert(input_ids = input_ids,attention_mask = attention_mask_ids,token_type_ids = segment_ids)
# bert forward 参数
"""
input_ids=None, attention_mask=None, token_type_ids=None
"""
# bert outputs 结果
"""
Outputs:
`Tuple` comprising various elements depending on the configuration (config) and inputs:
**last_hidden_state**: ``torch.FloatTensor`` of shape ``(batch_size, sequence_length, hidden_size)``
Sequence of hidden-states at the output of the last layer of the model.
**pooler_output**: ``torch.FloatTensor`` of shape ``(batch_size, hidden_size)``
Last layer hidden-state of the first token of the sequence (classification token)
further processed by a Linear layer and a Tanh activation function. The Linear
layer weights are trained from the next sentence prediction (classification)
objective during Bert pretraining. This output is usually *not* a good summary
of the semantic content of the input, you're often better with averaging or pooling
the sequence of hidden-states for the whole input sequence.
**hidden_states**: (`optional`, returned when ``config.output_hidden_states=True``)
list of ``torch.FloatTensor`` (one for the output of each layer + the output of the embeddings)
of shape ``(batch_size, sequence_length, hidden_size)``:
Hidden-states of the model at the output of each layer plus the initial embedding outputs.
**attentions**: (`optional`, returned when ``config.output_attentions=True``)
list of ``torch.FloatTensor`` (one for each layer) of shape ``(batch_size, num_heads, sequence_length, sequence_length)``:
Attentions weights after the attention softmax, used to compute the weighted average in the self-attention heads.
"""
print('last_hidden_state:\n',outputs[0].shape)
print('pooler_output:\n',outputs[1].shape)
print('hidden_states 层数:\n',len(outputs[2]))
print('attentions 层数:\n',len(outputs[3]))
outputs = self.fc1(outputs[0][:,0,:])
return outputs
if __name__ == '__main__':
model_ = Bert_Model(model_path,config_path)
print(model_)
# tokenizer 的词汇表
print('中文"字"词汇表大小:',len(model_.tokenizer.vocab))
# 数据
data = ['我不喜欢这世界',
'我只喜欢你',
'我很高兴']
# 将数据转化为 ids
inputs_ids_dict = model_.tokenizer.batch_encode_plus(batch_text_or_text_pairs=data,
padding=True,truncation=True,max_length=65,return_tensors='pt')
print(inputs_ids_dict)
# 将ids 数据转化为 token
print([model_.tokenizer.convert_ids_to_tokens(text) for text in inputs_ids_dict['input_ids']])
# 预测
model_.eval() # 关闭 dropout、BN、LN层
with torch.no_grad():
outputs = model_(input_ids=inputs_ids_dict['input_ids'],attention_mask_ids=inputs_ids_dict['attention_mask'],segment_ids=inputs_ids_dict['token_type_ids'])
print('logits:\n',outputs)
out:
中文"字"词汇表大小: 21128
{'input_ids': tensor([[ 101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102],
[ 101, 2769, 1372, 1599, 3614, 872, 102, 0, 0],
[ 101, 2769, 2523, 7770, 1069, 102, 0, 0, 0]]), 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 0, 0, 0]])}
[['[CLS]', '我', '不', '喜', '欢', '这', '世', '界', '[SEP]'], ['[CLS]', '我', '只', '喜', '欢', '你', '[SEP]', '[PAD]', '[PAD]'], ['[CLS]', '我', '很', '高', '兴', '[SEP]', '[PAD]', '[PAD]', '[PAD]']]
last_hidden_state:
torch.Size([3, 9, 768])
pooler_output:
torch.Size([3, 768])
hidden_states 层数:
13
attentions 层数:
12
logits:
tensor([[0.3703, 0.6640],
[0.1199, 0.7623],
[0.1927, 0.6366]])
优化思路:
1、定义数据预处理类:
停止词、高频词、空格、数字、大小写、噪声标签等
2、word2vec 训练时使用腾讯预训练的词向量
KeyedVectors.load_word2vec_format
3、构建 embeddiing 类的时候加 max_seq 参数
4、LDA是贝叶斯模型,生成LDA主题向量前是否考虑使用PCA降维,将特征进行独立化