放牧代码和思想
专注自然语言处理、机器学习算法
    愛しさ 優しさ すべて投げ出してもいい

基于神经网络的高性能依存句法分析器

目录

本文剖析了一个基于神经网络分类模型和arc-standard转移动作的判决式汉语依存句法分析器,其Java实现由我移植自LTP的C++代码,并添加了详细的注释,将内部数据结构由哈希表替换为高速的DoubleArrayTrie,分词和词性标注替换为HanLP原生的分词器,并深度集成到了HanLP中开源;现在还可以在线句法分析并可视化。本文将结合相应的论文,以图文形式记录代码和注释所不能覆盖的细节,以贯彻HanLP项目向生产环境普及NLP技术的初衷。

本文按照由浅到深,再由深到浅的方针编排。第一页介绍了调用接口,给用户或读者简要介绍了一下这是什么、怎么使用,给大家一个具体的印象;第二页整理了本神经网络句法分析器涉及到的众多论文,尝试深度剖析其原理;第三页从错综繁复的理论中走出来,展示了工程上的实现细节,以供借鉴改进。

本文中“代码”“实现”如不注明,都特指HanLP中移植的LTP Parser的Java代码。必须注意的是,虽然HanLP是一个商业友好的开源项目,但LTP是商用收费的。所以本Java实现严格遵守LTP的Licence,仅供科研人员和NLP爱好者研究学习用,商用必须向LTP付费,详见文末的版权声明一章。

水平有限,加上成文仓促,文中错误敬请指正。

调用方法

依存句法分析器类图

HanLP中有很多句法分析器,其中大部分都很朴素,目前的设计如下:

神经网络依存句法分析40.png

最左边的就是本文将要剖析的神经网络依存句法分析器,也许再加一个父类TransitionBasedDependencyParser会更好。

接口

/**
 * 依存句法分析器接口
 *
 * @author hankcs
 */
public interface IDependencyParser
{
    /**
     * 分析句子的依存句法
     *
     * @param termList 句子,可以是任何具有词性标注功能的分词器的分词结果
     * @return CoNLL格式的依存句法树
     */
    CoNLLSentence parse(List<Term> termList);

    /**
     * 分析句子的依存句法
     *
     * @param sentence 句子
     * @return CoNLL格式的依存句法树
     */
    CoNLLSentence parse(String sentence);

    /**
     * 获取Parser使用的分词器
     *
     * @return
     */
    Segment getSegment();

    /**
     * 设置Parser使用的分词器
     *
     * @param segment
     */
    IDependencyParser setSegment(Segment segment);

    /**
     * 获取依存关系映射表
     *
     * @return
     */
    Map<String, String> getDeprelTranslator();

    /**
     * 设置依存关系映射表
     *
     * @param deprelTranslator
     */
    IDependencyParser setDeprelTranslator(Map<String, String> deprelTranslator);

    /**
     * 依存关系自动转换开关
     * @param enable
     */
    IDependencyParser enableDeprelTranslator(boolean enable);
}

一个Demo

/**
 * 依存句法分析(神经网络句法模型需要-Xms1g -Xmx1g -Xmn512m)
 * @author hankcs
 */
public class DemoDependencyParser
{
    public static void main(String[] args)
    {
        CoNLLSentence sentence = HanLP.parseDependency("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。");
        System.out.println(sentence);
        // 可以方便地遍历它
        for (CoNLLWord word : sentence)
        {
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 也可以直接拿到数组,任意顺序或逆序遍历
        CoNLLWord[] wordArray = sentence.getWordArray();
        for (int i = wordArray.length - 1; i >= 0; i--)
        {
            CoNLLWord word = wordArray[i];
            System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
        }
        // 还可以直接遍历子树,从某棵子树的某个节点一路遍历到虚根
        CoNLLWord head = wordArray[12];
        while ((head = head.HEAD) != null)
        {
            if (head == CoNLLWord.ROOT) System.out.println(head.LEMMA);
            else System.out.printf("%s --(%s)--> ", head.LEMMA, head.DEPREL);
        }
    }
}

输出

1	徐先生	徐先生	nh	nr	_	4	主谓关系	_	_
2	还	还	d	d	_	4	状中结构	_	_
3	具体	具体	a	a	_	4	状中结构	_	_
4	帮助	帮助	v	v	_	0	核心关系	_	_
5	他	他	r	rr	_	4	兼语	_	_
6	确定	确定	v	v	_	4	动宾关系	_	_
7	了	了	u	ule	_	6	右附加关系	_	_
8	把	把	p	pba	_	15	状中结构	_	_
9	画	画	v	v	_	8	介宾关系	_	_
10	雄鹰	雄鹰	n	n	_	9	动宾关系	_	_
11	、	、	wp	w	_	12	标点符号	_	_
12	松鼠	松鼠	n	n	_	10	并列关系	_	_
13	和	和	c	cc	_	14	左附加关系	_	_
14	麻雀	麻雀	n	n	_	10	并列关系	_	_
15	作为	作为	p	p	_	6	动宾关系	_	_
16	主攻	主攻	v	v	_	17	定中关系	_	_
17	目标	目标	n	n	_	15	动宾关系	_	_
18	。	。	wp	w	_	4	标点符号	_	_

徐先生 --(主谓关系)--> 帮助
还 --(状中结构)--> 帮助
具体 --(状中结构)--> 帮助
帮助 --(核心关系)--> ##核心##
他 --(兼语)--> 帮助
确定 --(动宾关系)--> 帮助
了 --(右附加关系)--> 确定
把 --(状中结构)--> 作为
画 --(介宾关系)--> 把
雄鹰 --(动宾关系)--> 画
、 --(标点符号)--> 松鼠
松鼠 --(并列关系)--> 雄鹰
和 --(左附加关系)--> 麻雀
麻雀 --(并列关系)--> 雄鹰
作为 --(动宾关系)--> 确定
主攻 --(定中关系)--> 目标
目标 --(动宾关系)--> 作为
。 --(标点符号)--> 帮助

。 --(标点符号)--> 帮助
目标 --(动宾关系)--> 作为
主攻 --(定中关系)--> 目标
作为 --(动宾关系)--> 确定
麻雀 --(并列关系)--> 雄鹰
和 --(左附加关系)--> 麻雀
松鼠 --(并列关系)--> 雄鹰
、 --(标点符号)--> 松鼠
雄鹰 --(动宾关系)--> 画
画 --(介宾关系)--> 把
把 --(状中结构)--> 作为
了 --(右附加关系)--> 确定
确定 --(动宾关系)--> 帮助
他 --(兼语)--> 帮助
帮助 --(核心关系)--> ##核心##
具体 --(状中结构)--> 帮助
还 --(状中结构)--> 帮助
徐先生 --(主谓关系)--> 帮助

麻雀 --(并列关系)--> 雄鹰 --(动宾关系)--> 画 --(介宾关系)--> 把 --(状中结构)--> 作为 --(动宾关系)--> 确定 --(动宾关系)--> 帮助 --(核心关系)--> ##核心##

可视化

可以使用DependencyViewer进行可视化:

神经网络依存句法分析51.png

使用英文依存标签

由于训练的时候使用的是Chinese Dependency Treebank 1.0,所以原始的标签是英文的,在Parser中,被按照下表进行了转换:

Tag 关系 Description Example
SBV 主谓关系 subject-verb 我送她一束花 (我 <– 送)
VOB 动宾关系 直接宾语,verb-object 我送她一束花 (送 –> 花)
IOB 间宾关系 间接宾语,indirect-object 我送她一束花 (送 –> 她)
FOB 前置宾语 前置宾语,fronting-object 他什么书都读 (书 <– 读)
DBL 兼语 double 他请我吃饭 (请 –> 我)
ATT 定中关系 attribute 红苹果 (红 <– 苹果)
ADV 状中结构 adverbial 非常美丽 (非常 <– 美丽)
CMP 动补结构 complement 做完了作业 (做 –> 完)
COO 并列关系 coordinate 大山和大海 (大山 –> 大海)
POB 介宾关系 preposition-object 在贸易区内 (在 –> 内)
LAD 左附加关系 left adjunct 大山和大海 (和 <– 大海)
RAD 右附加关系 right adjunct 孩子们 (孩子 –> 们)
IS 独立结构 independent structure 两个单句在结构上彼此独立
WP 标点符号 punctuation 标点符号
HED 核心关系 head 指整个句子的核心

如果你更喜欢英文标签,还可以关闭中文依存自动转换:

IDependencyParser parser = new NeuralNetworkDependencyParser().enableDeprelTranslator(false);
System.out.println(parser.parse("徐先生还具体帮助他确定了把画雄鹰、松鼠和麻雀作为主攻目标。"));

输出:

1	徐先生	徐先生	nh	nr	_	4	SBV	_	_
2	还	还	d	d	_	4	ADV	_	_
3	具体	具体	a	a	_	4	ADV	_	_
4	帮助	帮助	v	v	_	0	HED	_	_
5	他	他	r	rr	_	4	DBL	_	_
6	确定	确定	v	v	_	4	VOB	_	_
7	了	了	u	ule	_	6	RAD	_	_
8	把	把	p	pba	_	15	ADV	_	_
9	画	画	v	v	_	8	POB	_	_
10	雄鹰	雄鹰	n	n	_	9	VOB	_	_
11	、	、	wp	w	_	12	WP	_	_
12	松鼠	松鼠	n	n	_	10	COO	_	_
13	和	和	c	cc	_	14	LAD	_	_
14	麻雀	麻雀	n	n	_	10	COO	_	_
15	作为	作为	p	p	_	6	VOB	_	_
16	主攻	主攻	v	v	_	17	ATT	_	_
17	目标	目标	n	n	_	15	VOB	_	_
18	。	。	wp	w	_	4	WP	_	_

可视化

神经网络依存句法分析42.png

与LTP对比

神经网络依存句法分析44.png

可以发现对这个句子,除了分词和词性标注的不同,其他都是一致的。至于箭头的方向,那是可视化工具决定的,我个人认为应该指向head更好。

知识共享许可协议 知识共享署名-非商业性使用-相同方式共享码农场 » 基于神经网络的高性能依存句法分析器

评论 26

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #9

    请问这个神经网路模型的训练代码在哪里。我找了好久没有找到。

    微微小冷3年前 (2021-08-30)回复
  2. #8

    图片显示不了

    hipanda5年前 (2019-04-24)回复
    • 切换到外网IP就可以了 应该是我的网络的问题

      hipanda5年前 (2019-04-24)回复
  3. #7

    您好 我看代码 好像没有神经网络的训练部分吧?请问训练是如何完成的?

    karis7年前 (2017-07-18)回复
    • 麻烦问一下,最后你找到训练部分了吗?

      leilei6年前 (2017-12-04)回复
  4. #6

    博主,请问
    # 依存句法分析
    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

    依存句法为什么会报这样的错误?

    Law7年前 (2016-12-30)回复
  5. #5

    博主您好,我想试下的s-LSTM方法,请问能否给下语料呢?多谢!

    Deep NLP8年前 (2016-04-27)回复
  6. #4

    请参考文末Reference

    hankcs8年前 (2016-01-03)回复
  7. #3

    您好,想在NLP中使用神经网络文本特征的输入格式应该怎么定义?

    柳若先8年前 (2015-12-30)回复
    • 请详细描述问题。

      hankcs8年前 (2015-12-30)回复
      • 想用DBN 从中文文本挖掘信息,有标注好的语料,如何把这些标注好的语料作为特征放到DBN中训练

        柳若先8年前 (2015-12-30)回复
        • 请参考对方的文档。

          hankcs8年前 (2015-12-31)回复
  8. #2

    博主好,最近在用你的库,其中“再说”跟“再讲”的词性一个是C,一个是V,这很奇怪,像这种情况,我们该怎么把“再说”的词性改过来?

    Sam8年前 (2015-12-22)回复
    • 请参考https://github.com/hankcs/HanLP#修改方法

      hankcs8年前 (2015-12-22)回复
      • “修改了后者之后必须同步删除前者的缓存”,删除缓存是什么意思啊?有一个文件还是有这样的接口可调用?

        Sam8年前 (2015-12-22)回复
        • 请通读文档至少一次!

          hankcs8年前 (2015-12-23)回复
    • 譬如这样的句子:在说什么&在讲什么,再说一遍&再讲一遍,句子结构、词性应该是一样的,为什么分析的结果会不一样?

      Sam8年前 (2015-12-22)回复
      • 词不一样,数据的稀疏性。

        hankcs8年前 (2015-12-22)回复
  9. #1

    博主您好,看过您的文章受益匪浅。我使用LTP时发现,LTP的“语义依存分析”似乎比“依存句法分析”更加适合应用于语义理解,请问您有“语义依存分析”的源码或者知道实现方法吗

    Terry9年前 (2015-12-01)回复
    • 你好,这是学术界新提出来的方法,最近还有一场赛事。在论文都没有公开发表的时候,没人知道详情。

      hankcs9年前 (2015-12-01)回复
      • 嗯,我会继续关注之,谢了

        Terry9年前 (2015-12-01)回复
      • 大神我也在关注这个,有最新消息分享一下,还有我发现你能找到好多论文的材料,请问你平时都是去哪里找的,阁下有空的话回答下我的问题。

        岩枭6年前 (2018-07-16)回复

我的作品

HanLP自然语言处理包《自然语言处理入门》