实现细节
在上一章结合论文介绍了神经网络依存句法分析器的整体架构和少量细节,这里将从工程的角度将分析流程整个过一遍。
分词与词性标注
默认的分词模块是基于词语的BiGram概率图最短路分词器(开启了人名识别等),词性标注是HMM-Viterbi。你可以从HanLP实现的众多分词器中挑选一个,通过com.hankcs.hanlp.dependency.IDependencyParser#setSegment来使其生效。
句法分析器在接受了一个句子后首先将其分词词性标注,得到一个List<Term> termList。由于HanLP使用的是人民日报语料训练的分词模型,而句法分析模型使用的是CTB,CTB使用的是863词性标注集:
Tag | Description | Example | Tag | Description | Example |
a | adjective | 美丽 | ni | organization name | 保险公司 |
b | other noun-modifier | 大型, 西式 | nl | location noun | 城郊 |
c | conjunction | 和, 虽然 | ns | geographical name | 北京 |
d | adverb | 很 | nt | temporal noun | 近日, 明代 |
e | exclamation | 哎 | nz | other proper noun | 诺贝尔奖 |
g | morpheme | 茨, 甥 | o | onomatopoeia | 哗啦 |
h | prefix | 阿, 伪 | p | preposition | 在, 把 |
i | idiom | 百花齐放 | q | quantity | 个 |
j | abbreviation | 公检法 | r | pronoun | 我们 |
k | suffix | 界, 率 | u | auxiliary | 的, 地 |
m | number | 一, 第一 | v | verb | 跑, 学习 |
n | general noun | 苹果 | wp | punctuation | ,。! |
nd | direction noun | 右侧 | ws | foreign words | CPU |
nh | person name | 杜甫, 汤姆 | x | non-lexeme | 萄, 翱 |
所以这里还进行了一个映射。
转为依存实例
接下来句法分析器为这个句子建立了一个实例,将单词和词性映射为相应的ID:
/** * 将实例转为依存树 * @param data 实例 * @param dependency 输出的依存树 * @param with_dependencies 是否输出依存关系(仅在解析后才有意义) */ void transduce_instance_to_dependency(final Instance data, Dependency dependency, boolean with_dependencies)
提取聚类类别
对于每个词,都从3个聚类中找到了它所属的类(没找到的话就为null)。
/** * 获取词聚类特征 * @param data 输入数据 * @param cluster4 * @param cluster6 * @param cluster */ void get_cluster_from_dependency(final Dependency data, List<Integer> cluster4, List<Integer> cluster6, List<Integer> cluster)
提取原始特征
如同上文所述,对这些特征进行了提取:
/** * 生成特征 * @param s 当前状态 * @param cluster4 * @param cluster6 * @param cluster * @param features 输出特征 */ void get_features(final State s, final List<Integer> cluster4, final List<Integer> cluster6, final List<Integer> cluster, List<Integer> features) { Context ctx = new Context(); get_context(s, ctx); get_basic_features(ctx, s.ref.forms, s.ref.postags, s.deprels, features); get_distance_features(ctx, features); get_valency_features(ctx, s.nr_left_children, s.nr_right_children, features); get_cluster_features(ctx, cluster4, cluster6, cluster, features); }
神经网络前向传播
神经网络模型对输入特征做一个前向传播:
/** * 给每个类别打分 * @param attributes 属性 * @param retval 返回各个类别的得分 */ void score(final List<Integer> attributes, List<Double> retval) { Map <Integer,Integer > encoder = precomputation_id_encoder; // arma.vec hidden_layer = arma.zeros<arma.vec>(hidden_layer_size); Matrix hidden_layer = Matrix.zero(hidden_layer_size, 1); for (int i = 0, off = 0; i < attributes.size(); ++i, off += embedding_size) { int aid = attributes.get(i); int fid = aid * nr_feature_types + i; Integer rep = encoder.get(fid); if (rep != null) { hidden_layer.plusEquals(saved.col(rep)); } else { // 使用向量而不是特征本身 // W1[0:hidden_layer, off:off+embedding_size] * E[fid:]' hidden_layer.plusEquals(W1.block(0, off, hidden_layer_size, embedding_size).times(E.col(aid))); } } hidden_layer.plusEquals(b1); // 加上偏置 Matrix output = W2.times(new Matrix (hidden_layer.cube())); // 立方激活函数 // retval.resize(nr_classes, 0.); retval.clear(); for (int i = 0; i < nr_classes; ++i) { retval.add(output.get(i, 0)); } }
这里有一个小trick,由于许多矩阵运算的中间步骤是固定的,所以预先算好了存在saved矩阵里面,这对运行时速度有很大提升。
分类决策
句法分析器执行输出层合法且得分最高的动作:
for (int step = 1; step < L * 2 - 1; ++step) { List<Integer> attributes = new ArrayList<Integer>(); if (use_cluster) { get_features(states[step], cluster4, cluster6, cluster, attributes); } else { get_features(states[step], attributes); } List<Double> scores = new ArrayList<Double>(system.number_of_transitions()); classifier.score(attributes, scores); List<Action> possible_actions = new ArrayList<Action>(); system.get_possible_actions(states[step], possible_actions); int best = -1; for (int j = 0; j < possible_actions.size(); ++j) { int l = system.transform(possible_actions.get(j)); if (best == -1 || scores.get(best) < scores.get(l)) { best = l; } } Action act = system.transform(best); system.transit(states[step], act, states[step + 1]); }
后期修饰
将依存关系转为String类型,如果enable了中英转换的话则转换一下,填充到CoNLLWord中作为输出。
巧妙之处
可见整个句法分析器的难点有两个,一个是特征的抽象化(聚类、向量化),另一个就是神经网络模型。
另外,除了最初的将单词和词性等从String转为ID之外,整个句法分析器没有涉及到任何字符串操作,取而代之的是大量的矩阵运算。这很好地解决了“传统句法分析器将95%以上的时间浪费在特征提取上”这一弊病,特别是利用神经网络自动抽取组合特征中的隐含语法信息这一点,相较于手工编写特征模板,前进了一大步。
版权声明
严正声明,保护版权,支持开源,商用责任自负!
本NeuralNetworkParser由hankcs移植自LTP的C++代码,将内部数据结构及分词、标注模块替换为HanLP原生。
仅供科研人员、NLP爱好者学习研究用;如果您在HanLP移植的NeuralNetworkParser的基础上取得了研究成果,请您注明“使用了HanLP汉语言处理包(https://github.com/hankcs/HanLP)中移植的LTP依存句法分析模块”,并按LTP的要求添加相应声明;如作商业用途,必须遵守LTP开源协议中的付费规定!
附录:LTP开源协议
开源协议
语言技术平台面向国内外大学、中科院各研究所以及个人研究者免费开放源代码,但如上述机构和个人将该平台用于商业目的(如企业合作项目等)则需要付费。
除上述机构以外的企事业单位,如申请使用该平台,需付费。
凡涉及付费问题,请发邮件到 car@ir.hit.edu.cn 洽商。
如果您在LTP基础上发表论文或取得科研成果,请您在发表论文和申报成果时声明“使用了哈工大社会计算与信息检索研究中心研制的语言技术平台(LTP)”,参考文献中加入以下论文: Wanxiang Che, Zhenghua Li, Ting Liu. LTP: A Chinese Language Technology Platform. In Proceedings of the Coling 2010:Demonstrations. 2010.08, pp13-16, Beijing, China. 同时,发信给 car@ir.hit.edu.cn ,说明发表论文或申报成果的题目、出处等。
Reference
http://deeplearning.stanford.edu/wiki/index.php/Softmax%E5%9B%9E%E5%BD%92
https://catalog.ldc.upenn.edu/LDC2012T05
http://blog.csdn.net/danieljianfeng/article/details/41901063#t4
http://www.ltp-cloud.com/intro/#dp_how
http://ltp.readthedocs.org/zh_CN/latest/license.html
Transition-based Dependency Parsing with Rich Non-local Features.pdf
Transition-Based Dependency Parsing.pdf
Incremental Structured Prediction Using a Global Learning and Beam-Search Framework.pdf
请问这个神经网路模型的训练代码在哪里。我找了好久没有找到。
图片显示不了
切换到外网IP就可以了 应该是我的网络的问题
您好 我看代码 好像没有神经网络的训练部分吧?请问训练是如何完成的?
麻烦问一下,最后你找到训练部分了吗?
博主,请问
# 依存句法分析
print(HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。"))
Traceback (most recent call last):
File "C:/Users/admin/PycharmProjects/text1/test6_jufa1.py", line 32, in <module>
print(HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。"))
jpype._jexception.ExceptionInInitializerErrorPyRaisable: java.lang.ExceptionInInitializerError
依存句法为什么会报这样的错误?
博主您好,我想试下的s-LSTM方法,请问能否给下语料呢?多谢!
请参考文末Reference
您好,想在NLP中使用神经网络文本特征的输入格式应该怎么定义?
请详细描述问题。
想用DBN 从中文文本挖掘信息,有标注好的语料,如何把这些标注好的语料作为特征放到DBN中训练
请参考对方的文档。
博主好,最近在用你的库,其中“再说”跟“再讲”的词性一个是C,一个是V,这很奇怪,像这种情况,我们该怎么把“再说”的词性改过来?
请参考https://github.com/hankcs/HanLP#修改方法
“修改了后者之后必须同步删除前者的缓存”,删除缓存是什么意思啊?有一个文件还是有这样的接口可调用?
请通读文档至少一次!
譬如这样的句子:在说什么&在讲什么,再说一遍&再讲一遍,句子结构、词性应该是一样的,为什么分析的结果会不一样?
词不一样,数据的稀疏性。
博主您好,看过您的文章受益匪浅。我使用LTP时发现,LTP的“语义依存分析”似乎比“依存句法分析”更加适合应用于语义理解,请问您有“语义依存分析”的源码或者知道实现方法吗
你好,这是学术界新提出来的方法,最近还有一场赛事。在论文都没有公开发表的时候,没人知道详情。
嗯,我会继续关注之,谢了
大神我也在关注这个,有最新消息分享一下,还有我发现你能找到好多论文的材料,请问你平时都是去哪里找的,阁下有空的话回答下我的问题。