2021SC@SDUSC
系列文章目录
(十六)PKE代码分析九
前言
pke包含模型如下:
本篇博客将开始从有监督模型的基于神经的模型进行代码分析
supervised->neural_based
目录
一、seq2seq.py
用于自动关键短语提取的 Seq2Seq 模型的实现
(一)原理
目前Seq2Seq模型在机器翻译,语音识别,文本摘要,问答系统等领域取得了巨大的成功。如图1所示,Seq2Seq其实就是Encoder-Decoder结构的网络,它的输入是一个序列,输出也是一个序列。在Encoder中,将序列转换成一个固定长度的向量,然后通过Decoder将该向量转换成我们想要的序列输出出来。
图1 Encoder-Decoder结构
如图2所示,Encoder和Decoder一般都是RNN,通常为LSTM或者GRU,图中每一个方格都为一个RNN单元。
在Encoder中,“欢迎/来/北京”这些词转换成词向量,也就是Embedding,我们用 vi 来表示,与上一时刻的隐状态 h i-1 按照时间顺序进行输入,每一个时刻输出一个隐状态 ,我们可以用函数 表达RNN隐藏层的变换: 。假设有t个词,最终通过Encoder自定义函数 将各时刻的隐状态变换为向量 : ,这个 就相当于从“欢迎/来/北京”这几个单词中提炼出来的大概意思一样,包含了这句话的含义。
Decoder的每一时刻的输入为Eecoder输出的 c 和Decoder前一时刻解码的输出 Si-1 ,还有前一时刻预测的词的向量 (如果是预测第一个词的话,此时输入的词向量为“_GO”的词向量,标志着解码的开始),我们可以用函数 表达解码器隐藏层变换: 。直到解码解出“_EOS”,标志着解码的结束。
图2 Encoder-Decoder细节
参考资料:简说Seq2Seq原理及实现 - 知乎 (zhihu.com)
(二)函数
包含一个类
class Seq2Seq(SupervisedLoadFile):
类中包含4个函数,函数很简单
1、def __init__(self):
重新初始化定义Seq2Seq
super(Seq2Seq, self).__init__()
# 输入序列
self.sequence = []
# 词汇
self.vocabulary = ['<SOS>', '<EOS>', '<UNK>']
2、def document_to_ix(self):
将文档转换为 ix 的序列
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))
except ValueError:
self.sequence.append(self.vocabulary.index('<UNK>'))
self.sequence.append(self.vocabulary.index('<EOS>'))
3、def candidate_selection(self): pass
4、def candidate_weighting(self): pass
比较值得一提的是导入的包
(三)包
1.from __future__ import
Python的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动。有些改动是不兼容旧版本的,也就是在当前版本运行正常的代码,到下一个版本运行就可能不正常了。
从Python 2.7到Python 3.x就有不兼容的一些改动,比如2.x里的字符串用'xxx'表示str,Unicode字符串用u'xxx'表示unicode,而在3.x中,所有字符串都被视为unicode,因此,写u'xxx'和'xxx'是完全一致的,而在2.x中以'xxx'表示的str就必须写成b'xxx',以此表示“二进制字符串”。
要直接把代码升级到3.x是比较冒进的,因为有大量的改动需要测试。相反,可以在2.7版本中先在一部分代码中测试一些3.x的特性,如果没有问题,再移植到3.x不迟。
Python提供了future模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性。
(1)from __future__ import absolute_import
这是一个在py2.x中导入3.x的导入特性的语句, 是为了区分出绝对导入和相对导入.
在一般的Python学习资料中介绍3.x的相对导入时候一般都会说相对导入最后不要超过两层.
但是需要区分出我们编写的代码是干嘛的,如果是写的应用程序,在加入了from __future__ import absolute_import 之后,那么在程序的编写过程中使用类似from package.submodule import b 只能导入系统环境路径里面的包,导入不了你写的应用程序的子包,如果导入你写的应用程序的子包必须使用from ..submodule import b。
如果写的是工具类程序,比如说写的是三方包,发布给别人安装。那么在加入了from __future__ import absolute_import 之后还是可以在相对导入的时候使用from package.submodule import b 。那么这么做不是from __future__ import absolute_import 所说的特性没有了么。其实不然。因为我们编写的程序是需要安装在系统环境路径里面的,所以这种绝对导入的方式是可以相对导入的,这个时候搜索包名的时候是在系统环境路径里面搜索,但是因为你的包就在这些路径的某一个路径里面,所以可以搜得到from package.submodule import b 里面的b(模块,函数,变量,类)。这种编写工具包以绝对导入进行相对导入的方法还避免了from ..submodule import b 最好导入不超过两层的这一建议. 特别适合在开发大型工具的时候。比如著名的深度学习框架tensorflow就是用的这种特性.
(2)from __future__ import print_function
在开头加上from __future__ import print_function
这句之后,即使在python2.X,使用print就得像python3.X那样加括号使用。python2.X中print不需要括号,而在python3.X中则需要。
# python2.7
print "Hello world"
# python3
print("Hello world")
2.from pke.supervised.api import SupervisedLoadFile
根据名字可以看出,这个是存在pke中的一个文件,结构如下
下面对这个文件进行代码分析
二、api.py
监督模型的抽象基类
包含一个类
class SupervisedLoadFile(LoadFile):#SupervisedLoadFile 类为监督模型提供额外的基本函数。
类中包含5个函数
1.def __init__(self):
重新定义初始化器
super(SupervisedLoadFile, self).__init__()
#实例容器
self.instances = {}
2.def feature_scaling(self):
将特征缩放到 [0.1]
candidates = self.instances.keys()
X = [self.instances[u] for u in candidates]
X = MinMaxScaler().fit_transform(X)
for i, candidate in enumerate(candidates):
self.instances[candidate] = X[i]
3.def feature_extraction(self): pass
用于特征提取的骨架
4.def classify_candidates(self, model=None):
将候选词分类为关键短语或非关键短语。
参数:
model(str):以pickle格式加载模型的路径,默认为None。
# 如果没有提供,则设置默认模型
if model is None:
instance = self.__class__.__name__
# model = os.path.join(self._models, instance+"-semeval2010.pickle")
if six.PY2:
model = os.path.join(self._models,
instance + "-semeval2010.py2.pickle")
else:
model = os.path.join(self._models,
instance + "-semeval2010.py3.pickle")
# 加载模型
clf = load_model(model)
# with open(model, 'rb') as f:
# clf = pickle.load(f)
# 获取实例矩阵
candidates = self.instances.keys()
X = [self.instances[u] for u in candidates]
# 对候选进行分类
y = clf.predict_proba(X)
for i, candidate in enumerate(candidates):
self.weights[candidate] = y[i][1]
5.def candidate_weighting(self):
提取特征并使用默认参数对候选者进行分类。
if not self.candidates:
return
self.feature_extraction()
self.classify_candidates()
总结
本文分析了supervised->neural_based->seq2seq.py以及它调用的包,其中包括api.py