关于序列化:几种Java常用序列化框架的选型与对比

简介: 序列化与反序列化是咱们日常数据长久化和网络传输中常常应用的技术,然而目前各种序列化框架让人目迷五色,不分明什么场景到底采纳哪种序列化框架。本文会将业界开源的序列化框架进行比照测试,别离从通用性、易用性、可扩展性、性能和数据类型与Java语法反对五方面给出比照测试。 作者 | 云烨起源 | 阿里技术公众号 一 背景介绍序列化与反序列化是咱们日常数据长久化和网络传输中常常应用的技术,然而目前各种序列化框架让人目迷五色,不分明什么场景到底采纳哪种序列化框架。本文会将业界开源的序列化框架进行比照测试,别离从通用性、易用性、可扩展性、性能和数据类型与Java语法反对五方面给出比照测试。 通用性:通用性是指序列化框架是否反对跨语言、跨平台。易用性:易用性是指序列化框架是否便于应用、调试,会影响开发效率。可扩展性:随着业务的倒退,传输实体可能会发生变化,然而旧实体有可能还会被应用。这时候就须要思考所抉择的序列化框架是否具备良好的扩展性。性能:序列化性能次要包含工夫开销和空间开销。序列化的数据通常用于长久化或网络传输,所以其大小是一个重要的指标。而编解码工夫同样是影响序列化协定抉择的重要指标,因为现在的零碎都在谋求高性能。Java数据类型和语法反对:不同序列化框架所可能反对的数据类型以及语法结构是不同的。这里咱们要对Java的数据类型和语法个性进行测试,来看看不同序列化框架对Java数据类型和语法结构的反对度。上面别离对JDK Serializable、FST、Kryo、Protobuf、Thrift、Hession和Avro进行比照测试。二 序列化框架1 JDK SerializableJDK Serializable是Java自带的序列化框架,咱们只须要实现java.io.Serializable或java.io.Externalizable接口,就能够应用Java自带的序列化机制。实现序列化接口只是示意该类可能被序列化/反序列化,咱们还须要借助I/O操作的ObjectInputStream和ObjectOutputStream对对象进行序列化和反序列化。 上面是应用JDK 序列化框架进行编解码的Demo: 通用性 因为是Java内置序列化框架,所以自身是不反对跨语言序列化与反序列化。 易用性 作为Java内置序列化框架,无序援用任何内部依赖即可实现序列化工作。然而JDK Serializable在应用上相比开源框架难用许多,能够看到下面的编解码应用十分僵硬,须要借助ByteArrayOutputStream和ByteArrayInputStream才能够残缺字节的转换。 可扩展性 JDK Serializable中通过serialVersionUID管制序列化类的版本,如果序列化与反序列化版本不统一,则会抛出java.io.InvalidClassException异样信息,提醒序列化与反序列化SUID不统一。 java.io.InvalidClassException: com.yjz.serialization.java.UserInfo; local class incompatible: stream classdesc serialVersionUID = -5548195544707231683, local class serialVersionUID = -5194320341014913710下面这种状况,是因为咱们没有定义serialVersionUID,而是由JDK主动hash生成的,所以序列化与反序列化前后后果不统一。 然而咱们能够通过自定义serialVersionUID形式来躲避掉这种状况(序列化前后都是应用定义的serialVersionUID),这样JDK Serializable就能够反对字段扩大了。 private static final long serialVersionUID = 1L;性能 JDK Serializable是Java自带的序列化框架,然而在性能上其实一点不像亲生的。上面测试用例是咱们贯通全文的一个测试实体。 public class MessageInfo implements Serializable { private String username; private String password; private int age; private HashMap<String,Object> params; ... public static MessageInfo buildMessage() { MessageInfo messageInfo = new MessageInfo(); messageInfo.setUsername("abcdefg"); messageInfo.setPassword("123456789"); messageInfo.setAge(27); Map<String,Object> map = new HashMap<>(); for(int i = 0; i< 20; i++) { map.put(String.valueOf(i),"a"); } return messageInfo; }}应用JDK序列化后字节大小为:432。光看这组数字兴许不会感觉到什么,之后咱们会拿这个数据和其它序列化框架进行比照。 ...

April 30, 2021 · 3 min · jiezi

关于序列化:序列化ProtoBuf-与-JSON-的比较

介绍 ProtoBuf 是google团队开发的用于高效存储和读取结构化数据的工具。什么是结构化数据呢,正如字面上表白的,就是带有肯定构造的数据。比方电话簿上有很多记录数据,每条记录蕴含姓名、ID、邮件、电话等,这种构造反复呈现。 同类 XML、JSON 也能够用来存储此类结构化数据,然而应用ProtoBuf示意的数据能更加高效,并且将数据压缩得更小。 原理 ProtoBuf 是通过ProtoBuf编译器将与编程语言无关的特有的 .proto 后缀的数据结构文件编译成各个编程语言(Java,C/C++,Python)专用的类文件,而后通过Google提供的各个编程语言的反对库lib即可调用API。(对于proto构造体怎么编写,可自行查阅文档) ProtoBuf编译器装置 Mac : brew install protobuf 举个例子 1.先创立一个proto文件message.proto syntax = "proto3";message Person { int32 id = 1; string name = 2; repeated Phone phone = 4; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message Phone { string number = 1; PhoneType type = 2; }} 2.创立一个Java我的项目并且将proto文件搁置 src/main/proto 文件夹下 3.编译proto文件至Java版本用命令行 cd 到 src/main 目录下 ...

December 7, 2020 · 2 min · jiezi

关于序列化:serialVersionUID作用是什么以及如何生成的

失常不设置serialVersionUID 的序列化和反序列化先定义一个实体Student.class,须要实现Serializable接口,然而不须要实现get(),set()办法 import java.io.Serializable;public class Student implements Serializable { private int age; private String name; public Student(int age, String name) { this.age = age; this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; }}测试类,思路是先把Student对象序列化到Student.txt文件,而后再讲Student.txt文件反序列化成对象,输入。 public class SerialTest { public static void main(String[] args) { serial(); deserial(); } // 序列化 private static void serial(){ Student student = new Student(9, "Mike"); try { FileOutputStream fileOutputStream = new FileOutputStream("Student.txt"); ObjectOutputStream objectOutputStream= new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(student); objectOutputStream.flush(); } catch (Exception exception) { exception.printStackTrace(); } } // 反序列化 private static void deserial() { try { FileInputStream fis = new FileInputStream("Student.txt"); ObjectInputStream ois = new ObjectInputStream(fis); Student student = (Student) ois.readObject(); ois.close(); System.out.println(student.toString()); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }}输入后果,序列化文件咱们能够看到Student.txt,反序列化进去,外面的字段都是不变的,阐明反序列化胜利了。 ...

November 28, 2020 · 4 min · jiezi

关于序列化:适合时间序列数据的计算脚本

工夫序列数据的计算脚本须具备较强的有序计算能力,本文从此类工具中精心筛选了三种,从开发效率、语法表达能力、结构化函数库等方面进行深度比照,考查了各脚本在序号计算、绝对地位计算、有序汇合计算等重点运算上的体现,esProc 在这几款工具中的体现最为杰出。点击适宜工夫序列数据的计算脚本理解详情。 工夫序列数据在这里指按工夫排序的日常业务数据。对工夫序列数据进行计算时,不仅波及季度、月份、工作日、周末等惯例计算,还常常遇到较为简单的有序运算,这就要求脚本语言应具备相应的计算能力。个别用于解决工夫序列数据的计算脚本有SQL、Python Pandas、esProc,上面就让咱们深刻理解这些脚本,看看它们的能力差异。 SQLSQL历史悠久用户泛滥,在其模型框架内早已倒退到极限,简直每种简略运算都能找到对应的SQL解法,这其中就包含有序运算。 比方比上期的例子:表stock1001存储某支股票的交易信息,次要字段有交易日期transDate、收盘价price,请计算每个交易日与上个交易日相比收盘价的增长率。 这个例子属于绝对地位计算,如果应用窗口函数,SQL写法绝对容易: 但有些SQL不反对窗口函数,实现比上期就会麻烦得多: 上述代码之所以麻烦,首先是因为SQL是基于无序汇合的,自身没有序号,不不便进行有序运算,为了实现有序运算,就要为无序汇合硬造出序号列,这个过程须要自关联和分组汇总,代码比较复杂。其次,比上期属于绝对地位计算,如果SQL有绝对序号,这种计算会简略许多,但SQL没有绝对序号,只能将上一行关联到本行,变相实现相邻地位计算,代码因而变得复杂。 基于无序汇合的SQL不不便实现有序运算,窗口函数尽管能够缓解这一情况,但如果运算再简单时,也仍然麻烦。 比方中位数的例子:scores表存储学生问题,次要字段有学生编号studentdid、数学问题math,请计算数学问题的中位数。中位数的定义是:如果记录总数L为偶数,则返回两头两个值的均值(序号别离为L/2和L/2+1);如果L为奇数,则返回惟一的两头值(序号为(L+1)/2)。 SQL计算中位数的代码: 能够看到,尽管曾经应用了窗口函数,但SQL依然很简单。生成序号的过程对于有序汇合来说是多余的,但对SQL来说就是必不可少的步骤,尤其是本例这种必须显式应用序号的状况,这让代码显得简单。SQL实现分支判断也较麻烦,所以对L为奇数的状况进行解决时,并没有返回惟一的两头值,而是两个同样的两头值求均匀,这个技巧尽管能够简化分支判断,但了解起来稍有艰难。 如果应用取整函数,则能够奇妙地跳过判断过程,在简化代码的同时计算出中位数。但这种技巧与中位数的原始定义不同,会造成了解艰难,这里没有采纳。 再看一个稍简单的例子:间断上涨天数。库表AAPL存储某支股票的股价信息,次要字段有交易日期transDate、收盘价price,请计算该股票最长的间断上涨天数。SQL如下: 按天然思路实现这个工作时,应答日期有序的股票记录进行循环,如果本条记录与上一条记录相比是上涨的,则将间断上涨天数(初始为0)加1,如果是上涨的,则将间断上涨天数和以后最大间断上涨天数(初始为0)相比,选出新的以后最大间断上涨天数,再将间断上涨天数清0。如此循环直到完结,以后最大间断上涨天数即最终的最大间断上涨天数。 但SQL不善于有序计算,无奈用上述天然思路实现,只能用一些难懂的技巧。把按日期有序的股票记录分成若干组,间断上涨的记录分成同一组,也就是说,某天的股价比上一天是上涨的,则和上一天记录分到同一组,如果上涨了,则开始一个新组。最初看所有分组中最大的成员数量,也就是最多间断上涨的天数。 对于这两个稍简单的有序运算例子,SQL实现起来就曾经很艰难了,一旦遇到更简单的运算,SQL简直无奈实现。之所以呈现这种后果,是因为SQL的实践根底就是无序汇合,这种人造缺点无论怎样打补丁,都无奈从根本上解决问题。 Python PandasPandas是Python的结构化计算库,常被用作工夫序列数据的计算脚本。 作为结构化计算函数库,Pandas能够轻松实现简略的有序计算。比方,同样计算比上期,Pandas代码是这样的: 上述前两句是为了从文件读取数据,外围代码仅有一句。须要留神的是,Pandas并不能示意前一行,从而间接实现绝对地位计算,但能够用shift(1)函数将列整体下移一行,从而变相实现绝对地位计算。代码中行和列、前一行和下一行看上去很像,初学者容易混同。 作为古代程序语言,Pandas在有序计算方面要比SQL先进,次要体现在Pandas基于有序汇合构建,dataFrame数据类型天生具备序号,适宜进行有序计算。后面那些稍简单的有序计算,用SQL会十分艰难,用Pandas就绝对容易。 同样计算中位数,Pandas外围代码如下: 上述代码中,Pandas能够间接用\[N\]示意序号,而不必额定制作序号,代码因而失去简化。其次,Pandas是过程性语言,分支判断比SQL易于了解,也不须要技巧来简化代码。 同样稍简单的例子最长间断上涨天数,Pandas也比SQL容易实现。外围代码如下: 本例中,Pandas能够依照天然思路实现,而不用采取难懂的技巧,代码的表白效率要比SQL高得多。 有点遗憾的是, 有序计算经常要波及绝对地位计算,但Pandas不能间接表白绝对地位,只能把列下移一行来变相示意本行的上一行,了解时有点艰难。 Pandas在有序计算方面确实比SQL容易些,但遇到更简单的状况,Pandas也会变得很繁琐,下面试举两例。 比方过滤累计值的例子:表sales存储客户的销售额数据,次要字段有客户client、销售额amount,请找出销售额累计占到一半的前n个大客户,并按销售额从大到小排序。Pandas代码如下: 再比方计算股价最高3天的涨幅:表stock1001存储某支股票的每日股价,次要字段有交易日期transDate、收盘价price,请将股价最高的三天按逆序排列,计算每一天相比前一天的涨幅。Pandas代码如下: 这些更简单的例子也须要用到一些难懂的技巧去实现,不仅难以编写,而且难以读懂,这里就不再具体解释。 esProc与Pandas相似,esProc也具备丰盛的结构化计算函数,与Pandas不同的是,esProc除了基于有序汇合并反对序号机制外,还提供了不便的相邻援用机制,以及丰盛的地位函数,从而快捷不便地实现有序计算。 对于简略的有序计算,esProc和其余计算脚本一样,都能够轻松实现。比方同样比上期的esProc代码: 下面代码A1从csv文件取数,A2是外围代码。esProc能够用直观易懂的\[-1\]示意绝对本行的前一行,这是Pandas和SQL都没有的性能,也是esProc更为业余的体现。 同样计算中位数,esProc外围代码如下: 上述代码中,esProc能够间接用\[N\]示意序号,而不必额定制作序号,代码更为简洁。esProc同样是过程性语法,既能够用if/else语句实现大段的分支,也能够像本例一样,用if函数实现简洁的判断。 同样稍简单的例子最长间断上涨天数,esProc也比SQL/Pandas容易实现。外围代码如下: 本例中,esProc能够依照天然思路实现,而不用采取非凡的技巧,代码表白效率要比SQL更高。除此外, esProc既能够用循环语句实现大段的循环,也能够像本例一样,用循环函数max实现简洁的循环聚合。 esProc是更为业余的结构化计算语言,即便遇到更简单的有序计算,也能较为轻松地实现。 比方过滤累计值的例子,esProc只需如下代码: 本例按天然思维实现,先在A2计算出从最大的客户到每个客户的累计值,再在A3算出最大累计值的一半,在A4算出累计值大于A3的地位,最初按地位取数据就是所需后果。这里有体现esProc专业性的两处特色,其一是A3中的m函数,该函数能够逆序取数,-1示意倒数第一条;其二是A4中的pselect,能够按条件返回序号。这两种函数都能够无效简化有序计算。 再比方计算股价最高那3天的涨幅,esProc只需如下代码: 上述代码中,A2中的ptop示意前N条的地位,和后面的pselect相似,返回的不是记录的汇合,而是序号的汇合,相似这样的函数在esProc中还有很多,其目标都是简化有序计算。A4中的#也是esProc的特色,间接示意序号字段,应用起来十分不便,不用像SQL那样额定制作,或Pandas那样设定index。 通过比拟咱们能够发现,esProc具备丰盛的结构化函数,是业余的结构化计算语言,能够轻松实现常见的有序计算,即便更简单的计算也能无效简化,是更加现实的工夫序列数据计算脚本。

November 5, 2020 · 1 min · jiezi

关于序列化:序列化和反序列化

一、序列化的含意、意义及应用场景序列化:将对象写入到IO流中反序列化:从IO流中复原对象意义:序列化机制容许将实现序列化的Java对象转换位字节序列,这些字节序列能够保留在磁盘上,或通过网络传输,以达到当前复原成原来的对象。序列化机制使得对象能够脱离程序的运行而独立存在。应用场景:所有可在网络上传输的对象都必须是可序列化的,比方RMI(remote method invoke,即近程办法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有须要保留到磁盘的java对象都必须是可序列化的。通常倡议:程序创立的每个JavaBean类都实现Serializeable接口。二、序列化实现的形式果须要将某个对象保留到磁盘上或者通过网络传输,那么这个类应该实现Serializable接口或者Externalizable接口之一。 1、Serializable1.1 一般序列化Serializable接口是一个标记接口,不必实现任何办法。一旦实现了此接口,该类的对象就是可序列化的。 序列化步骤:步骤一:创立一个ObjectOutputStream输入流;步骤二:调用ObjectOutputStream对象的writeObject输入可序列化对象。 public class Person implements Serializable {  private String name;  private int age;  //我不提供无参结构器  public Person(String name, int age) {      this.name = name;      this.age = age;  }  @Override  public String toString() {      return "Person{" +              "name='" + name + ''' +              ", age=" + age +              '}';  }}public class WriteObject {  public static void main(String[] args) {      try (//创立一个ObjectOutputStream输入流           ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"))) {          //将对象序列化到文件s          Person person = new Person("9龙", 23);          oos.writeObject(person);      } catch (Exception e) {          e.printStackTrace();      }  }}复制代码反序列化步骤:步骤一:创立一个ObjectInputStream输出流;步骤二:调用ObjectInputStream对象的readObject()失去序列化的对象。 咱们将下面序列化到person.txt的person对象反序列化回来 public class Person implements Serializable {  private String name;  private int age;  //我不提供无参结构器  public Person(String name, int age) {      System.out.println("反序列化,你调用我了吗?");      this.name = name;      this.age = age;  }  @Override  public String toString() {      return "Person{" +              "name='" + name + ''' +              ", age=" + age +              '}';  }}public class ReadObject {  public static void main(String[] args) {      try (//创立一个ObjectInputStream输出流           ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) {          Person brady = (Person) ois.readObject();          System.out.println(brady);      } catch (Exception e) {          e.printStackTrace();      }  }}//输入后果//Person{name='9龙', age=23}复制代码waht???? 输入通知咱们,反序列化并不会调用构造方法。反序列的对象是由JVM本人生成的对象,不通过构造方法生成。 1.2 成员是援用的序列化如果一个可序列化的类的成员不是根本类型,也不是String类型,那这个援用类型也必须是可序列化的;否则,会导致此类不能序列化。 看例子,咱们新增一个Teacher类。将Person去掉实现Serializable接口代码。 public class Person{    //省略相干属性与办法}public class Teacher implements Serializable {    private String name;    private Person person;    public Teacher(String name, Person person) {        this.name = name;        this.person = person;    }     public static void main(String[] args) throws Exception {        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) {            Person person = new Person("路飞", 20);            Teacher teacher = new Teacher("雷利", person);            oos.writeObject(teacher);        }    }}复制代码 咱们看到程序间接报错,因为Person类的对象是不可序列化的,这导致了Teacher的对象不可序列化 1.3 同一对象序列化屡次的机制同一对象序列化屡次,会将这个对象序列化屡次吗?答案是否定的。 public class WriteTeacher {    public static void main(String[] args) throws Exception {        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) {            Person person = new Person("路飞", 20);            Teacher t1 = new Teacher("雷利", person);            Teacher t2 = new Teacher("红发香克斯", person);            //顺次将4个对象写入输出流            oos.writeObject(t1);            oos.writeObject(t2);            oos.writeObject(person);            oos.writeObject(t2);        }    }}复制代码顺次将t1、t2、person、t2对象序列化到文件teacher.txt文件中。 留神:反序列化的程序与序列化时的程序统一。 public class ReadTeacher {    public static void main(String[] args) {        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"))) {            Teacher t1 = (Teacher) ois.readObject();            Teacher t2 = (Teacher) ois.readObject();            Person p = (Person) ois.readObject();            Teacher t3 = (Teacher) ois.readObject();            System.out.println(t1 == t2);            System.out.println(t1.getPerson() == p);            System.out.println(t2.getPerson() == p);            System.out.println(t2 == t3);            System.out.println(t1.getPerson() == t2.getPerson());        } catch (Exception e) {            e.printStackTrace();        }    }}//输入后果//false//true//true//true//true复制代码从输入后果能够看出,Java序列化同一对象,并不会将此对象序列化屡次失去多个对象。 Java序列化算法所有保留到磁盘的对象都有一个序列化编码号当程序试图序列化一个对象时,会先查看此对象是否曾经序列化过,只有此对象从未(在此虚拟机)被序列化过,才会将此对象序列化为字节序列输入。如果此对象曾经序列化过,则间接输入编号即可。图示上述序列化过程。 1.4 java序列化算法潜在的问题因为java序利化算法不会反复序列化同一个对象,只会记录已序列化对象的编号。如果序列化一个可变对象(对象内的内容可更改)后,更改了对象内容,再次序列化,并不会再次将此对象转换为字节序列,而只是保留序列化编号。 public class WriteObject {    public static void main(String[] args) {        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));             ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"))) {            //第一次序列化person            Person person = new Person("9龙", 23);            oos.writeObject(person);            System.out.println(person);            //批改name            person.setName("海贼王");            System.out.println(person);            //第二次序列化person            oos.writeObject(person);            //顺次反序列化出p1、p2            Person p1 = (Person) ios.readObject();            Person p2 = (Person) ios.readObject();            System.out.println(p1 == p2);            System.out.println(p1.getName().equals(p2.getName()));        } catch (Exception e) {            e.printStackTrace();        }    }}//输入后果//Person{name='9龙', age=23}//Person{name='海贼王', age=23}//true//true复制代码1.5 可选的自定义序列化有些时候,咱们有这样的需要,某些属性不须要序列化。应用transient关键字抉择不须要序列化的字段。 public class Person implements Serializable {   //不须要序列化名字与年龄   private transient String name;   private transient int age;   private int height;   private transient boolean singlehood;   public Person(String name, int age) {       this.name = name;       this.age = age;   }   //省略get,set办法}public class TransientTest {   public static void main(String[] args) throws Exception {       try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));            ObjectInputStream ios = new ObjectInputStream(new FileInputStream("person.txt"))) {           Person person = new Person("9龙", 23);           person.setHeight(185);           System.out.println(person);           oos.writeObject(person);           Person p1 = (Person)ios.readObject();           System.out.println(p1);       }   }}//输入后果//Person{name='9龙', age=23', singlehood=true', height=185cm}//Person{name='null', age=0', singlehood=false', height=185cm}复制代码从输入咱们看到,应用transient润饰的属性,java序列化时,会疏忽掉此字段,所以反序列化出的对象,被transient润饰的属性是默认值。对于援用类型,值是null;根本类型,值是0;boolean类型,值是false。 应用transient尽管简略,但将此属性齐全隔离在了序列化之外。java提供了可选的自定义序列化。能够进行管制序列化的形式,或者对序列化数据进行编码加密等。 private void writeObject(java.io.ObjectOutputStream out) throws IOException;private void readObject(java.io.ObjectIutputStream in) throws IOException,ClassNotFoundException;private void readObjectNoData() throws ObjectStreamException;复制代码通过重写writeObject与readObject办法,能够本人抉择哪些属性须要序列化, 哪些属性不须要。如果writeObject应用某种规定序列化,则相应的readObject须要相同的规定反序列化,以便能正确反序列化出对象。这里展现对名字进行反转加密。 public class Person implements Serializable {   private String name;   private int age;   //省略构造方法,get及set办法   private void writeObject(ObjectOutputStream out) throws IOException {       //将名字反转写入二进制流       out.writeObject(new StringBuffer(this.name).reverse());       out.writeInt(age);   }   private void readObject(ObjectInputStream ins) throws IOException,ClassNotFoundException{       //将读出的字符串反转复原回来       this.name = ((StringBuffer)ins.readObject()).reverse().toString();       this.age = ins.readInt();   }}复制代码当序列化流不残缺时,readObjectNoData()办法能够用来正确地初始化反序列化的对象。例如,应用不同类接管反序列化对象,或者序列化流被篡改时,零碎都会调用readObjectNoData()办法来初始化反序列化的对象。 更彻底的自定义序列化 ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException; ...

September 15, 2020 · 1 min · jiezi

工程师如何给女友买包问问阿里百事通

阿里妹导读:工作那么忙,怎么给女朋友买包?是翻看包包的详情页,再从商品评论中去找信息吗?为了帮助类似的同学节省时间,阿里工程师们提出快速回答生成模型RAGE。你问它答,这个“百事通”能从整体结构,评论的抽取和表示及融合四个方面综合解决生成模型响应速率及生成质量的问题,进而提高生成的回答的真实性及有效性。从此,如何给女友“买包”,不再是难题。 本篇内容参考论文《Review-Driven Answer Generation for Product-Related Qestions in E-Commerce》论文作者为:武汉大学李晨亮、陈诗倩,阿里巴巴计峰、周伟、陈海青。 引言随着互联网技术的普及,电子商务产业得到了蓬勃的发展,用户的购买行为逐渐由线下转移到线上,然而线上购物带来便利的同时,弊端也逐渐显现。用户在做购买决定之前,通常希望获取更多的商品详情与使用感受等信息,然而,当网页浏览与点击代替了面对面的交易,用户无法获得直观的判断,仅能通过翻阅商品详情页及已购买用户的评论获取有效信息。用户需浏览及过滤大量的评论信息才能获得商品的综合评价,这无疑增加了线上购物的时间成本,降低了用户的购物体验。 为了解决线上环境信息获取渠道闭塞且耗时的问题,各大电商平台,例如,淘宝、亚马逊,相继提供社区问答(CQA)的服务。虽然社区问答在一定程度上缓解了部分用户浏览及过滤评论信息的时间成本,然而,等待已购买用户回答问题的过程同样是低效耗时且低召回的。因此,为了进一步节省用户购物时间,各大电商平台开始探索通过智能问答系统,自动、及时且真实的回答用户提出的商品相关性问题,帮助用户获取所需的信息。虽然现有的智能问答系统经过了几十年的发展,已经相对成熟,然而依然无法在电商领域广泛应用,其原因在于: 1.检索式问答系统过分依赖于问答库,而电商领域中问题形式千变万化,构造完整的问答库相对困难且耗时。2.现有的生成式问答系统的工作均以循环神经网络及其变种形式为基础。循环神经网络因其时序特性而无法并行处理,导致效率较低。3.目前生成式问答系统外部信息的引入主要依赖于结构化的知识库或者是关键词及主题模型,而在电商领域中,商品知识库的构造是一项消耗时间及人力成本的工作。 因此针对电商领域问答系统的需求现状及现有工作中存在的不足,我们创新性的提出了利用非结构评论信息引导回答生成的思想,同时提出了一种基于多层门控卷积神经网络的快速回答生成模型RAGE。该模型分别从整体结构,评论的抽取、表示及融合四个方面综合解决生成模型响应速率及生成质量的问题,进而提高生成的回答的真实性及有效性。 2 模型模型整体结构如图1: 2.1基础结构 2.1.1问题编码器 考虑到循环神经网络存在的种种不足,我们选择采用门控卷积神经网络作为问题编码器对问题序列进行编码。然而,卷积神经网络因其权值共享的特性,导致其对位置信息不敏感。为解决门控卷积神经网络位置信息丢失的问题,我们在输入矩阵中引入位置向量,以保证卷积过程中模型对于位置信息的敏感性。同时,我们将词性信息(POS tag)引入输入矩阵,词性信息中所包含的句法和词法信息能够更好的帮助门控卷积神经网络理解词间关系和文本语义。 而后我们通过堆叠多层的门控卷积神经网络来扩大其感受野,高层次的门控卷积神经网络可以通过低层次的门控卷积神经网络提取的特征建模距离中心词较远的上下文。同时,为了避免因为网络层数加深而产生梯度消失问题,本文利用残差学习网络(ResidualConnection),将l层输入与l层的输出结合作为l+1层的输入,以保证在反向传播的过程中梯度能稳定的在层级间传播。基于多层门控卷积神经网络的问题编码过程如公式2-2所示: 2.1.2 基础解码器 编码的过程与问题编码过程类似,不同的地方在于,卷积核的感受野被限制为上文而非上下文,因为回答生成的过程中,j时刻的生成词由第j时刻的状态向量决定,而就生成过程而言,下一时刻的状态对于当前时刻是未知的,所以j时刻的状态向量中不应该带有下文的信息,如公式2-4,2-5所示: 2.2 评论的抽取、表示及融合 2.2.1 评论的抽取 我们采用Word Mover’s Distance(WMD来衡量文本间的语义关系进行评论片段的抽取。对于给定问答对,首先拼接问答对中的问题与答案,而后对该问答对以及问题对应商品的所有评论片段集合R中的一个评论片段r进行分词并去除停用词,将两者分别表示为词袋,再分别计算每个词的词频。 最终用问答对和评论片段间的最小转移开销表示两者间的距离,如公式2-10所示: 其中限制条件为: 2.2.2评论片段的表示 2.2.3 评论的融合 为了使每一层的生成状态均对外部信息保持敏感,在回答生成器中我们同样采用了层次注意力机制。另外,我们认为问答任务中外部信息的选择过程不仅仅由当前的生成状态决定,还应与问题的语义密切相关。因此,在RAGE中我们利用与当前生成状态相关的加权问题编码向量与带权词典计算注意力权重,其原因在于加权问题编码向量中不仅仅含有当前生成状态的信息,同时包含了问题的语义信息,能够准确的对外部信息进行选择。其具体过程如公式2-14,2-15所示,最终得到与l层j时刻生成状态相关的评论信息编码向量。 式中表示第l层中,j时刻的问题编码向量与带权词典中中第i个词的表示向量计算的注意力权重。 为了避免信息的冗余,在每一层中本文通过门控机制选择性的利用问题编码信息和评论信息对生成状态进行更新,得到最终的生成状态。因而,将公式2-8改为公式2-16。 式中为门控权值向量,由l层的j时刻生成词生成状态,当前生成状态相关的加权问题编码向量,当前生成状态相关的评论信息编码经过函数()映射而得,具体程如公式2-17所示。 3 实验3.1对比模型 1)Seq2seqwith Attention(Bahdanau 2016)2)TA-Seq2seq(Xing2017)3)ConvSeq2seq(Gehring2017)4)ConvSeq2seq-RV:在ConvSeq2seq的基础上,每次生成时动态的限制生成的词必须出现在其对应的相关评论片段中5)RAGE/POS:RAGE去除POS信息 ...

July 9, 2019 · 1 min · jiezi

利用spark进行机器学习时模型序列化存储到hive解决方案

机器学习模型的训练和预测经常是在不同的时间点进行,在工程实现中,一般训练和预测都是在不同的子工程里面进行,训练子工程训练模型后存储到hive,之后预测子工程项目再将模型重hive中load出来进行预测 1.模型存储到hive存储很简单,将要存储的模型调用如下spark的序列化方法def serialize(spark: SparkSession)序列化后再转换拼装成sql,然后执行 spark.sql(insertSQL)即可,如下 case class ModleToHive(modelBizType: String, data: String) def save(modelUID: String): Unit = { val instance = ModleToHive( modelUID, modelBizType, model.serialize(spark) ) val instDf = Seq(instance).toDF() instDf.createOrReplaceTempView("model") var sqlString = s"insert into modelTable select modelUID as modelUID, modelBizType as modelBizType, data as saved_model" sqlString = sqlString + " from model " spark.sql(sqlString).collect()这样模型就存储到hive了 2.从hive仓库load模型并反序列化 val sqlString = s"select saved_model from modelTable where modelUID=modelUID " val modelHexBinary = spark.sql(sqlString).first() val ser = new KryoSerializer(sparkConf).newInstance() val byteBuffer = ByteBuffer.wrap(DatatypeConverter.parseHexBinary(modelHexBinary.getString(0))) ser.deserialize[T](byteBuffer)这样模型就又反序列化出来了,可用于预测了 ...

June 9, 2019 · 1 min · jiezi

异常检测的N种方法阿里工程师都盘出来了

阿里妹导读:互联网黑产盛行,其作弊手段层出不穷,导致广告效果降低,APP推广成本暴增。精准识别作弊是互联网公司和广告主的殷切期望。今天我们将从时间序列、统计、距离、线性方法、分布、树、图、行为序列、有监督机器学习和深度学习模型等多个角度探讨异常检测。作者 | 黎伟斌、胡熠、王皓 背景异常点检测(Outlier detection),又称为离群点检测,是找出与预期对象的行为差异较大的对象的一个检测过程。这些被检测出的对象被称为异常点或者离群点。异常点检测在生产生活中有着广泛应用,比如信用卡反欺诈、工业损毁检测、广告点击反作弊等。 异常点(outlier)是一个数据对象,它明显不同于其他的数据对象。如下图1所示,N1、N2区域内的点是正常数据。而离N1、N2较远的O1、O2、O3区域内的点是异常点。 异常检测的一大难点是缺少ground truth。常见的方法是先用无监督方法挖掘异常样本,再用有监督模型融合多个特征挖掘更多作弊。 近期使用多种算法挖掘异常点,下面从不同视角介绍异常检测算法的原理及其适用场景,考虑到业务特殊性,本文不涉及特征细节。 1.时间序列1.1 移动平均(Moving Average,MA) 移动平均是一种分析时间序列的常用工具,它可过滤高频噪声和检测异常点。根据计算方法的不同,常用的移动平均算法包括简单移动平均、加权移动平均、指数移动平均。假设移动平均的时间窗口为T,有一个时间序列: 1.1.1 简单移动平均(Simple Moving Average,SMA) 从上面的公式容易看出可以用历史的值的均值作为当前值的预测值,在序列取值随时间波动较小的场景中,上述移动均值与该时刻的真实值的差值超过一定阈值则判定该时间的值异常。 适用于: a.对噪声数据进行平滑处理,即用移动均值替代当前时刻取值以过滤噪声; b.预测未来的取值。 1.1.2 加权移动平均(Weighted Moving Average, WMA) 由于简单移动平均对窗口内所有的数据点都给予相同的权重,对近期的最新数据不够敏感,预测值存在滞后性。按着这个思路延伸,自然的想法就是在计算移动平均时,给近期的数据更高的权重,而给窗口内较远的数据更低的权重,以更快的捕捉近期的变化。由此便得到了加权移动平均和指数移动平均。 加权移动平均比简单移动平均对近期的变化更加敏感,加权移动平均的滞后性小于简单移动平均。但由于仅采用线性权重衰减,加权移动平均仍然存在一定的滞后性。 1.1.3 指数移动平均(Exponential Moving Average, EMA) 指数移动平均(Exponential Moving Average, EMA)和加权移动平均类似,但不同之处是各数值的加权按指数递减,而非线性递减。此外,在指数衰减中,无论往前看多远的数据,该期数据的系数都不会衰减到 0,而仅仅是向 0 逼近。因此,指数移动平均实际上是一个无穷级数,即无论多久远的数据都会在计算当期的指数移动平均数值时,起到一定的作用,只不过离当前太远的数据的权重非常低。在实际应用中,可以按如下方法得到t时刻的指数移动平均: 1.2 同比和环比 同比和环比计算公式如图2所示。适合数据呈周期性规律的场景中。如:1.监控APP的DAU的环比和同比,以及时发现DAU上涨或者下跌;2.监控实时广告点击、消耗的环比和同比,以及时发现变化。当上述比值超过一定阈值(阈值参考第10部分)则判定出现异常。 1.3 时序指标异常检测(STL+GESD) STL是一种单维度时间指标异常检测算法。大致思路是: (1)先将指标做STL时序分解,得到seasonal,trend,residual成分,如图3所示;(2)用GESD (generalized extreme studentized deviate)算法对trend+residual成分进行异常检测;(3)为增强对异常点的鲁棒性,将GESD算法中的mean,std等统计量用median, MAD(median absolute deviation)替换;(4)异常分输出:abnorm_score = (value - median)/MAD, value为当前值,median为序列的中位数。负分表示异常下跌,正分表示异常上升。 ...

May 23, 2019 · 1 min · jiezi

迈向电商认知智能时代的基石:阿里电商认知图谱揭秘

阿里妹导读:电商平台最大的挑战是从日益增长的海量商品(数十亿)中挑选出的一个小的子集(几十或上百)展示给用户,以满足用户的个性化的购物需求。为了解决仍存在的重复推荐、缺少新意等问题,我们提出建设大规模电商认知图谱。今天,搜索推荐事业部认知图谱团队全面总结了目前在构建电商认知图谱方面的探索,主要介绍认知图谱的定义、整体的构建思路,构建过程中一些具体的算法问题,和最终在搜索推荐上的应用。背景纵使近年来电商搜索、推荐算法已经取得了长足的进步,但这些算法依然存在许多问题,如推荐中经常为人诟病的重复推荐、缺少新意等。究其本质,这是因为现有的算法主要还是沿袭“商品到商品”的思路,并不是直接从用户需求来驱动的,甚至对用户需求没有一个清晰的定义。而另一方面,理解并满足用户需求又是这些算法所要达成的最终目标,这两者之间的有着天然的隔阂。为了打破这个隔阂,让搜索、推荐算法更好地认知用户的需求,我们提出建设大规模电商认知图谱(E-commerce ConceptNet),将用户需求显式地表达成图中的节点(称为E-commerce Concept),并将这些需求点和电商领域内的商品、类目,电商外部的通用领域知识等关联起来,为商品认知、用户认知和知识认知提供统一的数据基础,并为下游搜索推荐算法提供新的优化思路和更多的可能性。什么是e-commerce concept?前面提到,我们将用户需求称为“e-commerce concept”: 一个有商品需求的概念,一般情况下以一个符合常识,语义完整,语序通顺的短语表示。例如:“连衣裙”、“儿童防走失”、“烧烤必备”、“宝宝保暖”、“波西米亚连衣裙”、“春节庆祝”等。这些concept需要满足如下的基本原则:如上所示,右边的短语均违背了电商概念的基本原则,所以在实际挖掘过程中都是会被过滤掉的。进一步,我们将concept分为了三大类:购物场景(shopping scenario):表示一类非特定品类的用户需求,场景感较强,如“儿童防走失”、“春节送礼”等。泛品类(extensive category):表示一类有特定品类的用户需求,可以是不加修饰的纯净品类,如“连衣裙”、“水果”等,也可以是有属性限制的品类,如“韩版波点连衣裙”、“儿童羽毛球拍”等。通用概念(general concept):表示一类通用的概念,可以和电商外部的开放领域知识相关联,如“防晒”、“烧烤”、“老人”等。E-commerce concept从哪里来?在明确了定义和基本原则之后,我们需要挖掘大量的concept用以覆盖各式各样的用户需求。目前,我们认为用户在使用淘宝或天猫搜索时输入的搜索词(query)和商品的标题(title)是concept挖掘可以利用的最大来源。而我们的工作主要是要将满足我们上述原则的concept短语,从充满噪音的query、title中挖掘出来,这一步称为“Concept Mining”。Concept Mining主要分为两步,一个是候选生成(Candidate Generation),另一个是概念正确性判断(Concept Classification)。总体流程如下:其中,候选的生成分为两块,一块是使用AutoPhrase按照字粒度从句子中切分出来的短语信息,一块是通过序列模板抽取器(Sequential Pattern Extractor)做频繁序列挖掘后的模板信息,结合2-gram的统计语言模型,得到concept候选。在得到候选后,我们会利用一个判别模型来融合语言模型embedding,concept的序列信息,以及规则前后缀,pv统计等特征,判断concept是否是符合要求的。Candidate Generation我们首先通过pattern抽取器从现有的正负concept中提取pattern并计算权重,然后通过这些pattern,并结合三个窗口内的统计语言模型,进行候选的剪枝,最后生成的候选基本都是符合语序,满足基本常识的。Concept Classification我们一方面结合一些简单的规则进行特征抽取,另一方面,利用现有的序列特征训练Wide&Deep model,来进行concept的合理性判断。在初始数据的处理方面,由于我们大部分的concept都是短文本,而query和title中大部分的term序列不符合正常的语序,我们还利用长文本的parsing infomation进行候选抽取和截断,训练了ELMo作为基础的语言模型,并在同样长度的gram内调整语序,来得到最佳的序列信息再给判别模型。Ontology在明确了e-commerce concept的定义并挖掘出了大量的concept后,我们会疑惑,concept作为一个词(phrase),除了name之外,没有分类(domain),没有描述(description),也没有属性(attributes),怎么叫”图谱“呢?这么少的信息量如何能在下游应用中起到作用呢?concept要成为图中的节点,那我们的图到底是什么呢?为了更好地理解e-commerce concept,同时和外部知识图谱对齐,引入更多的通用知识,我们定义了一套电商认知图谱的本体(Ontology),用以描述实体、概念的属性和其之间的关系。实体表示客观世界存在的具体实例,例如,歌手刘德华为一个具体的实例。概念表示客观世界中的宽泛概念,例如,娱乐明星为一个泛指的概念。分类体系与属性关系定义(Schema),包括定义实体和概念的类别,以及实体和概念具体的属性与属性值。例如,在分类体系中,歌手刘德华属于人物→娱乐人物→歌手,属性包含出生日期,代表作等。在这里,我们参考Schema.org、cnSchema.org中对客观事物进行描述的结构,建立了以事物类(Thing)为根节点的电商知识图谱底层本体分类体系。在事物类的子类中,包括“动作”、“创作品”、“活动”、“无形物”、“品类”、“医疗实体”、“机构”、“人物”、“地点”共9大类。每一个子类又有其自己的子类,每一个子类将继承父类的所有属性和关系。具体结构如下图所示:本体分类体系,其中括号内内容为类别对应的中文名和英文缩写在这里,中心白色节点为事物类,是所有类的根节点。环绕在事物类周围的9个节点是事物类的直接子类。其中每一个类别又有自己的节点。在该图中,以无形物类为例,受众类是无形物类的子节点,而受众:动物类、受众:身体部位类、受众:人群类、受众:植物类是受众类的子节点。在通过结构化、半结构化、非结构化数据进行知识获取时,数据按照该分类体系进行录入。如前文所述,电商认知图谱的终极目标是刻画用户需求,因此,在本体中我们定义了多个电商专用类来对电商环境下的客观世界进行建模:Brand (品牌) Category (品类):品类是顾客在购买决策中所涉及的最后一级商品分类,由该分类可以关联到品牌,并且在该分类上可以完成相应的购买选择。品类中的实例是我们进行本体构建过程中重点挖掘的内容。Audience (受众):受众是商品直接对应的购物人群或种群,是电商场景下一个非常重要的分类。受众类下包括四个子类:受众:动物、受众:身体部位、受众:人群、受众:植物。Style (风格):对于一件商品,一定会有其特有的风格来吸引购买的人群,风格类主要对其进行描述。风格类下包括六个子类:文学风格、音乐舞蹈风格、气味风格、触觉风格、口味风格、以及视觉风格。Function (功能):对商品进行功能的具体描述,可以精准的定位商品,将商品和需求直接联系起来。功能类下包括四个子类:美妆功能、服饰功能、保健功能、家居功能。Material(材质):所谓材质,简单的说就是物体看起来是什么质地。通过材质对商品进行描述,可以使商品更加具体化。属性是词汇固有的属性,比如“别名”、“描述”等;关系是本体词汇之间存在的客观联系,如Person类中实例的“出生地”将链接到另外一个Place类的实例中。在本体的分类体系中,每个类别都有其特有的属性和关系,子类将继承父类所有的属性和关系。在这里,我们以事物类和品类类为例,介绍属性和关系,具体如下图所示:事物类:在该类别中,我们定义了“别名”、“描述”、“图片”、“名称”共四个属性和关系。“别名”实际上是当前词汇的一个同义词,是一个属性;“描述”是对当前事物特点的一种描述;“图片”可以连接到另外一个“图片对象”,实际上是两个事物之间的关系;“名称”是当前事物的标准的名字。品类类:品类类是事物类的直接子类,将直接继承事物类的所有属性和关系。与此同时,品类类含有自己特有的属性“品类类型”。本体分类体系下所有的类、子类均有其特有的属性和关系,在对本体中的每个类别进行建模时,我们定义了140+个属性和关系。在进行本体词汇构建时,我们充分调动集团内各大BU的优质结构化资源,来源包括淘系、优酷、飞猪、神马等等,对多来源的结构化、半结构化数据进行知识的整理与融合。具体的,如果将多来源结构化数据看成不同来源的知识体系,获取和融合就包括了本体和实例的匹配(Ontology/Enity Matching)和知识融合(Knowledge Fusion)。我们采用了基于文本特征的匹配方法,对多来源的数据进行了批量的合并。我们定义的知识融合任务是:在同一个类别下,含有相同意义的词汇需要合并为一个id,其中最为常见的词汇作为主键,其他同义词汇作为别名。如“老汉”与“老朽”是同义词,在同一个id下,“名称”属性内容为“老汉”,“别名”属性内容为“老朽”。在匹配的基础上,通过冲突检测,Truth Discovery等技术将知识进行一致性的合并消解。对于冲突,处理方法包括忽略,避免和消解。常见的消解方法包括:Voting、Quality-based、relation-based的方法。我们采用的是Quality-based的方法,对single-valued attribute进行消解。最终通过整理和融合结构化数据,获取了百万级的实体和Concept数据。自然文本以非结构化的形式存在,包含了大量丰富的语义关系,描述了客观世界里面实体,概念以及相互之间的关系。因此,对文本的理解也成为了获取实体和概念信息的重要来源。实体和概念作为图谱的关键元素,对其在文本中的识别成为了知识获取的重要技术。其中命名实体识别(NER)将文本中提及的实体进行划分并归类,可以从海量语句中挖掘指定类别的实体。我们采用基于远程监督(Distant Supervision)的序列标注模型,标注的类型标签包含上文提到的事件,功能,对象,时间,空间,品类,风格等多个大类。至此,我们搭建了一个为电商设计的ontology体系,并扩充了大量的实体、概念、属性和关系,也可以将其看做一个普通的电商知识图谱。从知识图谱到认知图谱上文介绍的认知图谱本体结构(Ontology),包含了比较完整的分类法以及相应的schema,并融合了大量的外部、电商实体、概念和属性关系,是一个比较初级的电商知识图谱,其目的是为了结构化我们挖掘得到的大规模的e-commerce concept,将这些concept链接到图中成为节点,让“知识图谱”真正迈向了“认知图谱”。这一步叫做Concept Tagging。理想情况下,我们希望concept经过分词后,每一个词单元都能够链接到本体词汇库的词汇上,从而获得相应的知识体系,但是由于本体不一定能覆盖全部的concept词汇,导致concept只有部分能够被链接,属性关系并不完整。其次,本体中存在一词多义的问题,相同的词汇具有不同的类型,因此需要进行词义消歧。而concept通常是短文本,上下文十分有限,常规的序列标注模型并不能取得可观的性能,并且目前的本体分类体系是树形结构,存在一个词汇分布于同一个大类,不同小类中。例如,“丹麦”这个词的类型有“空间→国家”以及“空间→行政区”,这也为词义消歧带来了难度。我们的目标是准确地将concept链接到本体词汇库的词汇上,输入是concept列表以及本体库,输出是对应的词汇及类型:针对上述难点,算法的整体流程图如下:下面我们将针对图中的模块具体说明:1) 基于词典的最大正向匹配及前缀匹配:给定一个concept,算法首先使用最小粒度分词,将concept切分成词,然后使用最大正向匹配算法,从左到右将分词后的concept的几个连续词与本体库的词典匹配,如果匹配上则返回本体词汇及类型(ID)。在这个过程中,存在匹配上的词在本体分类体系中的不同位置中,即一词多义的问题,在这里,我们将所有的可能候选返回,以供后续消歧处理。值得一提的是,我们在使用词表的时候,并没有使用全部的词表,其中的品牌表和IP表(名人、作品、电视电影等)非常庞大,歧义词很多。例如,我们平时十分常见的高频词也会是一个IP词,但大多数情况下并不表示一个IP。因此我们在最大正向匹配的过程中去除了这一部分数据,而是增加了一个前缀匹配的模块,将未标识的前缀与品牌表和IP中的人名表进行匹配,能够进一步的提升覆盖度。2)词义消歧: 与常规的消歧方法不同,concept通常由短文本组成,上下文能够提供的信息十分有限。因此我们选用了序列标注模型来学习词汇类型的组合,例如:“对象”+“风格”+“品类”等等。由于考虑到不同行业下,词汇的类型不同,例如,“拼接”这个词,在“服饰”领域下,“拼接针织连衣裙”中的“拼接”类型为“风格”,而在“家具灯具”领域中,“拼接水管”的类型为“功能”,因此我们使用了attention机制来学习领域相关的信息。序列标注的模型如下图所示:得到序列标注的模型输出后,再根据单词的sense候选,输出最终的tagging结果。后续会尝试将序列标注作为特征,再结合concept的其他特征,使用分类模型来对候选sense打分排序。3) 细粒度的tagging :在存在问题的讨论中,我们提到了存在一个词汇属于相同大类不同小类的情况。通常序列标注模型的标签类别只有十几种,而目前我们的本体库分类体系中包含几十种甚至上百种类型,传统的序列标注模型并不能够解决这个问题。因此,我们需要更细粒度的序列标注模型来进一步消歧。4) 对齐长文本召回:经过词表匹配与词义消歧后,由于现有本体库并没有涵盖concept中所有的词汇,因此我们需要tagging未标识的term,并识别出相应的类型,可以回流本体库。一种可行的方式就是利用大量电商领域的长文本句子,将concept远程对齐到长文本来进行序列标注,从而将未标识的term召回。认知图谱中的边知识图谱的关系是机器能够理解知识的关键。关系类型由头尾节点类型决定,节点可以是vocabulary、concept、entity的任意一种。目前我们定义了19中关系类型,并用三元组表示所有节点之间的关系。这些关系包括“is_related_to(相关)”、“isA(是一种)“、”has_instance(有实例)“、”is_part_of(是一部分)“等。 这里重点介绍对电商场景用途最大的两种关系:concept-isA-concept例子:波西米亚连衣裙 isA 连衣裙。电商需求大部分是品类需求,对品类需求的语义表达至关重要。isA关系使得我们的concept从偏平的结构变为图的结构,对机器理解语义非常重要。 通常,isA关系的构建包含两个步骤:在大规模文本语料中抽取isA关系,这里主要包括模板匹配(pattern-based)和基于向量表示的isA关系预测(distributional)在第一步抽取得到的isA关系集合中构建层次结构,例如去重,消歧,去环等清洗工作以及补充更细粒度的isA关系。而在电商认知图谱构建的特殊场景中,isA关系构建的主要难点在于:电商是一个垂直领域,尤其在淘宝这样一个"只有你想不到,没有淘宝买不到"的平台,涉及的品类五花八门,有不少品类词相对冷门但又十分重要。电商相关的文本语料稀缺,品类词在语料中的共现非常稀疏,给抽取带来了极大的难度。针对这些难点,我们正在着手设计一套人工+算法不断迭代优化的active learning流程,希望为后续的concept理解和推理应用提供可靠的支持。concept-is_related_to-item在现有电商环境下,构建概念和商品之间的is_related_to关系也会面临诸多挑战:概念过短、商品标题堆叠、无关词语、商品属性错误、商品图文不符等,这些会造成匹配错误或者带来歧义。针对上述问题我们采用的整体方案流程如下:首先使用文本匹配/i2i/语义模型的方式进行将concept与item (title、描述)进行语义匹配,然后会根据concept到category分数进行校准,再经过消歧后,最终会根据概念间关系进行商品的合并。下图是深度语义匹配模型的一个示意:完整的大图讲到这里,电商认知图谱的大图也呼之欲出了:如上图所示,完整的认知图谱包含以下几个部分:Concept:表达用户需求的最重要的语义节点。Ontology:一个为电商设计的知识图谱的分类体系、schema,通过与concept的连接形成最终的认知图谱,可以融合外部知识图谱数据,引入电商中很难直接挖掘到的常识。Relation:我们定义了十几类关系,用于描述不同节点之间的语义,是机器理解语义的关键。Item:基于图谱构建大规模的concept、vocabulary和relation,可以更加精确的理解商品。User:基于图谱构建大规模的concept、vocabulary和item attributes,可以更加精准的理解用户需求、推理用户需求。应用显式应用电商认知图谱现已在淘宝搜索推荐等多个产品落地应用,主要的产品形式是以concept为载体的主题卡片,如首页猜你喜欢瀑布流中的”购物百科“:宝贝详情页中的场景推荐:隐式应用通过电商认知图谱提供的以concept为核心的点、边关系数据,为搜索和推荐算法增加了新的信息粒度和信息结构,会带来更大的想象空间,可以更好地满足多样的用户需求。同时,很多新的基于认知图谱应用的课题我们还在进行中,如:可解释推荐Knowledge Graph Embedding推理式推荐总结和展望认知图谱的建设需要耗费大量的资源,涉及领域广泛,内容繁杂,离不开算法、工程、运营、以及大量众包/外包资源的帮助。本文只是浅显地总结了从算法工程师的角度来讲述的认知图谱构建,很多模块仍在探索和优化中。我们相信,以更好地认知用户需求为目标的电商认知图谱,将助力搜索推荐等从基于行为的方式迈向基于行为与语义融合的认知智能时代,将是平台生态稳定和日益进步的重要基础。关于我们阿里巴巴集团搜索推荐事业部认知图谱团队,旨在打造全球最大的中文电商知识图谱,支持包括淘宝、天猫优酷乃至海外电商在内整个阿里集团的推荐与搜索业务,每天服务上亿用户。电商"认知"图谱,从电商场景下的用户需求出发,不局限于传统的商品图谱,而是一个连接商品,用户,购物需求,以及各类开放领域知识、常识的大规模语义网络。本文作者:华仔阅读原文本文来自云栖社区合作伙伴“ 阿里技术”,如需转载请联系原作者。

April 9, 2019 · 1 min · jiezi

2019五个最棒的机器学习课程

摘要: 爱学习的朋友们,你们的福利来了!2019五个最棒的机器学习课程!!凭借强大的统计学基础,机器学习正在成为最有趣,节奏最快的计算机科学领域之一,目前已经有无穷无尽的行业和应用正在使用机器学习使它们更高效和智能。聊天机器人、垃圾邮件过滤、广告投放、搜索引擎和欺诈检测是机器学习模型正在实际应用于日常生活的几个例子。机器学习到底是什么呢?我认为机器学习是让我们找到模式并为人类无法做的事情创建数学模型。机器学习课程与包含探索性数据分析,统计,通信和可视化技术等主题的数据科学课程不同,它更侧重于教授机器学习算法,如何以数学方式工作,以及如何在编程语言中使用它们。以下是今年五大机器学习课程的简要回顾。最好的五个机器学习课程:1. 机器学习-Coursera2. 深度学习专项课程-Coursera3. 使用Python进行机器学习-Coursera4. 高级机器学习专项课程-Coursera5. 机器学习-EdX什么是一个非常好的机器学习课程?标准:上面的每门课程都遵循以下标准:严格关注机器学习;使用免费的开源编程语言,即Python,R或Octave;这些开源的语言都有很多免费的开源库;包含练习和实践经验的编程任务;解释算法如何以数学方式工作;有吸引力的讲师和有趣的讲座;有了这个标准,很多课程都会被淘汰,为了让自己沉浸其中并尽可能快速全面地学习ML,我相信除了在线学习之外,你还应该寻找各种书籍。以下是两本对我的学习经历产生重大影响的书籍。两本优秀的书籍伴侣除了参加下面的任何视频课程,如果你对机器学习还不熟悉,你应该考虑阅读以下书籍:统计学习简介,可在线免费获取。本书提供了令人难以置信的清晰直接的解释和示例,以提高你对许多基本机器学习技术的整体数学直觉。而去更多地是关于事物的理论方面,但它确实包含许多使用R编程语言的练习和例子。使用Scikit-Learn和TensorFlow进行动手机器学习,可通过Safari订阅获得。这是对前一本书的一个很好的补充,因为本文主要关注使用Python进行机器学习的应用。本书将强化你的编程技巧,并向你展示如何立即将机器学习应用于项目。现在,让我们来看看课程描述和评论。1:机器学习 - Coursera此课程的创作者是Andrew Ng,一个斯坦福大学教授,谷歌大脑、Coursera的创始人之一。本课程使用开源编程语言Octave而不是Python或R进行教学。对于某些人来说,这可能是不太友好,但如果你是一个完整的初学者,Octave实际上是一种最简单学习ML基础知识的方法。总的来说,课程材料非常全面,并且由Ng直观地表达,该课程完整地解释了理解每个算法所需的所有数学,包括一些微积分解释和线性代数的复习,课程相当独立,但事先对线性代数的一些了解肯定会有所帮助。提供者:Andrew Ng,斯坦福大学费用:免费审核,证书79美元课程结构:单变量的线性回归回顾线性代数多变量的线性回归Octave/Matlab教程Logistic回归正则化神经网络:表示神经网络:学习应用机器学习的建议机器学习系统设计支持向量机降维异常检测推荐系统大规模机器学习应用示例:Photo OCR如果你可以承诺完成整个课程,你将在大约四个月内掌握机器学习的基础知识。之后,你可以轻松地进入更高级或专业的主题,如深度学习,ML工程或任何其他引起你兴趣的话题。毫无疑问,这是新手开始的最佳课程。2:深度学习专项课程-Coursera同样由Andrew Ng教授,这是一个更高级的课程系列,适合任何有兴趣学习神经网络和深度学习的人。每门课程的作业和讲座都使用Python编程语言,并将TensorFlow库用于神经网络。这第一个机器学习课程的很好的后续,因为你现在将接触使用Python进行机器学习。提供者:Andrew Ng,deeplearning.ai费用:免费审核,证书每月49美元课程结构:1. 神经网络与深度学习深度学习简介神经网络基础知识浅层神经网络深度神经网络2. 改进神经网络:超参数调整,正则化和优化深度学习的实践方面优化算法超参数调整,批量标准化和编程框架3. 构建机器学习项目ML策略(1)ML策略(2)4. 卷积神经网络卷积神经网络的基础深度卷积模型:案例研究物体检测特殊应用:人脸识别和神经风格转移5. 序列模型递归神经网络自然语言处理和Word嵌入序列模型和注意机制为了理解本课程中介绍的算法,你应该熟悉线性代数和机器学习。如果你需要一些建议来获取所需的数学,请参阅本文末尾的学习指南。3:使用Python进行机器学习-Coursera这是另一个初学者课程,这个课程仅关注最基本的机器学习算法。本课程使用Python教学,并且对数学的要求不是很高。通过每个模块,你将有机会使用交互式Jupyter笔记本来完成你刚学过的新概念。每个笔记本都增强了你的知识,并为你提供了在实际数据上使用算法的具体说明。提供者:IBM价格:免费审核,证书每月39美元课程结构:机器学习简介回归分类聚类推荐系统项目本课程最好的一点是为每种算法提供实用的建议。当引入新算法时,老师会向你提供它的工作原理,它的优点和缺点,以及你应该使用它的哪种情况。这些点经常被排除在其他课程之外,这些信息对于新学员来说非常重要。4:高级机器学习专项课程-Coursera这是另一个高级系列课程,涉及了非常多的网络类型。如果你有兴趣尽可能多地使用机器学习技术,这个课程很关键。本课程的教学非常棒,由于其先进性,你需要学习更多的数学。本课程涵盖的大部分内容对许多机器学习项目至关重要。提供者:国立研究大学高等经济学院成本:免费审核,每月49美元的证书课程:1. 深度学习简介优化简介神经网络简介深度学习图像无监督表示学习Dee学习序列项目2. 如何赢得数据科学竞赛:向顶级Kagglers学习介绍和回顾关于模型的特征处理和生成最终项目描述探索性数据分析验证数据泄漏度量标准优化高级特征工程-1超参数优化高级特征工程-2Ensembling项目3. 机器学习的贝叶斯方法贝叶斯方法和共轭先验的介绍期望最大化算法变分推断和潜在Dirichlet分配(LDA)马尔可夫链蒙特卡洛变分自动编码器高斯过程和贝叶斯优化项目4. 实践强化学习简介:我为什么要关心?RL的核心:动态编程无模型方法基于近似值的方法基于政策的方法探索5. 计算机视觉中的深度学习图像处理和计算机视觉入门视觉识别的卷积特征物体检测对象跟踪和动作识别图像分割与合成6. 自然语言处理简介和文本分类语言建模和序列标记语义的向量空间模型序列到序列任务对话系统7. 通过机器学习解决大型强子对撞机挑战数据科学家的粒子物理入门粒子识别寻找稀有衰变中的新物理学在新的CERN实验中用机器学习搜索暗物质提示探测器优化完成这一系列课程大约需要8到10个月,所以如果你从今天开始,在不到一年的时间里,你将学到大量的机器学习算法,并能够开始处理更多尖端的应用程序。在这几个月中,你还将创建几个真正的项目,使计算机学习如何阅读,查看和播放。这些项目将成为你投资组合的理想选择,并将使你的GitHub对任何感兴趣的雇主都非常活跃。5:机器学习-EdX这是一个高级课程,具有文中任何其他课程的最高数学先决条件。你需要非常牢固地掌握线性代数、微积分、概率和编程。该课程在Python或Octave中都有编程作业,但该课程不教授任何一种语言。与其他课程的不同之处是对机器学习的概率方法的讲解。如果你有兴趣阅读教科书,例如机器学习:概率视角,这是硕士课程中最流行的数据科学书籍之一。提供者:哥伦比亚大学费用:免费审核,证书300美元课程结构:最大似然估计,线性回归,最小二乘法岭回归,偏差方差,贝叶斯规则,最大后验推断最近邻分类,贝叶斯分类器,线性分类器,感知器Logistic回归,Laplace逼近,核方法,高斯过程最大边距,支持向量机(SVM),树木,随机森林,提升聚类,K均值,EM算法,缺失数据高斯混合,矩阵分解非负矩阵分解,潜在因子模型,PCA和变化马尔可夫模型,隐马尔可夫模型连续状态空间模型,关联分析模型选择,后续步骤课程中的许多主题都包含在针对初学者的其他课程中,但数学并未在这里淡化。如果你已经学习了这些技术,有兴趣深入研究数学,并希望从事实际推导出某些算法的编程作业,那么请学习本课程。学习指南这里是你学习机器学习之旅的快速指南,首先,我们将介绍大多数机器学习课程的先决条件。课程先决条件高级的课程在开始之前需要以下知识:线性代数概率微积分程序设计这些是能够理解机器学习如何在幕后工作的简单组件。许多初级课程通常要求至少一些编程和熟悉线性代数基础知识,例如向量,矩阵。本文的第一个课程,Andrew Ng的机器学习,包含了你需要的大部分数学的复习,但是如果你以前没有学过线性代数,那么同时学习机器学习和线性代数可能会很困难。另外,我建议学习Python,因为大多数优秀的ML课程都使用Python。如果你学习使用Octave的Andrew Ng的机器学习课程,你应该在课程期间或之后学习Python,因为你最终需要它。另外,另一个很棒的Python资源是dataquest.io,它在他们的交互式浏览器环境中有一堆免费的Python课程。在学习了必备必需品之后,你就可以开始真正理解算法的工作原理了。基本算法在机器学习中有一套基本的算法,每个人都应该熟悉并具有使用经验。这些是:线性回归Logistic回归k-Means聚类k-最近邻居支持向量机(SVM)决策树随机森林朴素贝叶斯这些是必需品,上面列出的课程基本上包含所有这些。在开展新项目时,了解这些技术如何工作以及何时使用它们将非常重要。在基础知识之后,一些更先进的学习技巧将是:集成学习Boosting降维强化学习神经网络与深度学习这只是一个开始,但这些算法通常是你在最有趣的机器学习解决方案中看到的,它们是你工具箱的有效补充。就像基本技术一样,你学习的每一个新工具都应该养成一个习惯,立即将它应用到项目中,以巩固你的理解,并在需要复习时有所回头。解决一个项目在线学习机器学习具有挑战性并且非常有益。重要的是要记住,只是观看视频和参加测验并不意味着你真的在学习这些材料。如果你正在进行的项目使用不同的数据并且目标与课程本身不同,你将学到更多。一旦你开始学习基础知识,你应该寻找可以应用这些新技能的有趣数据。上面的课程将为你提供何时应用某些算法的直觉,因此立即将它们应用于你自己的项目中是一种很好的做法。通过反复试验,探索和反馈,你将发现如何尝试不同的技术,如何衡量结果,以及如何分类或预测。有关要采用何种ML项目的一些灵感,请参阅此示例列表。解决项目可以让你更好地理解机器学习环境,当你深入了解深度学习等更高级的概念时,实际上可以使用无限数量的技术和方法来理解和使用。阅读新研究机器学习是一个快速发展的领域,每天都有新的技术和应用出现。一旦你通过基础知识,你应该有能力通过一些关于你感兴趣的主题的研究论文。有几个网站可以获得符合你标准的新论文的通知。Google学术搜索始终是一个好的开始,输入“机器学习”和“深度学习”等关键词,或者你感兴趣的任何其他内容,点击左侧的“创建提醒”链接即可收到电子邮件。让它成为每周习惯,阅读这些警报,扫描文件,看看它们是否值得阅读,然后承诺了解正在发生的事情。如果它与你正在处理的项目有关,请查看你是否可以将这些技术应用于你自己的问题。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 15, 2019 · 1 min · jiezi

Java 序列化反序列化对比

Java 序列化工具对比,对比以下序列化工具对数据的存储大小以及计算耗时:JDK 1.8Hessian 4.0.60Kryo 4.0.2Protostuff:1.6.0版本依赖<dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.2</version></dependency><dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.60</version></dependency><dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-core</artifactId> <version>1.6.0</version></dependency><dependency> <groupId>io.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> <version>1.6.0</version></dependency>测试代码对 100000 个 User 进行序列化以及反序列化操作,输出操作时间以及各个工具序列化后累计的数据的长度:/** * 序列化器对比 * Created by Captain on 06/03/2019. /public class SerializerUtil { private static Kryo kryo = new Kryo(); /* * JDK 序列化 / public static byte[] serializable(Object obj) { if (obj == null) { return null; } if ( obj instanceof String ) { return ((String) obj).getBytes(); } ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(obj); byte[] bytes = baos.toByteArray(); return bytes; } catch (Exception e) { } return null; } /* * JDK 反序列化 / public static Object unserializable(byte[] bytes){ ByteArrayInputStream bais = null; try { // 反序列化 bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } catch (Exception e) { e.printStackTrace(); } return null; } /* * kryo 反序列化 / public static Object unserializableKryo(byte[] bytes){ if (bytes == null) { return null; } try { // 反序列化 Input input = new Input(new ByteArrayInputStream(bytes)); Object obj = kryo.readClassAndObject(input); input.close(); return obj; } catch (Exception e) { e.printStackTrace(); } return null; } /* * kryo 序列化 / public static byte[] serializableKryo(Object obj){ if (obj == null) { return null; } if ( obj instanceof String ) { return ((String) obj).getBytes(); } try { // 序列化 ByteArrayOutputStream baos = new ByteArrayOutputStream(); Output output = new Output(baos); kryo.writeClassAndObject(output, obj); output.flush(); output.close(); return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } return null; } /* * hessian 序列化 / public static byte[] serializableHessian(Object obj){ ByteArrayOutputStream byteArrayOutputStream = null; HessianOutput hessianOutput = null; try { byteArrayOutputStream = new ByteArrayOutputStream(); hessianOutput = new HessianOutput(byteArrayOutputStream); hessianOutput.writeObject(obj); return byteArrayOutputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } finally { try { byteArrayOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { hessianOutput.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } /* * hessian 反序列化 / public static Object unserializableHessian(byte[] bytes){ ByteArrayInputStream byteArrayInputStream = null; HessianInput hessianInput = null; try { byteArrayInputStream = new ByteArrayInputStream(bytes); // Hessian的反序列化读取对象 hessianInput = new HessianInput(byteArrayInputStream); return hessianInput.readObject(); } catch (IOException e) { e.printStackTrace(); } finally { try { byteArrayInputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { hessianInput.close(); } catch (Exception e) { e.printStackTrace(); } } return null; } /* * protostuff 序列化 / public static <T> byte[] serializableProtostuff(T obj){ try { RuntimeSchema schema = RuntimeSchema.createFrom(obj.getClass()); return ProtostuffIOUtil.toByteArray(obj, schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE)); } catch (Exception e){ e.printStackTrace(); return null; } } /* * protostuff 反序列化 */ public static Object unserializableProtostuff(byte[] bytes, Class clazz){ RuntimeSchema schema = RuntimeSchema.createFrom(clazz); Object obj = schema.newMessage(); ProtostuffIOUtil.mergeFrom(bytes, obj, schema); return obj; } public static void main(String[] args) { final int OBJECT_COUNT = 100000; User user = new User(); long sum = 0; long start = System.currentTimeMillis(); for ( int i = 0 ; i <= OBJECT_COUNT ; i++ ){ user.setId(i); user.setName(“Captain” + i); user.setAge(18 + i); byte[] bytes = serializable(user); sum += bytes.length; unserializable(bytes); } System.out.println(“JDK 1.8 序列化反序列化 -> 耗时 : " + (System.currentTimeMillis() - start) + " , 长度 : " + sum); long sum2 = 0; long start2 = System.currentTimeMillis(); for ( int i = 0 ; i <= OBJECT_COUNT ; i++ ){ user.setId(i); user.setName(“Captain” + i); user.setAge(18 + i); byte[] bytes = serializableKryo(user); sum2 += bytes.length; unserializableKryo(bytes); } System.out.println(“Kryo 4.0.2 序列化反序列化 -> 耗时 : " + (System.currentTimeMillis() - start2) + " , 长度 : " + sum2); long sum3 = 0; long start3 = System.currentTimeMillis(); for ( int i = 0 ; i <= OBJECT_COUNT ; i++ ){ user.setId(i); user.setName(“Captain” + i); user.setAge(18 + i); byte[] bytes = serializableHessian(user); sum3 += bytes.length; unserializableHessian(bytes); } System.out.println(“Hessian 4.0.60 序列化反序列化 -> 耗时 : " + (System.currentTimeMillis() - start3) + " , 长度 : " + sum3); long sum4 = 0; long start4 = System.currentTimeMillis(); for ( int i = 0 ; i <= OBJECT_COUNT ; i++ ){ user.setId(i); user.setName(“Captain” + i); user.setAge(18 + i); byte[] bytes = serializableProtostuff(user); sum4 += bytes.length; unserializableProtostuff(bytes, User.class); } System.out.println(“Protostuff 1.6.0 序列化反序列化 -> 耗时 : " + (System.currentTimeMillis() - start4) + " , 长度 : " + sum4); }}测试结果JDK 1.8 序列化反序列化 -> 耗时 : 2970 , 长度 : 21989111Kryo 4.0.2 序列化反序列化 -> 耗时 : 451 , 长度 : 5472470Hessian 4.0.60 序列化反序列化 -> 耗时 : 1397 , 长度 : 7888970Protostuff 1.6.0 序列化反序列化 -> 耗时 : 706 , 长度 : 2155925工具序列化后数据长度耗时msJDK 1.8219891112970Kryo 4.0.25472470451Hessian 4.0.6078889701397Protostuff 1.6.02155925706初步结论耗时:JDK > Hessian > Protostuff > Kryo数据长度:JDK > Hessian > Kryo > Protostuff从测试结果来看,序列化工具 Protostuff 以及 Kryo 在耗时及存储上看均优于 JDK 以及 Hessian,相应的可以提供更高的计算性能以及更少的存储空间,选型过程中应当优先考虑。其次,衡量性能与存储,可根据场景选取 Protostuff 或 Kryo。 ...

March 7, 2019 · 4 min · jiezi

图(关系网络)数据分析及阿里应用

摘要:2019年1月18日,由阿里巴巴MaxCompute开发者社区和阿里云栖社区联合主办的“阿里云栖开发者沙龙大数据技术专场”走近北京联合大学,本次技术沙龙上,阿里巴巴资深技术专家钱正平为大家分享了大数据技术背景下图数据的应用前景,以及阿里巴巴在图数据的建模、查询和系统优化等方面做出的初步探索。以下内容根据演讲视频以及PPT整理而成。一、什么是图数据?下面的关系网络展示了一个点和边构成的数据模型,点表示实体,边表示两个实体间的关系。关系网络极具灵活性,能够在统一视图里展示异构信息,其中的边可能来自不同表。比如,下图中的边表示了两个明星间的关系,可能由若干张表通过join操作形成。如今,机器学习的数据分析pipeline可应用于各行各业各个门类的数据,来帮助企业更好地决策。图数据的价值在于它能够显式地表达出数据间的复杂关联结构,以辅助机器学习的数据分析过程,帮助机器学习算法更好地挖掘出数据背后的结构特征,提供更精准更可靠的决策支持。图数据的这种能力对一些领域格外重要。Google早期使用的搜索算法pageRank就利用了图数据的这种能力,它利用网页间的相互链接信息来决定网页的重要程度。具体来说,被越多网页链接的网页越重要,被越重要的网页链接的网页也越重要。Google利用图数据重新定义了搜索,取得了非常卓越的成功。图数据对阿里巴巴同样意义重大。以阿里巴巴的应用生态为例,天猫包含了用户的在线交易信息,高德地图包含了用户的出行信息,优酷土豆等包含了用户的观影信息,以人为维度将这些信息关联起来可以得到关于某用户的完整信息,以理解用户偏好。图数据模型能够将许多分散的图场景整合起来,形成一个庞大的图结构。阿里巴巴的图结构包含几十亿个点,成百上千亿条边,同时阿里应用巨大的日交易量也使得图结构千变万化,这些都为图数据的计算带来了严峻的挑战。图应用与具体场景相关,阿里巴巴针对不同的应用场景设计了不同的图数据处理算法。以一个很长的数字序列为例,对其进行数据分析的第一步是“看”,即观察该序列可能存在的特征,此外,可能使用特征统计分析该序列包含某数字的个数。更进一步,模式匹配可以探寻该序列中可能存在的模式子串。最后,机器学习算法比如神经网络能帮助挖掘数字序列背后的规律。对该序列进行数据分析能够帮助在线预测相关信息,比如数字序列的下一位数字等。图数据分析方法能帮助洞察图数据,阿里巴巴在图数据方面的应用包括五类。第一类是“看”,下图展示了经敏感信息处理后的阿里巴巴内部使用的可视化平台。真实环境中,商业问题可能存在多方面因素,研判业务问题非常困难。将图结构应用于可视化平台能够整合多维度数据,动态地将多维度数据关联起来,以帮助用户更好地决策。第二类图数据应用是图算法。比如,pageRank算法利用图结构计算每个节点的权重值、连通分支等。连通分支可用于计算具有不同ID的实体,比如手机号、e-mail以及浏览器cookie等是否同属于一个自然人,从而提高企业的广告投放准确率。举例来说,淘宝用户使用浏览器购买商品后,浏览器将记录用户的cookie,下一次用户浏览新浪时,新浪可以根据该cookie获取用户的淘宝ID,从而获取用户的偏好以投放相关广告。连通分支将用户在不同应用的相关信息关联起来,从而更好地了解用户偏好,实现个性化应用。第三类图数据应用是模式,比如基于子图模式的异常检测。图结构将不同表数据关联起来,从而暴露出日志信息无法表露出来的问题。比如,左图揭示了各个用户转账行为间的关联,第二幅图揭示了三个用户与四个商品间频繁的交易模式,这些信息仅依赖系统文本文件中的日志都无法获得。据报道,仅有百分之一的安全漏洞问题能通过日志分析检测出来,日志的单规则信息是不全面的,利用图结构信息关联不同数据非常必要。左图展示了简单的淘宝刷单模式,刷单人为商家刷单后,商家通过支付宝即时支付刷单费用,形成了图结构中的“环”,阿里巴巴通过检测“环”以检测简单的刷单行为。提供刷单服务的公司,大多运营大量的虚假账号来满足刷单请求,每个虚假账号可能同时为多个商品提供刷单服务。阿里巴巴使用图结构来表示用户与商品间的购买行为,k1个用户在一定较短时间内与v2个商品发生完全购买的行为,意味着k1个用户中可能存在大量虚假账号。图结构增强了系统对用户行为的捕捉能力。第四类图数据应用是机器学习,比如利用基于图的机器学习应用实现淘宝推荐。为了计算某个用户对某个商品的兴趣度,阿里巴巴利用商品的重要属性比如标签等计算商品间的相似度,同时对用户的重要属性建模。也就是说,通过用户对相似商品的感兴趣程度预测用户对当前商品的兴趣度,从而实现商品推荐。这些信息无法单纯依赖某张表得到。比如,某用户喜欢夏季羽绒服,同时喜欢某品牌,单纯依赖表信息的商品推荐不会给该用户推荐相关品牌的冬季羽绒服,而连接了两方面信息的图结构则可能推荐该商品,提高了商品推荐的准确度。图结构信息还有利于解决冷启动及结果可解释性等难题。第五类图数据应用是知识图谱,比如基于知识图谱实现在线推理,提供在线智能服务。左边的例子展示了双11期间淘宝的凑单应用,即为用户推荐凑单商品以帮助用户获得满减折扣。阿里巴巴利用商品相似性图,能够方便地计算商品A的所有相似商品,从而实现相似商品推荐。当然,相似商品往往具有相同功能,而已经购买了某商品的用户很可能不愿意重复购买类似商品。因此,阿里巴巴又引入了随机游走机制,通过在商品相似图中以一定概率随机游走来选择推荐商品,平衡商品的相似性和多样性。应用图结构构建知识图谱的另一个例子是天猫精灵。天猫精灵通过构建多种类型的知识图谱来回答用户提出的各种问题,比如娱乐图谱能够展示电影的导演、演员,以及他们的其他电影作品等信息。“李未央”是某电视剧的角色名,假设用户提问“李未央还演了什么电影”,天猫精灵将通过分词得到“李未央”,知识图谱算法允许从“李未央”出发探究相关演员,从而进一步探究相关电影,这是普通的问答系统无法做到的。相比谷歌、微软等公司基于互联网数据构建知识图谱,阿里巴巴利用自身结构化数据来源的高数据质量优点,能够构建出更优质的图谱以实现在线推理。二、大数据系统趋势与挑战早期,大数据技术采用IOE模式,依赖单点运行的Oracle机器等高成本硬件。2009年,MaxCompute使用更低成本的机器集群来解决相同规模的计算问题,提高软件的容灾能力。2012年,实时风控、大屏、视频分析等应用向大数据技术提出了更高的计算时延要求。如今,更丰富的数据使用场景需求使得机器学习与异构信息网络图技术比如关联分析、MaxGraph等得到了发展。不断演化的需求加速了大数据技术的发展。关联分析背后的逻辑架构依赖于一个从一系列数据源构建得到的图模型(Graph model),数据科学家基于该图模型完成离线的数据挖掘任务,业务操作员基于该图模型实现在线推理、提供在线服务,此外,该图模型还根据系统事件实时更新。总的来说,关联分析需要满足多维度的需求。下图展示了基于图结构的开源解决方案。第一幅图展示了图的遍历,用于查询图中各项内容。第二幅图展示了图算法,包括pageRank等。第三幅图展示了模式匹配,第四幅图展示了机器学习。图结构解决方案的开源化追求可扩展性,以处理大规模数据计算任务。构建图应用要求组合多个系统的能力,比如图数据的存储、离线计算引擎以及在线计算服务器等,构建复杂度和运维难度都极高。MaxGraph产品通过实时或离线方式构建关系数据并存储为图结构,从而利用统一的分布式“瞬时计算”引擎来支持辨别、计算、匹配与机器学习等功能。基于MaxGraph提供的功能,一些上层图应用以及智能应用包括关系网络分析等才得以实现。三、图建模与存储下图展示了一个图模型,由点和边构成,并且允许点和边都携带属性。图建模时需要关注数据间的关联。以“电子邮件通信中的异常检测系统”为例,该系统要求在若干个相互发送e-mail的用户行为中检测风险。最直观的图建模方式是将用户建模成图的点,用户间相互发送的e-mail建模成图的边,但这样建模的问题在于图模型中没有体现e-mail这个实体,无法表达“用户自己给自己发送e-mail”等行为。正确的图建模方式应是将e-mail建模成图的点,同时实现e-mail与该e-mail发送者、收件人间的关联。在表达“用户自己给自己发送e-mail”时,将e-mail建模成一点,该点关联的发送者和收件人都指向相同用户。好的建模方式能够在系统规模、问题复杂性提升的情况下依然很好地捕获所有关键信息,满足用户需求。使用这样的建模方式来表达“对回复邮件的回复”行为时,“回复邮件”与“回复邮件的回复”都是e-mail,都应该被建模为图的点,“回复邮件”与相关的“回复邮件的回复”存在回复与被回复关系,应建模为边。判断图建模合理与否的关键在于判断图模型能否表达相关需求,比如,本示例中的图模型能否表达“热烈的邮件讨论”行为等。阿里巴巴采用分布式图存储来存储图模型的相关数据。四、图查询语言简介寻找具有某特点的“点集合”或者“边集合”是图数据查询的常见应用。图查询语言“Gremlin”可用于遍历图,寻找相关“点集合”或“边集合”,并基于获得的集合进行“groupby”等操作来构造最终查询结果。阿里巴巴优化了图查询语言,使得系统可以快速地实现复杂数据结构的查询。最新的竞品分析显示,“Gremlin”图查询语言具有数据加载快、可扩展与低延迟德等优点。五、全图计算与分析-高层语言除了图查询,全图计算与分析也是图应用的难点,阿里巴巴提供了类似SQL的抽象语言FLASH来降低全图计算的难度。阿里巴巴的抽象语言FLASH引入了循环语句,具有比SQL更强大的表达能力,将FLASH应用于连通分支算法,仅需几行代码就可以实现该算法功能。相比之下,使用C++语言实现连通分支算法所需要的代码量更大。下图展示了目前已验证的FLASH抽象语言可表达的所有算法。另外,阿里还使用Flink评估了FLASH语言的表达能力。左表第二列是使用Gelly语言实现相关算法使用的代码行数,第三列是使用FLASH语言实现相同算法所用的代码行数。总的来说,FLASH语言实现相同算法所需要的代码行数仅为Gelly语言的1/10甚至1/20,但两种实现语言带来的系统开销是几乎一致的。六、场景示例阿里云网络安全引入图结构以构建知识图谱,包括域名、主机IP、域名服务器等信息。引入图结构有利于在海量信息中及时发现网络中的隐藏模式,从而发现漏洞和威胁。相关实验显示,将海量数据预先构建成图再实时查询仅需500毫秒,相反,不预先将海量数据构建成图而采用SQL查询所需的时间高达80分钟,图结构能为查询带来数量级的性能提升,从而给业务带来质的变化。图技术在美国同样引起了广泛关注。最新数据显示,76%的FORTUNE 100语言都采用了图技术,排名前25的金融企业中有20家都利用图技术呈现交易信息。总的来说,图计算是大数据计算的有效工具,图数据能够提供更精准、更可靠的信息,以增强大数据分析能力,图计算将变得越来越重要。成功的图应用离不开建模、查询和系统优化等多个方面,大规模的动态图计算还存在许多问题尚未解决,未来阿里巴巴将致力于在这些方面做出贡献,为图应用开发者们带来福音。阿里巴巴发展图计算依赖于“横向”和“纵向”两个方面的合作,一方面,“横向”需要和阿里巴巴内部的硬件、网络等团队合作,以利用现有技术优化图计算的性能,从而给业务带来质的突破。另一方面,“纵向”需要和行业内领域专家紧密合作,利用图结构解决企业真实问题,使技术为业务赋能、创造更多价值。本文作者:晋恒阅读原文本文为云栖社区原创内容,未经允许不得转载。

February 18, 2019 · 1 min · jiezi

可应用于实际的14个NLP突破性研究成果(四)

摘要:最好的论文是可以直接走出实验室!NLP年度最佳应用论文大集锦!可应用于实际的14个NLP突破性研究成果(一) 可应用于实际的14个NLP突破性研究成果(二) 可应用于实际的14个NLP突破性研究成果(三)11.对序列建模的通用卷积和递归网络的实证评估作者:SHAOJIE BAI,J。ZICO KOLTER,VLADLEN KOLTUN论文摘要对于大多数深度学习实践者来说,序列建模与循环网络是同义词。然而,最近的研究结果表明,卷积架构在语音合成和机器翻译等任务上的表现优于循环网络。给定一个新的序列建模任务或数据集,应该使用哪种架构?我们对序列建模的一般卷积和循环架构进行了系统的评价。我们在广泛的标准任务中评估这些模型。我们的结果表明,一个简单的卷积架构在不同的任务和数据集上的表现优于LSTM等典型的循环网络。我们的结论是,需要重新考虑序列建模和循环网络之间的共同关联,卷积网络应该被视为序列建模任务的一个自然起点我们提供了相关代码:http://github.com/locuslab/TCN。总结本文的作者质疑了一个常见假设,即循环架构应该是序列建模任务的默认起点。他们的结果表明,时间卷积网络(TCN)在多个序列建模任务中明显优于长短期记忆网络(LSTMs)和门控循环单元网络等典型的循环架构。论文的核心思想是什么?1、时间卷积网络(TCN)是基于最近提出的最佳实践(如扩张卷积和残差连接)设计的,它在一系列复杂的序列建模任务中表现得明显优于通用的循环架构。2、TCN表现出比循环架构更长的记忆,因此更适合需要较长的历史记录的任务。关键成就是什么?在序列建模任务上提供了卷积架构和循环体系结构系统的比较。设计了卷积体系结构,它可以作为序列建模任务的方便且强大的起点。AI社区的对其评价?在使用RNN之前,一定要先从CNN开始。未来的研究领域是什么?为了提高TCN在不同序列建模任务中的性能,需要进一步精化架构和算法。可能应用的商业领域?引入TCN可以提高依赖于循环架构进行序列建模的AI系统的性能。其中包括以下任务:§机器翻译;§语音识别;§音乐和语音生成。你在哪里可以得到代码?1、如论文摘要所述,研究人员通过GitHub存储库提供了官方代码。2、你还可以查看PhilippeRémy提供的Keras实施的TCN。12.用于文本分类的通用语言模型微调-ULMFiT作者:JEREMY HOWARD和SEBASTIAN RUDER论文摘要迁移学习在计算机视觉方面取得了很多成功,但是同样的方法应用在NLP领域却行不通。所以我们提出了通用语言模型微调(ULMFiT),这是一种有效的转移学习方法,可以应用于NLP中的任何任务。该方法在6个文本分类任务上的性能明显优于现有的文本分类方法,在大部分的数据集上测试使得错误率降低了18-24%。此外,仅有100个标记样本训练的结果也相当不错。我们已经开源我们的预训练模型和代码。总结Howard和Ruder建议使用预先训练的模型来解决各种NLP问题。使用这种方法的好处是你无需从头开始训练模型,只需对原始模型进行微调。通用语言模型微调(ULMFiT)的方法优于最先进的结果,它将误差降低了18-24%。更重要的是,ULMFiT可以只使用100个标记示例,就能与10K标记示例中从头开始训练的模型的性能相匹配。论文的核心思想是什么?为了解决缺乏标记数据的难题,研究人员建议将转移学习应用于NLP问题。因此,你可以使用另一个经过训练的模型来解决类似问题作为基础,然后微调原始模型以解决你的特定问题,而不是从头开始训练模型。但是,这种微调应该考虑到几个重要的考虑因素:§不同的层应该进行不同程度地微调,因为它们捕获不同类型的信息。§如果学习速率首先线性增加然后线性衰减,则将模型的参数调整为任务特定的特征将更有效。§微调所有层可能会导致灾难性的遗忘;因此,从最后一层开始逐渐微调模型可能会更好。关键成就是什么?显著优于最先进的技术:将误差降低18-24%;所需的标记数据要少得多,但性能可以保障。AI社区对其的看法是什么?预先训练的ImageNet模型的可用性已经改变了计算机视觉领域,ULMFiT对于NLP问题可能具有相同的重要性。此方法可以应用于任何语言的任何NLP任务。未来的研究领域的方向是什么?改进语言模型预训练和微调。将这种新方法应用于新的任务和模型(例如,序列标记、自然语言生成、蕴涵或问答)。可能应用的商业领域?ULMFiT可以更有效地解决各种NLP问题,包括:§识别垃圾邮件、机器人、攻击性评论;§按特定功能对文章进行分组;§对正面和负面评论进行分类;§查找相关文件等你在哪里可以得到实现代码?Fast.ai提供ULMFiT的官方实施,用于文本分类,并作为fast.ai库的一部分。13.用非监督学习来提升语言理解,作者:ALEC RADFORD,KARTHIK NARASIMHAN,TIM SALIMANS,ILYA SUTSKEVER论文摘要自然语言理解包括各种各样的任务,例如文本蕴涵、问答、语义相似性评估和文档分类。虽然大量未标记的文本语料库很丰富,但用于学习这些特定任务的标记数据很少。我们证明,通过对多种未标记文本语料库中的语言模型进行生成预训练,然后对每项特定任务进行辨别性微调,可以实现这些任务的巨大收益。与以前的方法相比,我们在微调期间利用任务感知输入转换来实现有效传输,同时对模型架构进行最少的更改。我们证明了我们的方法在广泛的自然语言理解基准上的有效性。例如,我们在常识推理(Stories Cloze Test)上获得8.9%的性能改善,在问答(RACE)上达到5.7%,在文本蕴涵(MultiNLI)上达到1.5%。总结OpenAI团队建议通过在多种未标记文本语料库中预先训练语言模型,然后使用标记数据集对每个特定任务的模型进行微调,从而可以显著改善了语言理解。他们还表明,使用Transformer模型而不是传统的递归神经网络可以显著提高模型的性能,这种方法在所研究的12项任务中有9项的表现优于之前的最佳结果。论文的核心思想是什么?通过在未标记数据上学习神经网络模型的初始参数,然后使用标记数据使这些参数适应特定任务,结合使用无监督预训练和监督微调。通过使用遍历样式方法避免跨任务对模型体系结构进行大量更改:§预训练模型是在连续的文本序列上训练的,但是问题回答或文本蕴涵等任务具有结构化输入。§解决方案是将结构化输入转换为预先训练的模型可以处理的有序序列。使用Transformer模型而不是LSTM,因为这些模型提供了更加结构化的内存,用于处理文本中的长期依赖关系。取得了什么关键成就?对于自然语言推理(NLI)的任务,通过在SciTail上获得5%的性能改进和在QNLI上获得5.8%的性能改进。对于QA和常识推理的任务,表现优于以前的最佳结果-在Story Cloze上高达8.9%,在RACE上高达5.7%。通过在QQP上实现4.2%的性能改善,刷新了3个语义相似性任务中的2个的最新结果。对于分类任务,获得CoLA的45.4分,而之前的最佳结果仅为35分。AI社区对其看法是什么?该论文通过使用基于Transformer模型而非LSTM扩展了ULMFiT研究,并将该方法应用于更广泛的任务。“这正是我们希望我们的ULMFiT工作能够发挥作用的地方!”Jeremy Howard,fast.ai的创始人。未来的研究领域是什么?进一步研究自然语言理解和其他领域的无监督学习,以便更好地理解无监督学习的时间和方式。可能应用的商业领域?OpenAI团队的方法通过无监督学习增强了自然语言理解,因此可以帮助标记数据集稀疏或不可靠的NLP应用。 在哪里可以得到实现代码?Open AI团队在GitHub上的公开了代码和模型。14.语境化词向量解析:架构和表示,作者:MATTHEW E. PETERS,MARK NEUMANN,LUKE ZETTLEMOYER,WEN-TAU YIH论文摘要最近研究显示从预训练的双向语言模型(biLM)导出的上下文词表示为广泛的NLP任务提供了对现有技术的改进。然而,关于这些模型如何以及为何如此有效的问题,仍然存在许多问题。在本文中,我们提出了一个详细的实证研究,探讨神经结构的选择(例如LSTM,CNN)如何影响最终任务的准确性和所学习的表征的定性属性。我们展示了如何在速度和准确性之间的权衡,但所有体系结构都学习了高质量的上下文表示,这些表示优于四个具有挑战性的NLP任务的字嵌入。此外,所有架构都学习随网络深度而变化的表示,从基于词嵌入层的专有形态学到基于较低上下文层的局部语法到较高范围的语义。总之,这些结果表明,无人监督的biLM正在学习更多关于语言结构的知识。总结今年早些时候艾伦人工智能研究所的团队介绍了ELMo嵌入,旨在更好地理解预训练的语言模型表示。为此,他们精心设计了无监督和监督任务上广泛研究学习的单词和跨度表示。研究结果表明,独立于体系结构的学习表示随网络深度而变化。论文的核心思想是什么?预训练的语言模型大大提高了许多NLP任务的性能,将错误率降低了10-25%。但是,仍然没有清楚地了解为什么以及如何在实践中进行预训练。为了更好地理解预训练的语言模型表示,研究人员凭经验研究神经结构的选择如何影响:§直接终端任务准确性;§学习表示的定性属性,即语境化词表示如何编码语法和语义的概念。什么是关键成就?确认在速度和准确度之间存在权衡,在评估的三种架构中-LSTM,Transformer和Gated CNN:§LSTM获得最高的准确度,但也是最慢的;§基于Transformer和CNN的模型比基于LSTM的模型快3倍,但也不太准确。证明由预先训练的双向语言模型(biLM)捕获的信息随网络深度而变化:§深度biLM的词嵌入层专注于词形态,与传统的词向量形成对比,传统的词向量在该层也编码一些语义信息;§biLM的最低上下文层只关注本地语法;证明了biLM激活可用于形成对语法任务有用的短语表示。AI社区对其看法是什么?该论文在EMNLP 2018上发表。 “对我来说,这确实证明了预训练的语言模型确实捕获了与在ImageNet上预训练的计算机视觉模型相似的属性。”AYLIEN的研究科学家Sebastian Ruder。未来的研究领域是什么?使用明确的句法结构或其他语言驱动的归纳偏见来增强模型。 将纯无监督的biLM训练目标与现有的注释资源以多任务或半监督方式相结合。可能应用的商业领域?1、通过更好地理解预训练语言模型表示所捕获的信息,研究人员可以构建更复杂的模型,并增强在业务环境中应用的NLP系统的性能。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

February 18, 2019 · 1 min · jiezi

如何在Flutter上优雅地序列化一个对象

序列化一个对象才是正经事对象的序列化和反序列化是我们日常编码中一个非常基础的需求,尤其是对一个对象的json encode/decode操作。每一个平台都会有相关的库来帮助开发者方便得进行这两个操作,比如Java平台上赫赫有名的GSON,阿里巴巴开源的fastJson等等。而在flutter上,借助官方提供的JsonCodec,只能对primitive/Map/List这三种类型进行json的encode/decode操作,对于复杂类型,JsonCodec提供了receiver/toEncodable两个函数让使用者手动“打包”和“解包”。显然,JsonCodec提供的功能看起来相当的原始,在闲鱼app中存在着大量复杂对象序列化需求,如果使用这个类,就会出现集体“带薪序列化”的盛况,而且还无法保证正确性。来自官方推荐聪明如Google官方,当然不会坐视不理。json_serializable的出现就是官方给出的推荐,它借助Dart Build System中的build_runner和json_annotation库,来自动生成fromJson/toJson函数内容。(关于使用build_runner生成代码的原理,之前兴往同学的文章已经有所提及)关于如何使用json_serializable网上已经有很多文章了,这里只简单提一些步骤:Step 1 创建一个实体类Step 2 生成代码:来让build runner生成序列化代码。运行完成后文件夹下会出现一个xxx.g.dart文件,这个文件就是生成后的文件。Step 3 代理实现:把fromJson和toJson操作代理给上面生成出来的类我们为什么不用这个实现json_serializable完美实现了需求,但它也有不满足需求的一面:使用起来有些繁琐,多引入了一个类很重要的一点是,大量的使用"as"会给性能和最终产物大小产生不小的影响。实际上闲鱼内部的《flutter编码规范》中,是不建议使用"as"的。(对包大小的影响可以参见三笠同学的文章,同时dart linter也对as的性能影响有所描述)一种正经的方式基于上面的分析,很明显的,需要一种新的方式来解决我们面临的问题,我们暂且叫它,fish-serializable需要实现的功能我们首先来梳理一下,一个序列化库需要用到:获取可序列化对象的所有field以及它们的类型信息能够构造出一个可序列化对象,并对它里面的fields赋值,且类型正确支持自定义类型最好能够解决泛型的问题,这会让使用更加方便最好能够轻松得在不同的序列化/反序列化方式中切换,例如json和protobuf。困难在哪里flutter禁用了dart:mirrors,反射API无法使用,也就无法通过反射的方式new一个instance、扫描class的fields。泛型的问题由于dart不进行类型擦出,可以获取,但泛型嵌套后依然无法解开。Let’s rock无法使用dart:mirrors是个“硬”问题,没有反射的支持,类的内容就是一个黑盒。于是我们在迈出第一步的时候就卡壳了- -!这个时候笔者脑子里闪过了很多画面,白驹过隙,乌飞兔走,啊,不是…是c++,c++作为一种无法使用反射的语言,它是如何实现对象的 序列化/反序列化 操作的呢?一顿搜索猛如虎之后,发现大神们使用创建类对象的回调函数配合宏的方式来实现c++中类似反射这样的操作。这个时候,笔者又想到了曾经朝夕相处的Android(现在已经变成了flutter),Android中的Parcelable序列化协议就是一个很好的参照,它通过writeXXXAPIs将类的数据写入一个中间存储进行序列化,再通过readXXXAPIs进行反序列化,这就解决了我们上面提到的第一个问题,既如何将一个类的“黑盒子”打开。同时,Parcelable协议中还需要使用者提供一个叫做CREATOR的静态内部类,用来在反序列化的时候反射创建一个该类的对象或对象数组,对于没有反射可用的我们来说,用c++的那种回调函数的方式就可以完美解决反序列化中对象创建的问题。于是最终我们的基本设计就是:ValueHolder这是一个数据中转存储的基类,它内部的writeXXX APIs提供展开类内部的fields的能力,而readXXX则用来将ValueHolder中的内容读取赋值给类的fields。readList/readMap/readSerializable函数中的type argument,我们把它作为外部想要解释数据的方式,比如readSerializable<T>(key: ‘object’),表示外部想要把key为object的值解释为T类型。FishSerializableFishSerializable是一个interface,creator是个一个get函数,用来返回一个“创建类对象的回调”,writeTo函数则用来在反序列化的时候放置ValueHoder->fields的代码。JsonSerializer它继承于FishSerializer接口,实现了encode/decode函数,并额外提供encodeToMap和decodeFromMap功能。JsonSerializer类似JsonCodec,直接面向使用者用来json encode/decode以上,我们已经基本做好了一个flutter上支持对象序列化/反序列化操作的库的基本架构设计,对象的序列化过程可以简化为:由于ValueHolder中间存储的存在,我们可以很方便得切换 序列化/反序列器,比如现有的JsonSerializer用来实现json的encode/decode,如果有类似protobuf的需求,我们则可以使用ProtoBufSerializer来将ValueHolder中的内容转换成我们需要的格式。困难是不存在的有了基本的结构设计之后,实现的过程并非一帆风顺。如何匹配类型?为了能支持泛型容器的解析,我们需要类似下面这样的逻辑:List<SerializableObject> list = holder.readList<SerializableObject>(key: ’list’);List<E> readList<E>({String key}){ List<dynamic> list = _read(key);}E _flattenList<E>(List<dynamic> list){ list?.map<E>((dynamic item){ // 比较E是否属于某个类型,然后进行对应类型的转换 });}在Java中,可以使用Class#isAssignableFrom,而在flutter中,我们没有发现类似功能的API提供。而且,如果做下面这个测试,你还会发现一些很有意思的细节:void main() { print(‘int test’); test<int>(1); print(’\r\nint list test’); test<List<int>>(<int>[]); print(’\r\nobject test’); test<A<int>>(A<int>());}void test<T>(T t){ print(T); print(t.runtimeType); print(T == t.runtimeType); print(identical(T, t.runtimeType));}class A<T>{}输出的结果是:可以看到,对于List这样的容器类型,函数的type argument与instance的runtimeType无法比较,当然如果使用t is T,是可以返回正确的值的,但需要构造大量的对象。所以基本上,我们无法进行类型匹配然后做类型转换。如何解析泛型嵌套?接下去就是如何分解泛型容器嵌套的问题,考虑如下场景:Map<String, List<int>> listMap;listMap = holder.readMap<String, List<int>>(key: ’listMap’);readMap中得到的value type是一个List<int>,而我们没有API去切割这个type argument。所以我们采用了一种比较“笨”也相对实用的方式。我们使用字符串切割了type argument,比如:List<int> => <String>[List<int>, List, int]然后在内部展开List或Map的时候,使用字符串匹配的方式匹配类型,在目前的使用中,完美得支持了标准List和Map容器互相嵌套。但目前无法支持标准List和Map之外的其他容器类型。What’s moreIDE插件辅助写过Android的Parcelable的同学应该有种很深刻的体会,Parcelable协议中有大量的“机械”代码需要写,类似设计的fish-serializable也一样。为了不被老板和使用库的同学打死,同时开发了fish-serializable-intelij-plugin来自动生成这些“机械”代码。与json_serializable的对比fish-serializable在使用上配合IDE插件,减少了大量的"as"操作符的使用,同时在步骤上也更加简短方便。相比于json_annotation生成的代码,fish-serializable生成的代码也更具可读性,方便手动修改一些代码实现。fish-serializable可以通过手动接管 序列化/反序列化 过程的方式完美兼容json_annotation等其他方案。目前闲鱼app中已经开始大量使用。开源计划fish-serializable和fish-serializable-intelij-plugin都在开源计划中,相信不久就可以与大家见面,尽请期待~本文作者:闲鱼技术-海潴阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

January 30, 2019 · 1 min · jiezi

可应用于实际的14个NLP突破性研究成果(一)

摘要: 最好的论文是可以直接走出实验室!NLP年度最佳应用论文大集锦!语言理解对计算机来说是一个巨大的挑战。幼儿可以理解的微妙的细微差别仍然会使最强大的机器混淆。尽管深度学习等技术可以检测和复制复杂的语言模式,但机器学习模型仍然缺乏对我们的语言真正含义的基本概念性理解。但在2018年确实产生了许多具有里程碑意义的研究突破,这些突破推动了自然语言处理、理解和生成领域的发展。我们总结了14篇研究论文,涵盖了自然语言处理(NLP)的若干进展,包括高性能的迁移学习技术,更复杂的语言模型以及更新的内容理解方法。NLP,NLU和NLG中有数百篇论文,由于NLP对应用和企业AI的重要性和普遍性,所以我们从数百篇论文中寻找对NLP影响最大的论文。2018年最重要的自然语言处理(NLP)研究论文1.BERT:对语言理解的深度双向变换器的预训练,作者:JACOB DEVLIN,MING-WEI CHANG,KENTON LEE和KRISTINA TOUTANOVA论文摘要:我们引入了一种名为BERT的新语言表示模型,它是Transformer的双向编码器表示。与最近的语言表示模型不同,BERT旨在通过联合调节所有层中的左右上下文来预训练深度双向表示。因此,预训练的BERT表示可以通过一个额外的输出层进行微调,以创建适用于广泛任务的最先进模型,例如问答和语言推理,而无需实质性的具体的架构修改。BERT在概念上简单且经验丰富,它获得了11项自然语言处理任务的最新成果,包括将GLUE基准推至80.4%(提升了7.6%)、MultiNLI准确度达到86.7%(提升了5.6%)、SQuAD v1.1问题回答测试F1到93.2%(提升了1.5%)。总结谷歌AI团队提出了自然语言处理(NLP)的新前沿模型-BERT,它的设计允许模型从每个词的左侧和右侧考虑上下文。BERT在11个NLP任务上获得了新的最先进的结果,包括问题回答,命名实体识别和与一般语言理解相关的其他任务。论文的核心思想是什么?通过随机屏蔽一定比例的输入token来训练深度双向模型-从而避免单词间接“看到自己”的周期。通过构建简单的二进制分类任务来预训练句子关系模型,以预测句子B是否紧跟在句子A之后,从而允许BERT更好地理解句子之间的关系。训练一个非常大的模型(24个Transformer块,1024个隐藏层,340M参数)和大量数据(33亿字语料库)。什么是关键成就?刷新了11项NLP任务的记录,包括:获得80.4%的GLUE分数,这比之前最佳成绩提高了7.6%;在SQuAD 1.1上达到93.2%的准确率。预训练的模型不需要任何实质的体系结构修改来应用于特定的NLP任务。AI社区对其看法?BERT模型标志着NLP的新时代;两个无人监督的任务在一起为许多NLP任务提供了很好的性能;预训练语言模型成为一种新标准;未来的研究领域是什么?在更广泛的任务上测试该方法。收集BERT可能捕获或未捕获的语言现象。最可能的商业应用是什么?BERT可以帮助企业解决各种NLP问题,包括:提供更好的聊天机器人客服体验;客户评论分析;搜索相关信息;你在哪里可以代码?Google Research发布了一个官方Github存储库,其中包含Tensorflow代码和BERT预训练模型。BIT的PyTorch实现也可以在GitHub上获得。2.人类注意力的序列分类,作者:MARIA BARRETT,JOACHIM BINGEL,NORA HOLLENSTEIN,MAREK REI,ANDERSSØGAARD论文摘要学习注意力函数需要非常大规模的数据,不过有很多自然语言处理任务都是对人类行为的模拟,在这篇论文中作者们就表明人类的注意力确实可以为 NLP 中的许多注意力函数提供一个不错的归纳偏倚。具体来说,作者们根据人类阅读语料时的眼睛动作追踪数据估计出了「人类注意力」,然后用它对 RNN 网络中的注意力函数进行正则化。作者们的实验表明,人类注意力在大量不同的任务中都带来了显著的表现提升,包括情感分析、语法错误检测以及暴力语言检测。总结Maria Barrett和她的同事建议使用从眼动(eye-tracking)追踪语料库中获取的人类注意力来规范循环神经网络(RNN)中的注意力。通过利用公开可用的眼动追踪语料库,即通过眼睛跟踪测量(例如注视持续时间)增强的文本,它们能够在NLP任务中显着提高RNN的准确性,包括情绪分析、滥用语言检测和语法错误检测。论文的核心思想是什么?使用人的注意力,从眼动追踪语料库中估计,以规范机器注意力。模型的输入是一组标记序列和一组序列,其中每个标记与标量值相关联,该标量值表示人类读者平均专注于该标记的注意力。RNN联合学习循环参数和注意力功能,但可以在来自标记序列的监督信号和眼睛跟踪语料库中的注意力轨迹之间交替。建议的方法不要求目标任务数据带有眼睛跟踪信息。什么是关键成就?在注意力序列分类任务中引入循环神经结构。证明使用人眼注意力(从眼动追踪语料库中估计)来规范注意力功能可以在一系列NLP任务中实现显著改善,包括:§ 情绪分析,§ 检测语言检测,§ 语法错误检测。性能比基线平均误差减少4.5%。这些改进主要是由于召回率(recall)增加。AI社区对其看法?该论文获得了关于计算自然语言学习顶级会议的CoNLL 2018人类语言学习和处理启发的最佳研究论文特别奖。未来的研究领域是什么?在学习人类相关任务时,探索利用人类注意力作为机器注意力的归纳偏见的其他可能性。什么是可能的商业应用?RNN结合人类注意力信号,可应用于商业环境:§ 加强客户评论的自动分析;§ 过滤掉滥用的评论,回复。你在哪里可以得到实现代码?本研究论文的代码可在GitHub上获得。3.基于短语和神经元的无监督机器翻译,作者:GUILLAUME LAMPLE,MYLE OTT,ALEXIS CONNEAU,LUDOVIC DENOYER,MARC’AURELIO RANZATO论文摘要机器翻译系统在某些语言上实现了接近人类的性能,但其有效性强烈依赖于大量并行句子的可用性,这阻碍了它们适用于大多数语言。本文研究了如何在只能访问每种语言的大型单语语料库时学习翻译。我们提出了两种模型变体,一种神经模型,另一种基于短语的模型。两个版本都利用参数的初始化、语言模型的去噪效果以及通过迭代反向翻译自动生成并行数据。这些模型明显优于文献中的方法,同时更简单且具有更少的超参数。在广泛使用的WMT'14英语-法语和WMT'16德语-英语基准测试中,我们的模型不使用单个平行句的情况下分别获得28.1和25.2 BLEU分数,超过现有技术水平11 BLEU分。在英语-乌尔都语和英语-罗马尼亚语等低资源语言中,我们的方法比半监督和监督方法获得的效果都要好,我们的NMT和PBSMT代码是公开的。总结Facebook AI研究人员承认了缺乏用于训练机器翻译系统的大型并行语料库,并提出了一种更好的方法来利用单语数据进行机器翻译(MT)。特别是,他们认为通过适当的翻译模型初始化、语言建模和迭代反向翻译,可以成功地完成无监督的MT。研究人员提出了两种模型变体,一种是神经模型,另一种是基于短语的模型,它们的性能都极大地超越了目前最先进的模型。论文的核心思想是什么?无监督的MT可以通过以下方式完成:§ 合适的翻译模型初始化(即字节对编码);§ 在源语言和目标语言中训练语言模型,以提高翻译模型的质量(例如,进行本地替换,单词重新排序);§ 用于自动生成并行数据的迭代反向转换。有两种模型变体:神经和基于短语:§ 神经机器翻译一个重要的属性:跨语言共享内部表示。§ 基于短语的机器翻译在低资源语言对上优于神经模型,且易于解释和快速训练。什么是关键成就?基于神经和短语的机器翻译模型显著优于以前的无监督,例如:§ 对于英语-法语任务,基于短语的翻译模型获得的BLEU分数为28.1(比之前的最佳结果高出11 BLEU分);§ 对于德语-英语任务,基于神经和短语的翻译模型组合得到BLEU得分为25.2(高出基线10个BLEU点)。无监督的基于短语的翻译模型实现了超过使用10万个并行句子训练的监督模型对应的性能。AI社区的对其想法?该论文在自然语言处理领域的领先会议被评为EMNLP 2018评为最佳论文奖。未来的研究领域是什么?寻找更有效的原则实例或其他原则。扩展到半监督模型。什么是可能的商业应用?改进其中没有足够的并行语料库来训练受监督的机器翻译系统的机器翻译结果。你在哪里可以得到实现代码?Facebook团队在GitHub上提供了本研究论文的原始实现代码。未完待续……本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 29, 2019 · 1 min · jiezi

序列模型简介——RNN, Bidirectional RNN, LSTM, GRU

摘要: 序列模型大集合——RNN, Bidirectional RNN, LSTM, GRU既然我们已经有了前馈网络和CNN,为什么我们还需要序列模型呢?这些模型的问题在于,当给定一系列的数据时,它们表现的性能很差。序列数据的一个例子是音频的剪辑,其中包含一系列的人说过的话。另一个例子是英文句子,它包含一系列的单词。前馈网络和CNN采用一个固定长度作为输入,但是,当你看这些句子的时候,并非所有的句子都有相同的长度。你可以通过将所有的输入填充到一个固定的长度来解决这个问题。然而,它们的表现仍然比RNN要差,因为这些传统模型不了解给定输入的上下文环境。这就是序列模型和前馈模型的主要区别所在。对于一个句子,当看到一个词的时候,序列模型试图从在同一个句子中前面的词推导出关系。当我们读一个句子的时候,不会每次遇到一个新词都会再从头开始。我们会根据对所读过单词的理解来处理之后的每个单词。循环神经网络(Recurrent Neural Network,RNN)循环神经网络如上图所示。在一个时间步骤中的每个节点都接收来自上一个节点的输入,并且这可以用一个feedback循环来表示。我们可以深入这个feedback循环并以下图来表示。在每个时间步骤中,我们取一个输入x_i和前一个节点的输出a_i-1,对其进行计算,并生成一个输出h_i。这个输出被取出来之后再提供给下一个节点。此过程将一直继续,直到所有时间步骤都被评估完成。描述如何在每个时间步骤上计算输出的方程式,如下所示:在循环神经网络中的反向传播发生在图2中所示箭头的相反方向上。像所有其它的反向传播技术一样,我们评估一个损失函数,并获取梯度来更新权重参数。循环神经网络中有意思的部分是从右到左出现的反向传播。由于参数从最后的时间步骤更新到最初的时间步骤,这被称为通过时间的反向传播。长短期记忆(Long Short-Term Memory)— LSTM网络循环神经网络的缺点是,随着时间步骤长度的增大,它无法从差得很远的时间步骤中获得上下文环境。为了理解时间步骤t+1的上下文环境,我们有可能需要了解时间步骤0和1中的表示。但是,由于它们相差很远,因此它们所学的表示无法在时间步骤t+1上向前移动,进而对其起作用。“我在法国长大……我能说一口流利的法语”,要理解你说的法语,网络就必须远远地往后查找。但是,它不能这么做,这个问题可以归咎于梯度消失的原因。因此,循环神经网络只能记住短期存储序列。为了解决这个问题,Hochreiter & Schmidhuber提出了一种称为长短期记忆网络。LSTM网络的结构与循环神经网络保持一致,而重复模块会进行更多的操作。增强重复模块使LSTM网络能够记住长期依赖关系。让我们试着分解每个操作,来帮助网络更好地记忆。1、忘记门操作我们从当前时间步骤获取输入,并从前一时间步骤获取学习的表示,之后将它们连接起来。我们将连接后的值传递给一个sigmoid函数,该函数输出一个介于0和1之间的值(f_t)。我们在f_t和c_t-1之间做元素的乘积。如果一个值为0,那么从c_t-1中去掉,如果这个值为1,则完全通过。因此,这种操作也被称为“忘记门操作”。2、更新门操作上图表示的是“更新门操作”。我们将来自当前时间步骤中的值和前一时间步骤中已学习的表示连接起来。将连接的值通过一个tanh函数进行传递,我们生成一些候选值,并通过一个sigmoid函数传递,从候选值中选择一些值,所选的候选值将会被更新到c_t-1。3、输出门操作我们将当前时间步骤的值和前一时间步骤已学习的表示连接起来,并经由一个sigmoid函数传递来选择将要用作输出的值。我们获取单元状态并请求一个tanh函数,然后执行元素方式操作,其只允许选定的输出通过。现在,在一个单一单元中要完成很多的操作。当使用更大的网络时,与循环神经网络相比,训练时间将显著地增加。如果想要减少你的训练时间,但同时也使用一个能记住长期依赖关系的网络,那么还有另一个替代LSTM网络的方法,它被称为门控循环单元。门控循环单元(Gated Recurrent Unit ,GRU Network)与LSTM网络不同的是,门控循环单元没有单元状态,并且有2个门而不是3个(忘记、更新和输出)。门控循环单元使用一个更新门和一个重置门。更新门决定了应该让多少之前的信息通过,而重置门则决定了应该丢弃多少之前的信息。 在上面的图中,z_t表示更新门操作,通过使用一个sigmoid函数,我们决定让哪些之前的信息通过。h_t表示重置门操作,我们将前一时间步骤和当前时间步骤的连接值与r_t相乘。这将产生我们希望从前一时间步骤中所放弃的值。尽管门控循环单元在计算效率上比LSTM网络要高,但由于门的数量减少,它在表现方面仍然排在LSTM网络之后。因此,当我们需要更快地训练并且手头没有太多计算资源的情况下,还是可以选择使用门控循环单元的。双向循环神经网络所有上述双向RNN网络的一个主要问题是,它们从之前的时间步骤中学习表示。有时,你有可能需要从未来的时间步骤中学习表示,以便更好地理解上下文环境并消除歧义。通过接下来的列子,“He said, Teddy bears are on sale” and “He said, Teddy Roosevelt was a great President。在上面的两句话中,当我们看到“Teddy”和前两个词“He said”的时候,我们有可能无法理解这个句子是指President还是Teddy bears。因此,为了解决这种歧义性,我们需要往前查找。这就是双向RNN所能实现的。双向RNN中的重复模块可以是常规RNN、LSTM或是GRU。双向RNN的结构和连接如图10所示。有两种类型的连接,一种是向前的,这有助于我们从之前的表示中进行学习,另一种是向后的,这有助于我们从未来的表示中进行学习。正向传播分两步完成:我们从左向右移动,从初始时间步骤开始计算值,一直持续到到达最终时间步骤为止;我们从右向左移动,从最后一个时间步骤开始计算值,一直持续到到达最终时间步骤为止;结论将双向循环神经网络与LSTM模块相结合可以显著地提高性能,当将它们与监控机制相结合的时候,你可以在机器翻译、情感化分析等实例中获得最高水品的性能表现。希望本文对大家有帮助。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 28, 2019 · 1 min · jiezi

NLP度量指标BELU真的完美么?

摘要: NLP重要评价准则之一——BLEU,真的完美无缺么?刚接触自然语言处理的朋友通常会问我:当系统的输出是文本,而非对输入文本进行某种分类,如何对该系统进行评估。当模型的输入是文本信息,输出也是文本信息时,我们称之为序列到序列问题,也可称为字符串转换问题。序列到序列建模是解决NLP中较难任务的核心,它包括:1、 自动文摘(Text Summarization);2、 文本简化(Text simplification);3、 问答(Question answering);4、 聊天机器人(Chatbots);5、 机器翻译(Machine translation);理解序列到序列建模问题相对容易,如何对其进行评价才是难点。对于刚入门NLP的人来说,选取衡量标准较为困难。目前最流行的评价指标之一BLEU虽然常用,但也存在较大的缺陷。本文将介绍BELU的工作原理,指出其存在的问题,并探索如何结合自己的工作最大程度规避这些问题。一个难题BELU最初是评价机器翻译的指标,所以我们会以翻译(法语—英语)为例进行讲解。J’ai mangé trois filberts.下面两句为英语参考译文:I have eaten three hazelnuts.I ate three filberts.假设下面的翻译是由我们训练的神经网络产生。I ate three hazelnuts.问题来了:如何给上述翻译结果打分。要想利用机器学习来建立一个翻译系统,就需要一个实值分数来对其性能进行衡量。如果我们能够获取潜在的最佳得分,便能够计算它与实际值之间的误差。这能够在训练时为系统提供反馈,通过最小实际分数与潜在分数之间的差值来改进翻译模型,并通过查看同一任务上训练过的系统得分比较不同的模型。假设:如果输出句子中的单词在任何一个参考句出现,就给它打1分,如果没有出现,打0分。为了使计数标准化,使分数始终介于0和1之间。我们可以将某个参考译文中出现的单词总数除以输出句子中的单词总数。我们称该方法为unigram precision。在上面的翻译示例中,“I ate three hazelnuts”,我们能够在输出句子中看到至少一个参考句中的单词,再除以单词数4,该翻译的最终得分为1。但如果换成了下面的句子,该如何打分呢?Three three three three.按照刚才的衡量标准,得分依旧为1。但很明显,“I ate three hazelnuts”比“Three three three three”翻译得好。但如何将这一点告知我们正在训练的系统呢?你可以通过限定单词出现在翻译句子中的最大次数来调整分数。经过调整,“I ate three hazelnuts”计算出的得分仍然为1,而“Three three three three”为0.25。这解决了单词简单重复的问题,但新问题来了,如果单词的排列是无序的呢?就像下面:Ate hazelnuts I three如果继续用刚才的方法,这个句子得分为1。通过计数可以解决这个问题,但此时并非统计单个单词,而是相邻的单词。该方法称为n-grams,n是每组单词的数量,unigrams,bigrams,trigrams以及4-grams分别由一个、两个、三个、四个单词组成。在这个例子中,我们使用bigrams。通常来讲,BLEU的分数是unigram,bigram,trigram,4-grams的加权平均。为了简便,我们选择bigram,并忽略句子开头和结尾定义边界的单词。基于上述规则,句子排序如下:[Ate hazelnuts][hazelnuts I][I three]如果我们利用bigrams计算句子得分,“I ate three hazelnuts”是0分,“Three three three three”是0分,“I eat three hazelnuts”为1分,而下面这个例子也是0分:I ate.很明显这不是我们想要的。解决这个问题的方法是将目前的分数乘以一个简短惩罚因子。通过这个因子,得分高的候选翻译结果,能够同时在长度、词语选择、词语顺序等方面与参考句子匹配。如果翻译结果比参考句子更长或者一样长,惩罚因子为1。如果翻译译文长度比参考译文要短,就需要一个惩罚的机制去控制。在示例“I ate”中,句子长度为2个单词,与其最接近的参考句长度为4个单词。其简洁惩罚为0.36,乘以bigram的精度分数1,最终得分降至0.36。该指标旨在探测输出翻译与参考语句中有多少个n-grams重叠,并乘以简洁惩罚值后输出得分。BLEU由Kishore Papineni, Salim Roukos, Todd Ward, and Wei-Jing Zhu于2002年提出,是NLP中非常流行的度量指标,特别是对于系统输出是文本信息而不是分类的任务,其中包括机器翻译和自然语言生成。它解决了我们在文章开头提出的问题:找到一种方法,告诉我们翻译结果有多“好”,并为其打分。BLEU存在的问题在此之前,先概括一下BLEU的优势:**1、它方便,快速,容易计算,结果比较接近人类评分;2、在相同的任务中,能够很容易地将模型与基准进行比较;**但这些便利使得人们过度的使用它,即使在它不是最佳度量标准的任务中也作为了首选。尽管我们只以一句话为例进行了介绍,但BLEU是一种语料库级别的度量标准。计算语料库中的每个句子的BLEU分数,然后求它们的平均值会使得分数过大。BLEU的问题主要有以下四点:1、 不考虑意义;2、 不直接考虑句子结构3、 不能很好地处理形态丰富的语言4、 不能很好的映射到人类判断BLEU不考虑意义由于BLEU不考虑意义,我们便不能只使用它对机器翻译进行评估。作为一名机器翻译软件的用户,我更希望准确理解原文的含义,即使翻译的句子中在语法或句法上有所欠缺,只要清楚的表达了原文的意义也能接受。但BLEU并不考虑意义,它只奖励精确匹配的n-grams。这意味着一个虚词(如“an”或“on”)的差异和一个更重要的与内容相关的词语受到的惩罚是一样的。如果一个译文中有一个完全有效的同义词,只是没有出现在参考译文中,也会受到惩罚,但这并不合理。以下列句子为例对这个问题进行分析:Original (French): J’ai mangé la pomme.Reference translation: I ate the apple.下列的句子都是BLEU评出的 “糟糕的翻译”:I consumed the apple.I ate an apple.I ate the potato.但作为机器翻译的使用者,我觉得前面两句也表达清楚了原文的意思,即使它们和参考译文有所出入。第三句话让人不能接受,它完全改变了原文的意思。NIST方法是在BLEU方法上的一种改进。最主要的是引入了每个n-gram的信息量(information)的概念。BLEU算法只是单纯的将n-gram的数目加起来,而NIST是在得到信息量累加起来再除以整个译文的n-gram片段数目。这样相当于对于一些出现少的重点的词权重就给的大了。因此,在更常见的n-gram(如“of”)上的不匹配将受到更小的惩罚,而在更罕见的n-gram(如“buffalo buffalo”)上的不匹配将受到更大的惩罚。虽然这解决了赋予虚词过多权重的问题,但实际上却使惩罚同义词(如“ambled”代替“walked”)的问题变得更糟,因为这些同义词只出现在更少见的n-gram中,因此惩罚因子会更大。BLEU不直接考虑句子结构即使你通过调整词序改变句子的结构,仍然可以获得很高的BLEU分数。句法是对句子结构的研究,以词作为基本单位,并且各单词按照一定顺序排列。“I saw the dog with the telescope”一句,即能表示“I was using the telescope to look at the dog”,也可以说“the dog had the telescope”。二者的区别通过句子中各单词的排列顺序体现。在自然语言中,句子的内部结构特别重要,将句子各单词顺序打乱,既破坏了其完整含义,又让人难以理解。通过parsing可解决该问题。但parsing的计算相当密集,每次求值时必须解析所有输出,增加了开销。但不考虑句法结构,词序混乱的翻译与意思连贯的翻译获得相同的分数显得极其不合理。Callison-Burch等人在2006年对此进行了说明:Orejuela appeared calm as he was led to the American plane which will take him to Miami, Florida.Orejuela appeared calm while being escorted to the plane that would take him to Miami, Florida.Orejuela appeared calm as he was being led to the American plane that was to carry him to Miami in Florida.Orejuela seemed quite calm as he was being led to the American plane that would take him to Miami in Florida.翻译如下:Appeared calm when he was taken to the American plane, which will to Miami, Florida.这个翻译并不完美,它删除了人名,且句子后半段“will”后面没有动词,但它并非一点意义没有,毕竟比下面的翻译好,虽然两句话获得的BLEU分数相同:which will he was, when taken appeared calm to the American plane to Miami, Florida.BELU不能很好地处理形态丰富的语言BELU基于单词级别进行匹配,对于形态丰富的语言,显得并不适用。语素是语言中最小的音义结合体,它们组合在一起构成单词。以英语单词“cats”中的“s”为例,它告诉我们不止一只猫。有些语言,如土耳其语,在一个单词中有很多的语素,而英语,通常每个单词中的语素很少。以秘鲁语句为例:Jawen jemara ani iki.Jawen jemaronki ani iki.两句话都是可接受的英语“her village is large”的翻译。其中,以“jemar-”开头的单词在两个句子中有不同的结尾。不同的结尾代表不同的词素,这句话表明说话人很确定这个村子很大。上面那句话是他们去过那里见到了很大的村子,而下面那句话则表示他们是从别人那听说村子很大。这种特殊类型的语素被称为“证据标记(evidentiality marker)”,这在英语中不存在,而在秘鲁语中,一个句子的语法需要二者中的一个,所以我们的参考译文也应该有其中的一个。但是,如果我们没有在参考句中准确地找到该单词,就会对它进行惩罚,即使这两个句子都很好的表达了英语原句的意思。BELU不能很好的映射到人类判断构建机器翻译,聊天机器人以及问答系统最终的目的是希望人们能够使用它们。如果一个系统不能提供有效的输出,就没有意义。所以优化目的是使更多的人喜欢并尽可能多的使用所开发的系统。BELU首次提出时,作者进行了相关的行为测试,以确保与人类的判断相关。但当研究人员进行更多的实验时,发现BELU分数并不能很好的映射到人类判断。在一些任务中,甚至其它的评价方法更接近人类判断。Turian在2003年发现,BLEU在机器翻译中与人类判断的相关性最差,F1与人类判断最为相关,NIST次之。Sun在2010年比较了BLEU,GTM以及TER,发现BELU与人类判断的相关性最小。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

January 21, 2019 · 2 min · jiezi

最强NLP模型BERT可视化学习

摘要: 最强NLP模型谷歌BERT狂破11项纪录,全面超越人类,本文通过可视化带你直观了解它。2018年是自然语言处理(Natural Language Processing, NLP)领域的转折点,一系列深度学习模型在智能问答及情感分类等NLP任务中均取得了最先进的成果。近期,谷歌提出了BERT模型,在各种任务上表现卓越,有人称其为“一个解决所有问题的模型”。BERT模型的核心思想有两点,对推动NLP的发展有着重要的作用:(1)Transformer结构;(2)无监督的预训练。Transformer是一个只基于注意力(Attention)机制的序列模型,《Attention is all you need》一文中指出,它摒弃了固有的定式,没有采用RNN的结构。BERT模型同时需要预训练,从两个无监督任务中获取权重:语言建模(给定左右上下文,预测丢失的单词)以及下一个句子预测(预测一个句子是否跟在另一个句子后面)。BERT是个“多头怪”BERT与传统的注意力模型有所不同,它并非在RNN的隐藏状态上直接连接注意力机制。BERT拥有多层注意力结构(12层或24层,取决于模型),并且在每个层(12层或16层)中都包含有多个“头”。由于模型的权重不在层与层之间共享,一个BERT模型相当于拥有24×16=384种不同的注意力机制。BERT可视化BERT模型较为复杂,难以直接理解它学习的权重的含义。深度学习模型的可解释性通常不强,但我们可以通过一些可视化工具对其进行理解。Tensor2Tensor提供了出色的工具对注意力进行可视化,我结合PyTorch对BERT进行了可视化。点击查看详情。该工具将注意力可视化为连接被更新位置(左)和被关注位置(右)之间的连线。不同的颜色对应不同的“注意力头”,线段宽度反映注意力值的大小。在该工具的顶部,用户可以选择模型层,以及一个或者多个“注意力头”(通过点击顶部颜色切换,一共包含12个不同的“头”)BERT到底学习什么?该工具能用于探索预先训练的BERT模型的各个层以及头部的注意模式。以下列输入值为例进行详解:句子A:I went to the store.句子B:At the store, I bought fresh strawberries.BERT采用WordPiece tokenization对原始句子进行解析,并使用[CLS]对token进行分类以及[SEP]对token进行分隔,则输入的句子变为:[CLS] i went to the store. [SEP] at the store, i bought fresh straw ##berries. [SEP]接下来我将确定6个关键模式,并展示每个模式特定层/头的可视化效果。模式1:下一个单词的注意力(Attention to next word)在该模式下,特定单词的大部分注意力都集中在序列中该单词的下一个token处。如下图所示,我们以第二层的head 0为例(所选头部由顶部颜色栏中突出显示的正方形表示)。左边图中展示了所有token的注意力,右边则显示了特定token(“i”)的注意力。“i”几乎所有的注意力都集中在它的下一个token,即“went”处。左图中,[SEP]指向了[CLS],而非“at”,也就是说,指向下一个单词的这种模式只在句子中起作用,而在句子间的效果较弱。该模式类似于RNN中的backward,状态从右往左依次更新。模式2:前一个单词的注意力(Attention to previous word)在该模式下,特定单词的大部分注意力都集中在序列中该单词的前一个token处。本例中,“went”的大部分注意力集中于它的前一个单词“i”。模式2不如模式1明显,特定的单词注意力有所分散。该过程与RNN中的forward类似。模式3:相同/相关单词的注意力(Attention to identical/related words)在该模式下,特定单词的大部分注意力集中于与其相同或者相关的单词,包括该单词本身。下图中,“store”的大部分注意力集中在它本身。由于注意力有所分散,该模式也不明显。模式4:其它句子中相同/相关单词的注意力(Attention to identical/related words in other sentence)在该模式中,注意力集中在其它句子中与指定单词相同或者相似的单词。如下图,第二个句子中的“store”与第一个句子中的“store”关联最强。这对于下一个句子预测任务非常有帮助,它能够帮助识别句子之间的关系。模式5:预测单词的注意力(Attention)在该模式下,注意力集中于其它可以预测源单词的单词上,且不包括源单词本身。如下图,“straw”的注意力主要集中于“##berries”,而“##berries”的注意力主要集中于“straw”。模式6:分隔符标记的注意力(Attention to delimiter tokens)在该模式下,特定单词的注意力主要集中于分隔符,[CLS]或[SEP]中。如下图,大多数的注意力都集中在两个[SEP]中,这或许是模型将语句级别状态传递到各个token中的一种方法。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 17, 2019 · 1 min · jiezi

重磅公开!阿里语音识别模型端核心技术,让你“听”见未来

阿里妹导读:语音识别技术作为人工智能技术中的重要组成部分,成为影响人机交互的核心组件之一,从各种智能家用IoT设备的语音交互能力,到公共服务、智慧政务等场合的应用,语音识别技术正在影响着人们生活的方方面面。本文将全面介绍阿里云语音识别技术中的重要模型端技术,希望和业界同仁交流探讨。声学模型、语言模型和解码器可以看作是现代语音识别系统最核心的三个组成部分。虽然最近有一些研究者尝试构建End2end的语音识别系统,但包含声学模型、语言模型和解码器的现代语音识别系统依然是当前最主流和使用最广泛的系统。在这其中,声学模型主要用来构建输入语音和输出声学单元之间的概率映射关系;语言模型用来描述不同字词之间的概率搭配关系,使得识别出的句子更像自然文本;解码器负责结合声学单元概率数值和语言模型在不同搭配上的打分进行筛选,最终得到最可能的识别结果。随着近几年深度学习的火热,语音识别领域也纷纷投入深度学习的大潮之中。将传统HMM-GMM声学模型替换成HMM-DNN声学模型后,可以获得超过20%的相对提升,在传统N-Gram语言模型基础上叠加NN-LM语言模型也可以获得进一步的提高。在这过程中,声学模型由于更适合采用深度神经网络模型,从而受到研究者更多的关注。本文主要介绍阿里云语音识别技术中采用的声学模型技术和语言模型技术,包括LC-BLSTM声学模型、LFR-DFSMN声学模型和NN-LM语言模型,其中LC-BLSTM是对传统BLSTM模型的一种改进,在保持了高准确率的同时,提供了低延时的特性;而DFSMN是一种新颖的非递归结构的神经网络却可以像RNN一样对信号的长时相关进行建模,同时可以获得更稳定的训练效果和更好的识别准确。NN-LM语言模型是近年来在传统N-Gram语言模型基础上获得的进一步改进。Latency-Controlled BLSTM模型DNN(即fully connected DNN)模型的优点在于通过增加神经网络的层数和节点数,扩展了网络对于复杂数据的抽象和建模能力,但同时DNN模型也存在一些不足,例如DNN中一般采用拼帧来考虑上下文相关信息对于当前语音帧的影响,这并不是反映语音序列之间相关性的最佳方法。自回归神经网络(RNN)在一定程度上解决了这个问题,它通过网络节点的自连接达到利用序列数据间相关性的目的。进一步有研究人员提出一种长短时记忆网络(LSTM-RNN),它可以有效减轻简单RNN容易出现的梯度爆炸和梯度消散问题,而后研究人员又对LSTM进行了扩展,使用双向长短时记忆网络(BLSTM-RNN)进行声学模型建模,以充分考虑上下文信息的影响。BLSTM模型可以有效地提升语音识别的准确率,相比于DNN模型,相对性能提升可以达到15%-20%。但同时BLSTM模型也存在两个非常重要的问题:1、句子级进行更新,模型的收敛速度通常较慢,并且由于存在大量的逐帧计算,无法有效发挥GPU等并行计算工具的计算能力,训练会非常耗时;2、由于需要用到整句递归计算每一帧的后验概率,解码延迟和实时率无法得到有效保证,很难应用于实际服务。对于这两个问题,学术界首先提出Context-Sensitive-Chunk BLSTM(CSC-BLSTM)的方法加以解决,而此后又提出了Latency Controlled BLSTM(LC-BLSTM)这一改进版本,更好、更高效地减轻了这两个问题。我们在此基础上采用LC-BLSTM-DNN混合结构配合多机多卡、16bit量化等训练和优化方法进行声学模型建模,取得了相比于DNN模型约17-24%的相对识别错误率下降。典型的LSTM节点结构由3个gate组成:input gate、forget gate、output gate和一个cell组成,输入、输出节点以及cell同各个门之间都存在连接;inputgate、forget gate同cell之间也存在连接,cell内部还有自连接。这样通过控制不同门的状态,可以实现更好的长短时信息保存和误差传播。LSTM可以像DNN一样逐层堆积成为DeepLSTM,为了更好地利用上下文信息,还可以使用BLSTM逐层堆积构造Deep BLSTM,其结构如下图所示,网络中沿时间轴存在正向和反向两个信息传递过程,每一个时间帧的计算都依赖于前面所有时间帧和后面所有时间帧的计算结果,对于语音信号这种时序序列,该模型充分考虑了上下文对于当前语音帧的影响,能够极大提高音素状态的分类准确率。然而由于标准的BLSTM是对整句语音数据进行建模,训练和解码过程存在收敛慢、延迟高、实时率低等问题,针对这些弊端我们采用了Latency Controlled BLSTM进行解决,与标准的BLSTM使用整句语音进行训练和解码不同,Latency Control BLSTM使用类似truncated BPTT的更新方式,并在cell中间状态处理和数据使用上有着自己的特点,如下图所示,训练时每次使用一小段数据进行更新,数据由中心chunk和右向附加chunk构成,其中右向附加chunk只用于cell中间状态的计算,误差只在中心chunk上进行传播。时间轴上正向移动的网络,前一个数据段在中心chunk结束时的cell中间状态被用于下一个数据段的初始状态,时间轴上反向移动的网络,每一个数据段开始时都将cell中间状态置为0。该方法可以很大程度上加快网络的收敛速度,并有助于得到更好的性能。解码阶段的数据处理与训练时基本相同,不同之处在于中心chunk和右向附加chunk的维度可以根据需求进行调节,并不必须与训练采用相同配置。LFR-DFSMN模型FSMN是近期被提出的一种网络结构,通过在前馈全连接神经网络(Feedforward Fully-connectedNeural Networks,FNN)的隐层添加一些可学习的记忆模块,从而可以有效地对信号的长时相关性进行建模。FSMN相比于LCBLSTM不仅可以更加方便的控制时延,而且往往也能获得更好的性能,需要的计算资源也更少。但是标准的FSMN很难训练非常深层的结构,由于梯度消失问题导致训练效果不好。而深层结构的模型目前在很多领域被证明具有更强的建模能力。因而针对此我们提出了一种改进的FSMN模型,称之为深层的FSMN(Deep FSMN, DFSMN)。进一步的我们结合低帧率(Low Frame Rate,LFR)技术构建了一种高效的实时语音识别声学模型,相比于去年我们上线的LFR-LCBLSTM声学模型可以获得超过20%的相对性能提升,同时可以获得2-3倍的训练以及解码的加速,可以显著的减少我们的系统实际应用时所需要的计算资源。最早提出的FSMN的模型结构如上图(a)所示,其本质上是一个前馈全连接神经网络,通过在网络的某些隐层旁添加一些记忆模块(memory block)来对当前时刻周边的上下文信息进行建模,从而使得模型可以对时序信号的长时相关性进行建模。记忆模块采用如上图(b)所示的抽头延迟结构将当前时刻以及之前 N 个时刻的隐层输出通过一组系数编码得到一个固定的表达。FSMN的提出是受到数字信号处理中滤波器设计理论的启发:任何无限响应冲击(Infinite Impulse Response, IIR)滤波器可以采用高阶的有限冲击响应(FiniteImpulseResponse, FIR)滤波器进行近似。从滤波器的角度出发,如上图(c)所示的RNN模型的循环层就可以看作如上图(d)的一阶IIR滤波器。而FSMN采用的采用如上图(b)所示的记忆模块可以看作是一个高阶的FIR滤波器。从而FSMN也可以像RNN一样有效的对信号的长时相关性进行建模,同时由于FIR滤波器相比于IIR滤波器更加稳定,因而FSMN相比于RNN训练上会更加简单和稳定。根据记忆模块编码系数的选择,可以分为:标量FSMN(sFSMN)矢量FSMN(vFSMN)sFSMN 和 vFSMN 顾名思义就是分别使用标量和矢量作为记忆模块的编码系数。以上的FSMN只考虑了历史信息对当前时刻的影响,我们可以称之为单向的FSMN。当我们同时考虑历史信息以及未来信息对当前时刻的影响时,我们可以将单向的FSMN进行扩展得到双向的FSMN。FSMN相比于FNN,需要将记忆模块的输出作为下一个隐层的额外输入,这样就会引入额外的模型参数。隐层包含的节点越多,则引入的参数越多。研究结合矩阵低秩分解(Low-rank matrix factorization)的思路,提出了一种改进的FSMN结构,称之为简洁的FSMN(Compact FSMN,cFSMN)。下图是一个第l个隐层包含记忆模块的cFSMN的结构框图。对于cFSMN,通过在网络的隐层后添加一个低维度的线性投影层,并且将记忆模块添加在这些线性投影层上。进一步的,cFSMN对记忆模块的编码公式进行了一些改变,通过将当前时刻的输出显式的添加到记忆模块的表达中,从而只需要将记忆模块的表达作为下一层的输入。这样可以有效的减少模型的参数量,加快网络的训练。上图是我们进一步提出的Deep-FSMN(DFSMN)的网络结构框图,其中左边第一个方框代表输入层,右边最后一个方框代表输出层。我们通过在cFSMN的记忆模块(红色框框表示)之间添加跳转连接(skip connection),从而使得低层记忆模块的输出会被直接累加到高层记忆模块里。这样在训练过程中,高层记忆模块的梯度会直接赋值给低层的记忆模块,从而可以克服由于网络的深度造成的梯度消失问题,使得可以稳定的训练深层的网络。相比于之前的cFSMN,DFSMN优势在于,通过跳转连接可以训练很深的网络。对于原来的cFSMN,由于每个隐层已经通过矩阵的低秩分解拆分成了两层的结构,这样对于一个包含4层cFSMN层以及两个DNN层的网络,总共包含的层数将达到13层,从而采用更多的cFSMN层,会使得层数更多而使得训练出现梯度消失问题,导致训练的不稳定性。我们提出的DFSMN通过跳转连接避免了深层网络的梯度消失问题,使得训练深层的网络变得稳定。需要说明的是,这里的跳转连接不仅可以加到相邻层之间,也可以加到不相邻层之间。跳转连接本身可以是线性变换,也可以是非线性变换。具体的实验我们可以实现训练包含数十层的DFSMN网络,并且相比于cFSMN可以获得显著的性能提升。从最初的FSMN到cFSMN不仅可以有效的减少模型的参数,而且可以获得更好的性能。进一步的在cFSMN的基础上,我们提出的DFSMN,可以更加显著的提升模型的性能。如下表是在一个2000小时的英文任务上基于BLSTM,cFSMN,DFSMN的声学模型性能对比。从上表中可以看到,在2000小时这样的任务上,DFSMN模型可以获得比BLSTM声学模型相对14%的错误率降低,显著提高了声学模型的性能。传统的声学模型,输入的是每帧语音信号提取的声学特征,每帧语音的时长通常为10ms,对于每个输入的语音帧信号会有相对应的一个输出目标。最近有研究提出一种低帧率(Low Frame Rate,LFR)建模方案:通过将相邻时刻的语音帧进行绑定作为输入,去预测这些语音帧的目标输出得到的一个平均输出目标。具体实验中可以实现三帧(或更多帧)拼接而不损失模型的性能。从而可以将输入和输出减少到原来的三分之一甚至更多,可以极大的提升语音识别系统服务时声学得分的计算以及解码的效率。我们结合LFR和以上提出的DFSMN,构建了基于LFR-DFSMN的语音识别声学模型,经过多组实验我们最终确定了采用一个包含10层cFSMN层+2层DNN的DFSMN作为声学模型,输入输出则采用LFR,将帧率降低到原来的三分之一。识别结果和去年我们上线的最好的LCBLSTM基线比较如下表所示。通过结合LFR技术,我们可以获得三倍的识别加速。从上表中可以看到,在实际工业规模应用上,LFR-DFSMN模型比LFR-LCBLSTM模型可以获得20%的错误率下降,展示了对大规模数据更好的建模特性。NN-LM语言模型语言模型,顾名思义,对语言进行建模的模型。语言表达可以看作一串字符序列,不同的字符序列组合代表不同的含义,字符的单位可以是字或者词。语言模型的任务,可以看作是给定字符序列,如何估计该序列的概率,或者说,如何估计该序列的合理性。P(上海 的 工人 师傅 有 力量)>P(上海 的 工人 食腐 有 力量)拿这句话做个例子。比如到底应该是“工人师傅有力量”,还是“工人食腐有力量”,哪句话更“合适”。我们容易判断左边这句的概率大一点。于是我们希望通过语言模型的建模,可以给出符合人类预期的概率分配。就像这句,“工人师傅”的概率,大于“工人食腐”的概率。基于统计词频的传统N元文法模型,通过马尔可夫假设简化了模型结构和计算,通过计数的方式计算,通过查找的方式使用。拥有估计简单、性能稳定、计算快捷的优势,有超过三十年的使用历史。然而其马尔科夫假设强制截断建模长度,使得模型无法对较长的历史建模;基于词频的估计方式也使得模型不够平滑,对于低词频词汇估计不足。随着神经网络(Neural Networks,NNs)的第三次崛起,人们开始尝试通过NN来进行语言模型建模。一个典型的建模结构是递归神经网络(recurrentneural networks,RNNs),其递归的结构理论上可以对无穷长序列进行建模,弥补了N元文法对于序列长度建模的不足;同时其各层间的全向连接也保证了建模的平滑。此外为了提升模型的性能,研究者们还尝试了通过长短时记忆(Long Short-Term Memory,LSTM)结构来提升基本RNN本身建模能力的不足,进一步提升模型性能。NN用于大规模语言建模的系统中,需要面对一些问题,例如大词表带来的存储和计算增加。实际线上系统的词表往往比较大,而随着词表的增加,基本RNN结构的存储和计算量都会几何级数爆炸式增长。为此,研究者们进行了一些尝试,压缩词典尺寸成了一个最直接的解决方案,一个经典的方法是词表聚类。该方法可以大幅压缩词表尺寸,但往往也会带来一定的性能衰减。更直接的一个想法是直接过滤掉低频词汇,这样依然会带来一定的性能衰减,据此有一个改进策略,我们发现真正制约速度性能的主要是输出层节点,输入层节点大,借助projection层可以很好解决,于是输入层采用大辞典,而仅对输出层词表进行抑制,这样不仅尽可能地降低了损失,同时过滤掉过低的词频,也有利于模型节点的充分训练,性能往往还会略有提升。词表的压缩可以提升建模性能,降低计算量和存储量,但仅限于一定的量级,不可以无限制压缩,如何继续降低计算量依然是一个问题。一些方法被提了出来。例如LightRNN,通过类似聚类的方式,利用embedding的思想,把词表映射到一个实值矩阵上,实际输出只需要矩阵的行加矩阵的列,计算量大概也能开个方。和节点数多一起造成计算量大的一个原因就是softmax输出,需要计算所有的节点求个和,然后得到分母。若是这个分母能保持一个常数,实际计算的时候就只算需要的节点,在测试环节就快的多了。于是就有了正则项相关的方法,Variance Regularization,如果训练速度可以接受的话,这种方法在基本不损失模型正确性的情况下可以大幅提升前向计算速度;如果训练的时候也想提速,还可以考虑基于采样,sampling的方法,比如NCE、Importance Sampling、Black Sampling等,本质上就是说,在训练的时候不计算全部节点,只计算正样本(也就是标签为1的节点),以及部分通过某种分布采样的到的负样本,避免高输出造成的计算缓慢。速度上提升还是很明显的。从阿里云获得开发者模型定制能力想象一个做智能电话客服或是智能会议系统的开发者,需要为他的系统接入语音识别(将语音转写为文字)的能力。摆在他面前的会是这样一个尴尬的局面:一个选择是自己从零开始学做语音识别,这可能要花费大量的时间和金钱。毕竟人工智能这种事情,各大互联网巨头投入大量的人力、物力、财力,也要花较长的时间才能积累下技术;第二个选择是用上述巨头们在互联网上提供的开箱即用的、one size fits all的语音识别接口,时间是省下了,但语音转文字的准确率嘛,只能碰碰运气,毕竟巨头们也很忙,没有精力为你关注的场景进行优化。那么问题来了:有没有一种手段能够以最小的投入获得业务上最佳的语音识别效果呢?答案是肯定的。阿里云依托达摩院业界领先的语音交互智能,打破传统语音技术提供商的供给模式,在云计算时代让普通开发者也能够通过阿里云提供的语音识别云端自学习技术,获得定制优化自己所关心的业务场景的成套手段。阿里云让广大的开发者站在巨头的肩膀上,通过自主可控的自学习,在短时间内实现对语音识别系统应用从入门到精通,并在开发者关心的场景下轻松拥有业界顶尖的语音识别准确率。这就是云计算时代的语音识别技术全新的供给模式。与其它人工智能技术一样,语音识别技术的关键在于算法、算力和数据三个方面。阿里云依托达摩院语音交互智能,近年来持续在世界前沿进行“算法”演进,近期还将最新的研究成果DFSMN声学模型开源,供全世界的研究者复现目前最佳的结果并进行持续提升。在“算力”方面自不用说,这本身就是云计算的天然强项。基于阿里云ODPS-PAI平台,我们构建了专为语音识别应用优化的CPU/GPU/FPGA/NPU训练和服务混布平台,每天服务于阿里云上巨量的语音识别请求。在“数据”方面,我们提供通过海量数据训练的、开箱即用的场景模型,包括电商、客服、政务、手机输入等等。同时应该看到,在具体的落地场景下往往会有一些非常特殊、领域相关的“说法”需要被识别,很多时候类似于“碎屑岩岩性地层”、“海相碳酸盐岩”这种特定说法对于通用场景模型的识别率提出了挑战。要获得开发者关心的具体场景下最佳的准确率,开箱即用的模型一般还需要一定的定制优化工作才可以达到。传统上,这样的定制是通过语音技术服务提供商来完成的,在成本、周期、可控性等方面都存在明显不足。阿里云提供的语音定制“自学习”平台服务,可以提供多种手段,在很短的时间内、以较低的成本,让开发者完全掌控模型定制优化及上线的工作。阿里云创新工具平台及服务技术,依托强大的基础设施,使得在云计算的大背景下进行大规模定制化语音服务成为可能。而开发者完全无需关心后台的技术和服务,只需要使用阿里云提供的简单易用的“自学习”工具,利用场景知识和数据,就可以获得该特定场景下最优的效果,并按需要持续迭代提升。阿里云的智能语音自学习平台具备以下优势:易:智能语音自学习平台颠覆性地提供一键式自助语音优化方案,极大地降低进行语音智能优化所需要的门槛,让不懂技术的业务人员也可以来显著提高自身业务识别准确率。快:自学习平台能够在数分钟之内完成业务专属定制模型的优化测试上线,更能支持业务相关热词的实时优化,一改传统定制优化长达数周甚至数月的漫长交付弊端。准:自学习平台优化效果在很多内外部合作伙伴和项目上得到了充分验证,很多项目最终通过自学习平台不光解决了效果可用性问题,还在项目中超过了竞争对手使用传统优化方式所取得的优化效果。举例来说,开发者可以使用下述多种“自学习”手段来定制自己关心领域的模型:a)业务热词定制在许多特定场所,要求快速对特定词的识别能力进行加强(注:包括两种模式,模式一为其他词易被识别成特定词;模式二为特定词易被识别成其他词),采用实时热词加载技术,可以在实时场景下,通过设置不同的档位,能够实现热词识别能力的加强。b)类热词定制很多时候,相同的发音相同的属性在不同上下文上会需要不同的识别效果。联系人和地名就是典型的案例,对于不同人的好友,“张阳”和“章扬”我们就必须能准确地识别出相应的名字。同样,相隔千里的安溪跟安西如果识别错误会给导航带来大麻烦。智能语音自学习平台相信“每个人都值得被尊重”,提供联系人类和地名类的定制能力,“让天下没有难识的路”。c)业务专属模型定制用户通过输入对应领域的相关文本,如行业或公司的基本介绍、客服聊天记录、领域常用词汇和专有名词等,即可快速自行生成该行业下的定制模型,整个定制过程无需用户人工干预。通过这些手段,阿里云使得开发者不必关心语音技术的算法和工程服务细节,专注于他们擅长的垂直领域的知识和数据收集,实现全新的语音技术云端供给模式,造福于广大的开发者及其业务结果。本文作者:鄢志杰、薛少飞、张仕良、郑昊、雷鸣阅读原文本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

January 15, 2019 · 1 min · jiezi

用Python玩转时序数据

摘要: 本文简要介绍了如何从零开始使用Python中的时间序列。这包括对时间序列的简单定义,以及对利用pandas访问伦敦市居民智能电表所获取数据的处理。时间序列是日常生活中最常见的数据类型之一。股票价格、销售信息、气候数据、能源使用,甚至个人身高体重都是可以用来定期收集的数据样本。几乎每个数据科学家在工作中都会遇到时间序列,能够有效地处理这些数据是数据科学领域之中的一项非常重要的技能。本文简要介绍了如何从零开始使用Python中的时间序列。这包括对时间序列的简单定义,以及对利用pandas访问伦敦市居民智能电表所获取数据的处理。可以点击此处获取本文中所使用的数据。还提供了一些我认为有用的代码。让我们从基础开始,时间序列的定义是这样的:时间序列是按时间的顺序进行索引、排列或者绘制的数据点的集合。最常见的定义是,一个时间序列是在连续的相同间隔的时间点上取得的序列,因此它是一个离散时间数据的序列。时间序列数据是围绕相对确定的时间戳而组织的。因此,与随机样本相比,可能包含我们将要尝试提取的一些相关信息。加载和控制时间序列数据集让我们使用一些关于能源消耗计费的数据作为例子,以kWh(每半小时)为单位, 在2011年11月至2014年2月期间,对参与英国电力网络领导的低碳伦敦项目的伦敦居民样本数据进行分析。我们可以从绘制一些图表开始,最好了解一下样本的结构和范围,这也将允许我们寻找最终需要纠正的缺失值。对于本文的其余部分,我们只关注DateTime和kWh两列。重采样让我们从较简单的重采样技术开始。重采样涉及到更改时间序列观测的频率。特征工程可能是你对重新采样时间序列数据感兴趣的一个原因。实际上,它可以用来为监督学习模型提供额外的架构或者是对学习问题的领会角度。pandas中的重采样方法与GroupBy方法相似,因为你基本上是按照特定时间间隔进行分组的。然后指定一种方法来重新采样。让我们通过一些例子来把重采样技术描述的更具体些。我们从每周的总结开始:data.resample()方法将用于对DataFrame的kWh列数据重新取样;“W”表示我们要按每周重新取样;sum()方法用于表示在此时间段计算kWh列的总和;我们可以对每日的数据也这么做处理,并且可以使用groupby和mean函数进行按小时处理:为了进一步进行重新采样,pandas有许多内置的选项,你甚至还可以定义自己的方法。下面两个表分别显示了时间周期选项及其缩写别名和一些可能用于重采样的常用方法。其它探索这里还有一些你可以用于处理数据而进行的其它探索:用Prophet建模Facebook Prophet于2017年发布的,可用于Python,而R.Prophet是设计用于分析在不同时间间隔上显示模式的日观测时间序列。Prophet对于数据丢失情况和趋势的变化具有很强的鲁棒性,并且通常能够很好地处理异常值。它还具有高级的功能,可以模拟假日在时间序列上产生的影响并执行自定义的变更点,但我将坚持使用基本规则来启动和运行模型。我认为Prophet可能是生产快速预测结果的一个好的选择,因为它有直观的参数,并且可以由有良好领域知识背景的但缺乏预测模型的技术技能的人来进行调整。有关Prophet的更多信息,大家可以点击这里查阅官方文档。在使用Prophet之前,我们将数据里的列重新命名为正确的格式。Date列必须称为“ds”和要预测值的列为“y”。我们在下面的示例中使用了每日汇总的数据。然后我们导入Prophet,创建一个模型并与数据相匹配。在Prophet中,changepoint_prior_scale参数用于控制趋势对变化的敏感度,越高的值会更敏感,越低的值则敏感度越低。在试验了一系列值之后,我将这个参数设置为0.10,而不是默认值0.05。为了进行预测,我们需要创建一个称为未来数据框(future dataframe)的东西。我们需要指定要预测的未来时间段的数量(在我们的例子中是两个月)和预测频率(每天)。然后我们用之前创建的Prophet模型和未来数据框进行预测。非常简单!未来数据框包含了未来两个月内的预估居民使用电量。我们可以用一个图表来进行可视化预测展示:图中的黑点代表了实际值,蓝线则代表了预测值,而浅蓝色阴影区域代表不确定性。如下图所示,不确定性区域随着我们在之后的进一步变化而扩大,因为初始的不确定性随着时间的推移而扩散和增多。Prophet还可以允许我们轻松地对整体趋势和组件模式进行可视化展示:每年的模式很有趣,因为它看起来表明了居民的电量使用在秋季和冬季会增加,而在春季和夏季则会减少。直观地说,这正是我们期望要看到的。从每周的趋势来看,周日的使用量似乎比一周中其它时间都要多。最后,总体的趋势表明,使用量增长了一年,然后才缓慢地下降。需要进行进一步的调查来解释这一趋势。在下一篇文章中,我们将尝试找出是否与天气有关。LSTM(Long Short-Term Memory,长短期记忆网络)预测LSTM循环神经网络具有学习长序列观测值的前景。博客文章《了解LSTM网络》,在以一种易于理解的方式来解释底层复杂性方面做的非常出色。以下是一个描述LSTM内部单元体系结构的示意图:LSTM似乎非常适合于对时间序列的预测。让我们再次使用一下每日汇总的数据。LSTM对输入数据的大小很敏感,特别是当使用Sigmoid或Tanh这两个激活函数的时候。通常,将数据重新调整到[0,1]或[-1,1]这个范围是一个不错的实践,也称为规范化。我们可以使用scikit-learn库中的MinMaxScaler预处理类来轻松地规范化数据集。现在我们可以将已排好序的数据集拆分为训练数据集和测试数据集。下面的代码计算出了分割点的索引,并将数据拆分为多个训练数据集,其中80%的观测值可用于训练模型,剩下的20%用于测试模型。我们可以定义一个函数来创建一个新的数据集,并使用这个函数来准备用于建模的训练数据集和测试数据集。LSTM网络要求输入的数据以如下的形式提供特定的数组结构:[样本、时间间隔、特征]。数据目前都规范成了[样本,特征]的形式,我们正在为每个样本设计两个时间间隔。可以将准备好的分别用于训练和测试的输入数据转换为所期望的结构,如下所示:就是这样,现在已经准备好为示例设计和设置LSTM网络了。从下面的损失图可以看出,该模型在训练数据集和测试数据集上都具有可比较的表现。在下图中,我们看到LSTM在拟合测试数据集方面做得非常好。聚类(Clustering)最后,我们还可以使用示例的数据进行聚类。执行聚类有很多不同的方式,但一种方式是按结构层次来形成聚类。你可以通过两种方式形成一个层次结构:从顶部开始来拆分,或从底部开始来合并。我决定先看看后者。让我们从数据开始,只需简单地导入原始数据,并为某年中的某日和某日中的某一小时添加两列。Linkage和Dendrogramslinkage函数根据对象的相似性,将距离信息和对象对分组放入聚类中。这些新形成的聚类随后相互连接,以创建更大的聚类。这个过程将会进行迭代,直到在原始数据集中的所有对象在层次树中都连接在了一起。对数据进行聚类:完成了!!!这难道不是很简单吗?当然很简单了,但是上面代码中的“ward”在那里意味着什么呢?这实际上是如何执行的?正如scipy linkage文档上告诉我们的那样,“ward”是可以用来计算新形成的聚类之间距离的一个方法。关键字“ward”让linkage函数使用Ward方差最小化算法。其它常见的linkage方法,如single、complete、average,还有不同的距离度量标准,如euclidean、manhattan、hamming、cosine,如果你想玩玩的话也可以使用一下。现在让我们来看看这个称为dendogram的分层聚类图。dendogram图是聚类的层次图,其中那些条形的长度表示到下一个聚类中心的距离。如果这是你第一次看到dendrogram图,那看起来挺复杂的,但是别担心,让我们把它分解来看:在x轴上可以看到一些标签,如果你没有指定任何其它内容,那么这些标签就是X上样本的索引;·在y轴上,你可以看到那些距离长度(在我们的例子中是ward方法);水平线是聚类的合并;那些垂线告诉你哪些聚类或者标签是合并的一部分,从而形成了新的聚类;水平线的高度是用来表示需要被“桥接”以形成新聚类的距离;即使有解释说明,之前的dendogram图看起来仍然不明显。我们可以减少一点,以便能更好地查看数据。建议查找聚类文档以便能了解更多内容,并尝试使用不同的参数。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 8, 2019 · 1 min · jiezi

SQL 难点解决:序列生成

1、 生成连续整数序列MySQL8: with recursive t(n) as (select 1union allselect n+1 from t where n<7)select * from t;Oracle:select level nfrom dual connect by level<=7;集算器 SPL:A1:构造从 1 到 7 的整数序列示例 1:百鸡问题,鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、母、雏各几MySQL8: with recursive jg(n) as (select 1 union all select n+1 from jg where n<100/5),jm(n) as (select 1 union all select n+1 from jm where n<100/3),jc(n) as (select 3 union all select n+3 from jc where n<98)select jg.n jw, jm.n jm, jc.n jcfrom jg cross join jm cross join jcwhere jg.n5+jm.n3+jc.n/3=100 and jg.n+jm.n+jc.n=100集算器 SPL:A1:构造1到20的整数序列A2:构造1到33的整数序列A3:构造1到99且步长为3的整数序列A4:创建数据结构为(jw,jm,jc)的序表A5:对A1、A2、A3的数据进行嵌套循环,若满足于A1成员+A2成员+A3成员==100且A1成员5+A2成员3+A3成员/3==100则追加到A4序表中示例2:将指定列中冒号分隔的串划分成多行Oracle:with t(k,f) as (select 1 , ‘a1:a2:a3’ from dualunion all select 2, ‘b1:b2’ from dual),t1 as (select k,f, length(f)-length(replace(f,’:’,’’))+1 cnt from t),t2 as (select level n from dual connect by level<=(select max(cnt) from t1)),t3 as (select t1.k, t1.f, n, cnt,case when n=1 then 1 else instr(f,’:’,1,n-1)+1 end p1, case when n=cnt then length(f)+1 else instr(f,’:’,1,n) end p2from t1 join t2 on t2.n<=t1.cnt)select k,substr(f,p1,p2-p1) f from t3 order by k;集算器 SPL:A1:创建数据结构为(k,f)的序表,并追加2条记录(1, “a1:a2:a3)和(2,”b1:b2”)A2:将A1的字段f用冒号划分成序列并重新赋值给字段fA3:针对A1每条记录构造数据结构为(k,f)的序表,并根据字段f中成员构造记录(A1.k,f成员)追加到此序表中2、 生成连续日期序列MySQL8:with recursivet(d) as (select date'2018-10-03’union allselect d+1 from t where d<date'2018-10-09’)select d,dayofweek(d) w from t;集算器 SPL:A1:生成2018-10-03到2018-10-09的日期序列示例:列出2015-01-03到2015-01-07每天的销量汇总MySQL8:with recursivet(d,v) as (select date'2015-01-04’,30union all select date'2015-01-06’,50union all select date'2015-01-07’,50union all select date'2015-01-03’,40union all select date'2015-01-04’, 80),s(d) as (select date'2015-01-03’union allselect d+1 from s where d<date'2015-01-07’)select s.d, sum(t.v) vfrom s left join t on s.d=t.dgroup by s.d;集算器 SPL:A4:A2中记录按字段d的值对齐到A3A5:根据A4和A3对位构造统计后的序表3、 生成连续的工作日(不包含周六周日)序列MySQL8:with recursivet(d) as (select date'2018-10-03’union allselect d+1 from t where d<date'2018-10-09’)select d,dayofweek(d) w from twhere dayofweek(d)<=5;集算器 SPL:A1:构造从2018-10-03到2018-10-09不包含周六周日的日期序列A2:根据A1构造日期及相应周几的序表4、 根据序列生成表MySQL8:with recursive t1(n) as (select 1 union all select n+1 from t1 where n<14),t2(n, name) as (select n, concat(‘a’,n) name from t1)select max(if(n%4=1, name, null)) f1,max(if(n%4=2, name, null)) f2,max(if(n%4=3, name, null)) f3,max(if(n%4=0, name, null)) f4from t2group by floor((n+3)/4);集算器 SPL: ...

December 29, 2018 · 2 min · jiezi

一文了解自然语言处理神经史(下)

摘要: 越来越火的NLP到底经历了什么?2014年-序列到序列模型2014年,Sutskever等人提出序列到序列学习,一种通过神经网络将一个序列映射到另一个序列的通用框架。在该框架中,编码器神经网络逐个符号地处理句子并将其压缩成矢量表示; 然后,解码器神经网络基于编码器状态逐个符号地预测输出符号,在每个步骤中将先前预测的符号作为输入,如下面的图8所示。机器翻译成了这个框架的杀手级应用。2016年,谷歌宣布开始用NMT模型替换其基于单片短语的MT模型(Wu et al.,2016)。根据Jeff Dean的说法,这意味着用500线性神经网络模型替换500,000行基于短语的MT代码。由于其灵活性,该框架现在是自然语言生成任务的首选框架,不同的模型承担编码器和解码器的角色。重要的是,解码器模型不仅可以以序列为条件,而且可以以任意表示为条件。这使得例如基于图像生成标题(Vinyals等人,2015)(如下面的图9中可见),基于表格的文本(Lebret等人,2016),以及基于源代码更改的描述(Loyola等,2017),以及许多其他应用程序。序列到序列学习甚至可以应用于NLP中常见的结构化预测任务,其中NLP输出具有特定结构。简单地说,输出是线性化的,如下面图10中的consituency解析所示。神经网络已经证明了在给予consituency解析的足够数量的训练数据(Vinyals等,2015)和命名实体识别(Gillick等,2016)等的情况下,能够直接学习产生这种线性化输出的能力。用于序列和解码器的编码器通常基于RNN,但是也可以使用其他模型类型,最新的架构主要来自作为序列到序列架构的培养皿MT的工作。最近的模型是卷积编码器(Kalchbrenner等,2016; Gehring等,2017),变换器(Vaswani等,2017),将在下一个部分讨论,以及LSTM和变压器的组合(Chen等,2018)。2015-注意力注意力(Bahdanau等,2015)NMT)的核心创新之一,也是使NMT模型优于基于经典短语的MT系统的关键思想。序列到序列学习的主要瓶颈是它需要将源序列的整个内容压缩成固定大小的矢量。注意力通过允许解码器回顾源序列隐藏状态来减轻这种情况,然后将其作为加权平均值提供给解码器的附加输入,如下面的图11所示。注意力有不同的形式(Luong等,2015)在这里查看简要概述。 注意力广泛适用并且可能对任何需要根据输入的某些部分做出决策的任务有用。它已被应用于consituency解析(Vinyals等,2015),阅读理解(Hermann等,2015)和一次性学习(Vinyals等,2016)等。甚至输入不需要是序列,但可以包括其他表示,如图像字幕的情况(Xu et al.,2015),可以在下面的图12中看到。注意力的一个有用的副作用是,通过根据注意力量检查输入的哪些部分与特定输出相关。注意力也不仅限于查看输入序列;自-注意力可用于查看句子或文档中的周围单词以获得更多上下文敏感的单词表示。多层自-注意力是Transformer架构的核心(Vaswani等,2017),这是目前最先进的NMT模型。2015-基于记忆的网络注意力可以看作是模糊记忆的一种形式,其中记忆由模型的过去隐藏状态组成,模型选择从记忆中所检索的内容。有关注意事项及其与记忆关联的更详细概述,请查看此文章。许多具有更明确记忆的模型已经被提出,它们有不同的变体,例如神经网络图灵机(Graves et al,2014),记忆网络(Weston et al.,2015)[70]和端到端的记忆网络(Sukhbaatar et al.,2015),动态记忆网络( Kumar等,2015),可微神经计算机(Graves等,2016)和递归实体网络(Henaff等,2017)。通常基于与当前状态的相似性来访问内存,类似于注意力,并且通常可以写入和读取存储器,模型在实现和利用内存方面有所不同。例如,端到端记忆网络多次处理输入并更新内存以启用多个推理步骤。神经图灵机还具有基于位置的寻址,允许它们学习简单的计算机程序,如排序。基于记忆的模型通常应用于其中保留较长时间跨度信息的有用任务,例如语言建模和阅读理解。存储器的概念非常通用:知识库或表可以用作存储器,而存储器也可以基于整个输入或其特定部分来填充。2018年 - 预训练语言模型预训练的词嵌入与上下文无关,而且仅用于初始化模型中的第一层。最近几个月,一系列监督任务被用于预训练神经网络(Conneau等,2017; McCann等,2017; Subramanian等,2018)。相比之下,语言模型只需要未标记的文本; 因此,训练可以扩展到数十亿个tokens,新领域和新语言。 2015年首次提出了预训练语言模型(Dai&Le,2015); 直到最近,它们才被证明对各种各样的任务都有益。 语言模型嵌入可以用作目标模型中的特征(Peters等,2018),或者可以对目标任务数据微调语言模型(Ramachandran等,2017; Howard&Ruder,2018)。添加语言模型嵌入比许多任务的最新技术有了很大的改进,如下面的图13所示。预训练语言模型可以用更少的数据进行学习,由于语言模型仅需要未标记的数据,因此对于标记数据稀缺的低资源语言尤其有用。有关预训练语言模型的更多信息,请参阅本文。其他里程碑基于字符的表示:在字符上使用CNN或LSTM来获得基于字符的词表示是相当普遍的,特别是对于形态学丰富的语言和形态信息很重要或具有许多未知单词的任务。据我所知,基于字符的表示首先用于序列标记(Lample等,2016; Plank等,2016)。基于字符的表示减少了必须以增加计算成本处理固定词汇表的需要,并且能够实现诸如完全基于字符的NMT之类的应用(Ling等人,2016; Lee等人,2017)。对抗性学习:对抗性方法已经在风暴中占据了ML的领域,并且在NLP中也以不同的形式使用。对抗性示例越来越广泛地被广泛使用,不仅作为探测模型和理解其失败案例的工具,而且还使它们更加具有鲁棒性(Jia&Liang,2017)。对抗性训练:域对抗性损失(Ganin等,2016; Kim等,2017)是可以同样使模型更加健壮的有用的正规化形式。生成对抗网络(GAN)对于自然语言生成来说还不是太有效(Semeniuta等,2018),但是例如在匹配分布时是有用的(Conneau等,2018)。强化学习:强化学习已经被证明对于具有时间依赖性的任务是有用的,例如在训练期间选择数据(Fang等,2017; Wu等,2018)和建模对话(Liu等,2018)。RL对于直接优化诸如ROUGE或BLEU之类的非可微结束度量而不是优化替代损失(例如摘要中的交叉熵(Paulus等,2018; Celikyilmaz等,2018)和机器翻译也是有效的。(Ranzato等人,2016),反向强化学习在犒赏太复杂而无法指定的环境中可能是有用的,例如视觉叙事(Wang et al。,2018)。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

November 29, 2018 · 1 min · jiezi

一文了解自然语言处理神经史(上)

摘要: 越来越火的NLP到底经历了什么?本文扩展了Herman Kamper和我在2018年深度学习Indaba组织的自然语言处理前沿课程。整个课程的幻灯片都可以在这里找到,这篇文章将主要讨论NLP中基于神经网络方法的近期进展。免责声明:本文尝试将大约15年NLP的发展历程浓缩为今天最相关的八个里程碑,因此遗漏了许多相关和重要的发展。特别是,它严重偏向于当前的神经方法,这可能给人留下此期间没有其他有影响力方法的错误影响。2001年-神经语言模型语言建模是在给定前面的单词的情况下预测文本中的下一个单词的任务。 它可能是最简单的语言处理任务,具有实际应用,如智能键盘和电子邮件响应建议(Kannan et al.,2016)。语言建模有着丰富的历史。基于n-gram的经典方法采用平滑处理看不见的n-gram(Kneser&Ney,1995)。Bengio等人于2001年提出了第一种神经语言模型,一种前馈神经网络,如下图1所示。该模型把n个可以在表C中查找的先前单词向量表示作为输入。现在,这种向量被称为词嵌入。这些词嵌入被连接并送入隐藏层,然后将其输出提供给softmax层。想要了解更多该模型的信息,请查看此文章。最近,前馈神经网络已被用于语言建模的递归神经网络(RNN; Mikolov等人,2010)和长短期记忆网络(LSTM; Graves,2013)所取代。近年来已经提出了许多经典LSTM的新语言扩展模型(请参阅此页面以获得概述)。尽管有这些发展,但经典的LSTM仍然是一个强大的基线(Melis等,2018)。即使Bengio等人的经典前馈神经网络在某些环境中也与更复杂的模型竞争,但这些通常只学会考虑最近的词(Daniluk等,2017)。如何理解这些语言模型捕获的信息是一个活跃的研究领域(Kuncoro等,2018; Blevins等,2018)。语言建模通常是应用RNN时的首选训练场,并成功捕捉到了想象力,许多人通过Andrej的博客文章开始了解。语言建模是无监督学习的一种形式,Yann LeCun也将预测性学习作为获取常识的先决条件(参见NIPS 2016的Cake幻灯片)。 关于语言建模最显著的方面可能是,尽管它很简单,但它是本文讨论的许多后期进展的核心:词嵌入:word2vec的目标是简化语言建模;序列到序列模型:这种模型通过一次预测一个词来生成输出序列;预训练语言模型:这些方法使用语言模型中的表示来进行迁移学习;这反过来意味着NLP中许多最重要的最新进展减少为一种语言建模形式。 为了做“真正的”自然语言理解,仅仅从原始形式的文本中学习可能是不够的,我们将需要新的方法和模型。2008-多任务学习多任务学习是在多个任务上训练的模型之间共享参数的一般方法。在神经网络中,这可以通过绑定不同层的权重来轻松实现。多任务学习的想法在1993年由Rich Caruana首次提出,并应用于道路跟踪和肺炎预测(Caruana,1998)。直观地说,多任务学习鼓励模型学习对许多任务有用的表示。特别对于学习一般的低级表示,集中模型的注意力或在有限量的训练数据的设置中特别有用。有关多任务学习的更全面概述,请查看此文章。Collobert和Weston于2008年首次将多任务学习应用于NLP的神经网络。 在他们的模型中,查找表(或词嵌入矩阵)在两个在不同任务上训练的模型之间共享,如下面的图2所示。共享词嵌入使模型能够在词嵌入矩阵中协作和共享一般的低级信息,这通常构成模型中最大数量的参数。Collobert和Weston在2008年的论文中证明了它在多任务学习中的应用,它引领了诸如预训练词嵌入和使用卷积神经网络(CNN)之类的思想,这些思想仅在过去几年中被广泛采用。它赢得了ICML 2018的时间考验奖(参见此时的时间考验奖论文)。多任务学习现在用于各种NLP任务,并且利用现有或“人工”任务已成为NLP指令集中的有用工具。有关不同附加任务的概述,请查看此文章。虽然通常预先定义参数的共享,但是在优化过程期间也可以学习不同的共享模式(Ruder等,2017)。随着模型越来越多地在多项任务中被评估来评估其泛化能力,多任务学习越来越重要,最近提出了多任务学习的专用基准(Wang et al,2018; McCann et al,2018)。2013-词嵌入文本的稀疏向量表示,即所谓的词袋模型,在NLP中具有悠久的历史。正如我们在上面所看到的,早在2001年就已经使用了词或词嵌入的密集向量表示。 Mikolov等人在2013年提出的主要创新,是通过移动隐藏层和近似目标来使这些词嵌入的训练更有效率。虽然这些变化本质上很简单,但它们与高效的word2vec一起实现了大规模的词嵌入训练。Word2vec有两种模式,可以在下面的图3中看到:连续的词袋(CBOW)和skip-gram。它们的目标不同:一个基于周围的词预测中心词,而另一个则相反。虽然这些嵌入在概念上与使用前馈神经网络学习的嵌入技术没有什么不同,但是对非常大的语料库的训练使它们能够捕获诸如性别,动词时态和国家–首都关系之类的词之间的某些关系,由图4可知:这些关系及其背后的意义引发了对嵌入词的初步兴趣,许多研究调查了这些线性关系的起源(Arora等,2016; Mimno&Thompson,2017; Antoniak&Mimno,2018; Wendlandt等,2018))。然而,使用预训练嵌入作为初始化的固定词嵌入,把它作为当前NLP的主要内容被证明可以提高各种下游任务的性能。虽然捕获的关系word2vec具有直观且几乎神奇的性能,但后来的研究表明word2vec没有任何固有的特殊性:通过矩阵分解也可以学习词嵌入(Pennington等,2014; Levy&Goldberg,2014)和通过适当的调整,经典的矩阵分解方法(如SVD和LSA)可以获得类似的结果(Levy等,2015)。从那时起,许多工作已经开始探索词嵌入的不同方面,可以通过这篇文章了解一些趋势和未来方向。尽管有许多发展,但word2ve仍然是如今被广泛使用的一种流行的选择。Word2vec的范围甚至超出了词级别:带有负抽样的skip-gram,一个基于本地环境学习嵌入的方便目标,已被应用于学习句子的表示(Mikolov&Le,2014; Kiros et al.,2015)-甚至超越NLP,应用到网络(Grover&Leskovec,2016)和生物序列(Asgari&Mofrad,2015)等。一个特别令人兴奋的方向是将不同语言的词嵌入投影到同一空间中以实现(零射击)跨语言转移。越来越有可能以完全无监督的方式(至少对于类似语言)学习良好的投影,这开启了低资源语言和无监督机器翻译的应用(Lample等,2018; Artetxe等,2018)。请查看(Ruder等,2018)的概述。2013年-NLP的神经网络2013年和2014年是神经网络模型开始应用于NLP的标志年份。三种主要类型的神经网络被广泛使用:递归神经网络、卷积神经网络、循环神经网络。递归神经网络(RNN)是处理NLP中普遍存在的动态输入序列问题的明显选择。 Vanilla RNNs(Elman,1990)很快被经典的长短期记忆网络(Hochreiter&Schmidhuber,1997)所取代,后者证明其对消失和爆炸梯度问题更具弹性。在2013年之前,RNN仍然被认为很难训练,Ilya Sutskever的博士论文是改变这种现状的一个关键例子。LSTM细胞可视化可以在下面的图5中看到。双向LSTM(Graves等,2013)通常用于处理左右上下文。随着卷积神经网络(CNN)被广泛用于计算机视觉,它们也开始应用于文本(Kalchbrenner等,2014; Kim等,2014)。用于文本的卷积神经网络仅在两个维度上操作,其中滤波器仅需要沿时间维度移动。下面的图6显示了NLP中使用的典型CNN。卷积神经网络的一个优点是它们比RNN更可并行化,因为每个时间步的状态仅取决于本地环境(通过卷积运算)而不是像RNN取决过去所有状态。CNN可以使用扩张卷积扩展到更宽的感受野,以捕捉更广泛的背景(Kalchbrenner等2016)。 CNN和LSTM也可以组合和堆叠,并且可以使用卷积来加速LSTM。RNN和CNN都将语言视为一个序列。然而,从语言学的角度来看,语言本质上是等级的:单词被组成高阶短语和子句它们本身可以根据一组生产规则递归地组合。将句子视为树而不是序列的语言启发思想产生了递归神经网络,这可以在下面的图7中看到:与从左到右或从右到左处理句子的RNN相比,递归神经网络从下到上构建序列的表示。在树的每个节点处,通过组合子节点的表示来计算新表示。由于树也可以被视为在RNN上施加不同的处理顺序,因此LSTM自然地扩展到树。RNN和LSTM不仅仅可以被扩展来使用分层结构,而且不仅可以根据本地语言学习词嵌入,而且可以基于语法背景来学习词嵌入(Levy&Goldberg,2014);语言模型可以基于句法堆栈生成单词(Dyer et al。,2016); 图形卷积神经网络可以在树上运行(Bastings等,2017)。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。

November 29, 2018 · 1 min · jiezi

阿里AI设计师一秒出图,小撒连连惊呼,真相是...

近期,央视《机智过人》的舞台上来了位“三超设计师”——设计能力超强;出图能力超快;抗压能力超强,成功迷惑嘉宾和现场观众,更让撒贝宁出错三连。节目一开场,这位“设计师”就为现场嘉宾:主持人撒贝宁、演员韩雪、神经科学家鲁白生成了三张独具特色的海报。几乎是说话的瞬间,海报立即生成,出图速度之快让撒贝宁惊呼“秒完”。这位设计师正是阿里巴巴研制的AI设计师——鹿班。鹿班是为解放人类平面设计师而生,它学习了五百万张人类设计作品,现在它每秒能做八千次设计。自从2016年上线至今,鹿班已经完成了十亿次海报制作,是全球首位大规模投入使用的人工智能平面设计师。节目中,鹿班将接受设计领域的两轮检验,如果鹿班的作品被现场观众成功找出,则认为鹿班通过检验。究竟AI能否在设计领域达到人类水平?接下来,我们一起走进检验场。第一轮挑战中,鹿班与一次成稿率在80%以上的设计师、从业十二年的资深设计师等三位同台竞技,各自设计一张以“汽车卓越加速性能”为主题的商业海报。下图即四位设计师的设计成图,大家不妨来猜一猜哪幅是鹿班的作品。根据现场观众投票,多数观众认为4号作品出自鹿班之手。让观众出乎意料的是2号才是鹿班的创作,这个结果让神经学家鲁白大呼“不服气”。不信?眼见为实!接下来,战况升级。中央美术学院院长范迪安教授带来画家与服装设计师来和鹿班同台创作,为《孙子兵法》这本书设计封面。面对设计难度升级,鹿班能否成功应对?我们马上揭晓鹿班和两位人类设计师为《孙子兵法》设计的封面的作品:以上图片中有三幅作品,其中哪一张是鹿班的设计?到底观众们有没有猜对?不急,我们先请阿里巴巴资深技术专家星瞳为我们揭秘鹿班背后的技术。使用场景视觉生成引擎的使用场景大致可抽象成下图。以显式输入而言,用户可以输入标签需要的风格、色彩、构图等,或者输入一个例子,或者进行一些交互的输入。除显式输入之外还可以有隐式输入,比如人群信息、场景信息、上下文信息等。总的来说,输入可以是千变万化的,但通过规范化之后就会减少变化,使得生成过程可控,输出质量可控。对视觉生成引擎来说,它要求输入是规范化的。但在输入前,可以加入各种交互方式,如自然语言处理,语音识别等,将其转化成规范化输入。最后输出结构化信息或可视成图。技术框架和生产流程其技术框架如下图左侧。首先对视觉内容进行结构化理解,如分类、量化、特征化。其次通过一系列学习、决策变成满足用户需求的结构化信息即数据,最后将数据转化成可视的图像或视频。这一框架依赖于大量的现有数据。其核心是一个设计内核。同时,引入效用循环,利用使用后的反馈来不断迭代和改进系统。其生产流程分成六个步骤,如下图右侧所示。首先用户提出需求,将需求特征化转变成系统可以理解的结构化信息。其次将信息进行规划得到草图。有了粗略的草图后再将其转变成相对更精确的图,然后调整细节,最后通过数据可视化形成最终的图。当然其中还有很多的trick,以及各部分的优化。关键算法下面介绍一些关键算法。我们希望基于下图最左的耐克鞋生成最右的图。先通过规划器得到草图,再通过强化学习获得相对细致的结果,再通过对抗学习及渲染算法得到图片,再通过评估器进行评估,最后形成业务闭环,其中还会有一些基础的能力,包含更强的联合特征(非普通 CNN特征)及多维度检索算法等。基本上,处理的第一步是将图片中的信息结构化,这也是与现有的识别理解技术结合最紧密的地方。其中的难点和重点包括,对图像中多目标的识别、遮挡和互包含情况如何得到分割的信息等,下图只是个简单的示例。有了结构化信息之后,需要对信息进行量化。可以量化成特征或量化图。量化过程中会包含很多信息,比如主题风格、布局配色、元素种类、量化空间等。有了这些信息后可以在主题、种类、风格、视觉特征大小位置上,量化成各种码,用相对有限的特征来表达无限的图。下一步是通过用户的输入,得到一个相对粗略的结果即草图。目前主要使用的是深度序列学习。从图像角度,首先选定一个点的像素颜色再选择位置,再迭代进行操作,最后形成一张图。规划器模拟的就是这个过程。本质上预测过程是一棵树,当然也可以拆成一条条路径。为了简化,可以分成几步进行,比如空间序列,视觉序列。最后形成量化特征模型,主要应用的是LSTM模型。它把设计的过程转化成基于递归、循环的过程。得到草图后,利用行动器将草图细化。如果将图中的每个元素看作一个Agent,那么它将有若干个可选的行动空间。假设一张图中有20个元素,每个元素在视觉上有多种可选的行动空间,由其组合成的可选行动空间非常庞大。我们有很多trick可以解决这一问题,比如在空间上,只允许在有限范围内进行变动,且行动方向有序,即状态有序,行动有限。下一步是如何衡量结果的好坏。图像的评估相对比较主观,主要可以从美学和效果两方面来评估。美学角度可以包括是否对齐、色系搭配是否合理、有无遮挡这些较低级别的判断标准,以及较高级的,比如风格是否一致,是否切合主题。从效果上,产品投放后是否会在点击率等方面实现提升。最后将多个指标形成对应权重并形成多个DeepLR联合模型。但在衡量结果之前,需要形成像素级别可见的图。这里有以下几种构造器分类,包括临摹、迁移、创造、搭配与生成。前面介绍了,如何通过用户的需求形成可见的图。后续还需要进行投放和反馈并进行优化,形成效用外循环。这样才能使得系统效用不断得到提升,形成一个在线闭环,这也是智能设计相对设计师的一大优势。从技术角度来说,鹿班可以满足海量无选择客户的需求。相信在未来,可以做到“所想,即所见”。节目的最后,撒贝宁、韩雪、鲁白纷纷为鹿班站台,鹿班也因此成功入选 “2018智能先锋”。本文作者:厉害了!阅读原文本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

November 26, 2018 · 1 min · jiezi

简易RPC框架:序列化机制

概述在上一篇文章《简易RPC框架:基于 netty 的协议编解码》中谈到对于协议的 decode 和 encode,在谈 decode 之前,必须先要知道 encode 的过程是什么,它把什么东西转化成了二进制协议。由于我们还未谈到具体的 RPC 调用机制,因此暂且认为 encode 就是把一个包含了调用信息的 Java 对象,从 client 经过序列化,变成一串二进制流,发送到了 server 端。这里需要明确的是,encode 的职责是拼协议,它不负责序列化,同样,decode 只是把整个二进制报文分割,哪部分是报文头,哪部分是报文体,诚然,报文体就是被序列化成二进制流的一个 Java 对象。对于调用方来说,先将调用信息封装成一个 Java 对象,经过序列化后形成二进制流,再经过 encode 阶段,拼接成一个完整的遵守我们定好的协议的报文。对于被调用方来说,则是收取完整的报文,在 decode 阶段将报文中的报文头,报文体分割出来,在序列化阶段将报文体反序列化为一个 Java 对象,从而获得调用信息。本文探讨序列化机制。基于 netty handler由于这个 RPC 框架基于 netty 实现,因此序列化机制其实体现在了 netty 的 pipeline 上的 handler 上。例如对于调用方,它需要在 pipeline 上加上一个 序列化 encode handler,用来序列化发出去的请求,同时需要加上一个反序列化的 decode handler, 以便反序列化调用结果。如下所示: protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new ProtocolEncoder()) .addLast(new ProtocolDecoder()) .addLast(new SerializationHandler(serialization)) .addLast(new DeserializationHandler(serialization)); }其中的 SerializationHandler 和 DeserializationHandler 就是上文提到的序列化 encode handler 和反序列化 decode handler。同样,对于被调用方来说,它也需要这两个handler,与调用方的 handler 编排顺序一致。其中,serialization 这个参数的对象代表具体的序列化机制策略。序列化机制上文中,SerializationHandler 和 DeserializationHandler 这两个对象都需要一个 serialization 对象作为参数,它是这么定义的:private ISerialization serialization = SerializationFactory.getSerialization(ServerDefaults.DEFAULT_SERIALIZATION_TYPE);采用工厂模式来创建具体的序列化机制:/** * 序列化工厂 * * @author beanlam * @version 1.0 /public class SerializationFactory { private SerializationFactory() { } public static ISerialization getSerialization(SerializationType type) { if (type == SerializationType.JDK) { return new JdkSerialization(); } return new HessianSerialization(); }}这里暂时只支持 JDK 原生序列化 和 基于 Hessian 的序列化机制,日后若有其他效率更高更适合的序列化机制,则可以在工厂类中进行添加。这里的 hessian 序列化是从 dubbo 中剥离出来的一块代码,感兴趣可以从 dubbo 的源码中的 com.caucho.hessian 包中获得。以 HessianSerialization 为例:/* * @author beanlam * @version 1.0 */public class HessianSerialization implements ISerialization { private ISerializer serializer = new HessianSerializer(); private IDeserializer deserializer = new HessianDeserializer(); @Override public ISerializer getSerializer() { return serializer; } @Override public IDeserializer getDeserializer() { return deserializer; } @Override public boolean accept(Class<?> clazz) { return Serializable.class.isAssignableFrom(clazz); }}根据 Hessian 的 API, 分别返回一个 hessian 的序列化器和反序列化器即可。 ...

November 11, 2018 · 1 min · jiezi