基本功 | Litho的使用及原理剖析

1. 什么是Litho?

Litho是Facebook推出的一套高效构建Android UI的声明式框架,主要目的是提升RecyclerView复杂列表的滑动性能和降低内存占用。下面是Litho官网的介绍:

Litho is a declarative framework for building efficient user interfaces (UI) on Android. It allows you to write highly-optimized Android views through a simple functional API based on Java annotations. It was primarily built to implement complex scrollable UIs based on RecyclerView. With Litho, you build your UI in terms of components instead of interacting directly with traditional Android views. A component is essentially a function that takes immutable inputs, called props, and returns a component hierarchy describing your user interface.

Litho是高效构建Android UI的声明式框架,通过注解API创建高优的Android视图,非常适用于基于Recyclerview的复杂滚动列表。Litho使用一系列组件构建视图,代替了Android传统视图交互方式。组件本质上是一个函数,它接受名为Props的不可变输入,并返回描述用户界面的组件层次结构。

Litho是一套完全不同于传统Android的UI框架,它继承了Facebook一向大胆创新的风格,突破性地在Android上实现了React风格的UI框架。架构图如下:

应用层:上层Android应用接入层。

规范层(API):允许用户使用声明式的API(注解)来构建符合Flexbox规范的布局。

布局层:Litho使用可挂载组件、布局组件和Flexbox组件来构建布局,其中可挂载组件和布局组件允许用户使用规范来定义,各个组件的具体用法下面的组件规范中会详细介绍。在Litho中每一个组件都是一个独立的功能模块。Litho的组件和React的组件相类似,也具有属性和状态的概念,通过状态的变更来控制组件的展示样式。

布局测量:Litho使用Yoga来完成组件布局的异步或同步(可根据场景定制)测量和计算,实现了布局的扁平化。

布局渲染:Litho不仅支持使用View来渲染视图,还可以使用更轻量的Drawable来渲染视图。Litho实现了大量使用Drawable来渲染的基础组件,可以进一步拍平布局。

除了上面提到的扁平化布局,Litho还实现了布局的细粒度复用和异步计算布局的能力,对于这些功能的实现在Litho的特性及原理剖析中详细介绍。下面先介绍一下大家比较关心的Litho使用方法。

2. Litho的使用

Litho的使用方式相比于传统的Android来说有些另类,它抛弃了通过XML定义布局的方式,采用声明式的组件在Java中构建布局。

2.1 Litho和原生Android在使用上的区别

Android传统布局:首先在资源文件res/layout目录下定义布局文件xx.xml,然后在Activity或Fragment中引用布局文件生成视图,示例如下:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World"android:textAlignment="center"android:textColor="#666666"android:textSize="40dp" />
public class MainActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.helloworld);}
}

Litho布局:Litho抛弃了Android原生的布局方式,通过组件方式构建布局生成视图,示例如下:

public class MainActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ComponentContext context = new ComponentContext(this);final Text.Builder builder = Text.create(context);final Component = builder.text("Hello World").textSizeDip(40).textColor(Color.parseColor("#666666")).textAlignment(Layout.Alignment.ALIGN_CENTER).build();LithoView view = LithoView.create(context, component);setContentView(view);}
}

2.2 Litho自定义视图

Litho中的视图单元叫做Component,可以直观的翻译为“组件”,它的设计理念来自于React组件化的思想。每个组件持有描述一个视图单元所必须的属性和状态,用于视图布局的计算工作。视图最终的绘制工作是由组件指定的绘制单元(View或者Drawable)来完成的。

Litho组件的创建方式也和原生View的创建方式有着很大的区别。Litho使用注解定义了一系列的规范,我们需要使用Litho的注解来定义自己的组件生成规则,最终由Litho在编译期自动编译生成真正的组件。

2.2.1 组件规范

Litho提供了两种类型的组件规范,分别是Layout Spec规范和Mount Spec规范。下面分别介绍两种规范的使用方式:

Layout Spec规范:用于生成布局类型组件的规范,布局组件在逻辑上等同于Android中的ViewGroup,用于组织其他组件构成一个布局。它要求我们必须使用@LayoutSpec注解来注明,并实现一个标注了@OnCreateLayout注解的方法。示例如下:

  @LayoutSpecclass HelloComponentSpec {@OnCreateLayoutstatic Component onCreateLayout(ComponentContext c, @Prop String name) {return Column.create(c).child(Text.create(c).text("Hello, " + name).textSizeRes(R.dimen.my_text_size).textColor(Color.BLACK).paddingDip(ALL, 10).build()).child(Image.create(c).drawableRes(R.drawable.welcome).scaleType(ImageView.ScaleType.CENTER_CROP).build()).build();}}

最终Litho会在编译时生成一个名为HelloComponent的组件。

  public final class HelloComponent extends Component {@Prop(resType = ResType.NONE,optional = false) String name;private HelloComponent() {super();}@Overrideprotected Component onCreateLayout(ComponentContext c) {return (Component) HelloComponentSpec.onCreateLayout((ComponentContext) c, (String) name);}...public static Builder create(ComponentContext context, int defStyleAttr, int defStyleRes) {Builder builder = sBuilderPool.acquire();if (builder == null) {builder = new Builder();}HelloComponent instance = new HelloComponent();builder.init(context, defStyleAttr, defStyleRes, instance);return builder;}public static class Builder extends Component.Builder<Builder> {private static final String[] REQUIRED_PROPS_NAMES = new String[] {"name"};private static final int REQUIRED_PROPS_COUNT = 1;HelloComponent mHelloComponent;...public Builder name(String name) {this.mHelloComponent.name = name;mRequired.set(0);return this;}@Overridepublic HelloComponent build() {checkArgs(REQUIRED_PROPS_COUNT, mRequired, REQUIRED_PROPS_NAMES);HelloComponent helloComponentRef = mHelloComponent;release();return helloComponentRef;}}}

Mount Spec规范:用来生成可挂载类型组件的规范,用来生成渲染具体View或者Drawable的组件。同样,它必须使用@MountSpec注解来标注,并至少实现一个标注了@onCreateMountContent的方法。Mount Spec相比于Layout Spec更复杂一些,它拥有自己的生命周期:

  • @OnPrepare,准备阶段,进行一些初始化操作。
  • @OnMeasure,负责布局的计算。
  • @OnBoundsDefined,在布局计算完成后挂载视图前做一些操作。
  • @OnCreateMountContent,创建需要挂载的视图。
  • @OnMount,挂载视图,完成布局相关的设置。
  • @OnBind,绑定视图,完成数据和视图的绑定。
  • @OnUnBind,解绑视图,主要用于重置视图的数据相关的属性,防止出现复用问题。
  • @OnUnmount,卸载视图,主要用于重置视图的布局相关的属性,防止出现复用问题。

除了上述两种组件类型,Litho中还有一种特殊的组件——Layout,它不能使用规范来生成。Layout是Litho中的容器组件,类似于Android中的ViewGroup,但是只能使用Flexbox的规范。它可以包含子组件节点,是Litho各组件连接的纽带。Layout组件只是Yoga在Litho中的代理,组件的所有布局相关的属性都会直接设置给Yoga,并由Yoga完成布局的计算。Litho实现了两个Layout组件Row和Column,分别对应Flexbox中的行和列。

2.2.2 Litho的属性

在Litho中属性分为两种,不可变属性称为Props,可变属性称为State,下面分别介绍一下两种属性:

Props属性:组件中使用@Prop注解标注的参数集合,具有单向性和不可变性。下面通过一个简单的例子了解一下如何在组件中定义和使用Props属性:

     @MountSpecclass MyComponentSpec {@OnPreparestatic void onPrepare(ComponentContext c,@Prop(optional = true) String prop1) {...}@OnMountstatic void onMount(ComponentContext c,SomeDrawable convertDrawable,@Prop(optional = true) String prop1,@Prop int prop2) {if (prop1 != null) {...}}}

在上面的代码中,共使用了三次Prop注解,分别标注prop1和prop2两个变量,即定义了prop1和prop2两个属性。Litho会在自动编译生成的MyComponent类的Builder类中生成这两个属性的同名方法。按照如下代码,便可以去使用上面定义的属性:

     MyComponent.create(c).prop1("My prop 1").prop2(256).build();

State属性:意为“状态”属性,State属性虽然可变,但是其变化由组件内部控制,例如:输入框、Checkbox等都是由组件内部去感知用户行为,并更新组件的State属性。所以一个组件一旦创建,我们便无法通过任何外部设置去更改它的属性。组件的State属性虽然不允许像Props属性那样去显式设置,但是我们可以定义一个单独的Props属性来当做某个State属性的初始值。

3. Litho的特性及原理剖析

Litho官网首页通过4个段落重点介绍了Litho的4个特性。

3.1 声明式组件

Litho采用声明式的API来定义UI组件,组件通过一组不可变的属性来描述UI。这种组件化的思想灵感来源于React,关于声明式组件的用法上面已经详细介绍过了。

传统Android布局因为UI与逻辑分离,所以开发工具都有强大的预览功能,方便开发者调整布局。而Litho采用React组件化的思想,通过组件连接了逻辑与布局UI,虽然Litho也提供了对Stetho的支持,借助于Chrome开发者工具对界面进行调试,不过使用起来并没有那么方便。

3.2 异步布局

Android系统在绘制时为了防止页面错乱,页面所有View的测量(Measure)、布局(Layout)以及绘制(Draw)都是在UI线程中完成的。当页面UI非常复杂、视图层级较深时,难免Measure和Layout的时间会过长,从而导致页面渲染时候丢帧出现卡顿情况。Litho为解决该问题,提出了异步布局的思想,利用CPU的闲置时间提前在异步线程中完成Measure和Layout的过程,仅在UI线程中完成绘制工作。当然,Litho只是提供了异步布局的能力,它主要使用在RecyclerView等可以提前知道下一个视图长什么样子的场景。

3.2.1 异步布局原理剖析

针对RecyclerView等滑动列表,由于可以提前知道接下来要展示的一个甚至多个条目的视图样式,所以只要提前创建好下一个或多个条目的视图,就可以提前完成视图的布局工作。

那么Android原生为什么不支持异步布局呢?主要有以下两个原因:

  • View的属性是可变的,只要属性发生变化就可能导致布局变化,因此需要重新计算布局,那么提前计算布局的意义就不大了。而Litho组件的属性是不可变的,所以对于一个组件来说,它的布局计算结果是唯一且不变的。

  • 提前异步布局就意味着要提前创建好接下来要用到的一个或者多个条目的视图,而Android原生的View作为视图单元,不仅包含一个视图的所有属性,而且还负责视图的绘制工作。如果要在绘制前提前去计算布局,就需要预先去持有大量未展示的View实例,大大增加内存占用。反观Litho的组件则没有这个问题,Litho的组件只是视图属性的一个集合,仅负责计算布局,绘制工作由指定的绘制单元来完成,相比与传统的View显然Litho的组件要轻量的多。所以在Litho中,提前创建好接下来要用到的多个条目的组件,并不会带来性能问题,甚至还可以直接把组件当成滑动列表的数据源。如下图所示:

3.3 扁平化的视图

使用Litho布局,我们可以得到一个极致扁平的视图效果。它可以减少渲染时的递归调用,加快渲染速度。

下面是同一个视图在Android和Litho实现下的视图层级效果对比。可以看到,同样的样式,使用Litho实现的布局要比使用Android原生实现的布局更加扁平。

3.3.1 扁平化视图原理剖析

Litho使用Flexbox来创建布局,最终生成带有层级结构的组件树。然后Litho对布局层级进行了两次优化。

  • 使用了Yoga来进行布局计算,Yoga会将Flexbox的相对布局转成绝对布局。经过Yoga处理后的布局没有了原来的布局层级,变成了只有一层。虽然不能解决过度绘制的问题,但是可以有效地减少渲染时的递归调用。

  • 前面介绍过Litho的视图渲染由绘制单元来完成,绘制单元可以是View或者更加轻量的Drawable,Litho自己实现了一系列挂载Drawable的基本视图组件。通过使用Drawable可以减少内存占用,同时相比于View,Android无法检查出Drawable的视图层级,这样可以使视图效果看起来更加扁平。

原理如下图所示,Litho会先把组件树拍平成没有层级的列表,然后使用Drawable来绘制对应的视图单元。

Litho使用Drawable代替View能带来多少好处呢?Drawable和View的区别在于前者不能和用户交互,只能展示,因此Drawable不会像View那样持有很多变量和引用,所以Drawable比View从内存上看要轻量很多。举个例子:50个同样展示“Hello world”的TextView和TextDrawable在内存占比上,前者几乎是后者的8倍。对比图如下,Shallow Size表示对象自身占用的内存大小。

3.3.2 绘制单元的降级策略

由于Drawable不具有交互能力,所以对于使用Drawable无法实现的交互场景,Litho会自动降级成View。主要有以下几种场景:

  • 有监听点击事件。
  • 限制子视图绘出父布局。
  • 有监听焦点变化。
  • 有设置Tag。
  • 有监听触摸事件。
  • 有光影效果。

对于以上场景的使用请仔细考虑,过多的使用会导致Litho的层级优化效果变差。

3.3.3 对比Android的约束布局

为了解决布局嵌套问题,Android推出了约束布局(ConstraintLayout),使用约束布局也可以达到扁平化视图的目的,那么使用Litho的好处是什么呢?

Litho可以更好地实现复杂布局。约束布局虽然可以实现扁平效果,但是它使用了大量的约束来固定视图的位置。随着布局复杂程度的增加,约束条件变得越来越多,可读性也变得越来越差。而Litho则是对Flexbox布局进行的扁平化处理,所以实际使用的还是Flexbox布局,对于复杂的布局Flexbox布局可读性更高。

3.4 细粒度的复用

Litho中的所有组件都可以被回收,并在任何位置进行复用。这种细粒度的复用方式可以极大地提高内存使用率,尤其适用于复杂滑动列表,内存优化非常明显。

3.4.1 原生RecyclerView复用原理剖析

原生的RecyclerView视图按模板类型进行存储并复用,也就是说模板类型越多,所需存储的模板种类也就越多,导致内存占用越来越大。原理如下图。滑出屏幕的itemType1和itemType2都会在Recycler缓存池保存,等待后面滑进屏幕的条目的复用。

3.4.2 细粒度复用优化内存原理剖析

在Litho中,item在回收前,会把LithoView中挂载的各个绘制单元拆分出来(解绑),由Litho自己的缓存池去分类回收,在展示前由LithoView按照组件树的样式组装(挂载)各个绘制单元,这样就达到了细粒度复用的目的。原理如下图。滑出屏幕的itemType1会被拆分成一个个的视图单元。LithoView容器由Recycler缓存池回收,其他视图单元由Litho的缓存池分类回收。

使用细粒度复用的RecyclerView的缓存池不再需要区分模板类型来缓存大量的视图模板,只需要缓存LithoView容器。细粒度回收的视图单元数量要远远小于原来缓存在各个视图模板中的视图单元数量。

4. 实践

美团对Litho进行了二次开发,在美团的MTFlexbox动态化实现方案(简称动态布局)中把Litho作为底层UI渲染引擎来使用。通过动态布局的预览工具,为Litho提供实时预览能力,同时可以有效发挥Litho的性能优化效果。

目前Litho+动态布局的实现方案已经应用在了美团App中,给美团App带来了不错的性能提升。后续博主会详细介绍Litho+动态布局在美团性能优化的实践方案。

使用Litho+动态布局实现的部分卡片

4.1 内存数据

由于Litho中使用了大量Drawable替换View,并且实现了视图单元的细粒度复用,因此复杂列表滑动时内存优化比较明显。美团首页内存占用随滑动页数变化走势图如下。随着一页一页地滑动,内存优化了30M以上。(数据采集自Vivo x20手机内存占用情况)

4.2 FPS数据

FPS的提升主要得益于Litho的异步布局能力,提前计算布局可以减少滑动时的帧率波动,所以滑动过程较平稳,不会有高低起伏的卡顿感。(数据采集自魅蓝2手机一段时间内连续fps的波动情况)

5. 总结

Litho相对于传统Android是颠覆式的,它采用了React的思路,使用声明式的API来编写UI。相比于传统Android,确实在性能优化上有很大的进步,但是如果完全使用Litho开发一款应用,需要自己实现很多组件,而Litho的组件需要在编译时生成,实时预览方面也有所欠缺。相对于直接使用Litho的高成本,把Litho封装成Flexbox布局的底层渲染引擎是个不错的选择。

6. 参考资料

  1. Litho官网
  2. 说一说 Facebook 开源的 Litho
  3. React官网
  4. Yoga官网

7. 作者简介

  • 何少宽,美团Android开发工程师,2015年加入美团,负责美团平台终端业务研发工作。
  • 张颖,美团Android开发工程师,2017年加入美团,负责美团平台终端业务研发工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文浅尝 | 基于深度强化学习将图注意力机制融入知识图谱推理

论文笔记整理&#xff1a;陈名杨&#xff0c;浙江大学直博生。Introduction知识图谱&#xff08;KGs&#xff09;在很多NLP的下游应用中起着越来越重要的作用。但是知识图谱常常是不完整的&#xff0c;所以解决知识图谱补全的任务也非常重要。主要有三种方法来完成知识图谱补全…

聊聊如何提升推荐系统的结果多样性

文 | 洪九(李戈)源 | 知乎个性化推荐系统的出现为处理信息过载问题提供了一个有效的工具&#xff0c;已经成为互联网各大平台(电商、信息流等)的标配&#xff0c;并在技术(个性化召回、个性化排序等)上取得了长足的发展&#xff0c;逐渐从传统模型过度到深度学习时代。但是&…

论文浅尝 | GNN with Generated Parameters for Relation Extraction

论文笔记整理&#xff1a;申时荣&#xff0c;东南大学博士生。地址&#xff1a;https://arxiv.org/pdf/1902.00756.pdf来源&#xff1a;ACL2019在许多自然语言处理任务&#xff08;例如关系提取&#xff09;中&#xff0c;多跳关系推理是必不可少的&#xff0c;而图神经网络&am…

大众点评信息流基于文本生成的创意优化实践

1. 引言 信息流是目前大众点评除搜索之外的第二大用户获取信息的入口&#xff0c;以优质内容来辅助用户消费决策并引导发现品质生活。整个大众点评信息流&#xff08;下文简称点评信息流&#xff09;围绕个性化推荐去连接用户和信息&#xff0c;把更好的内容推荐给需要的用户。…

LeetCode 701. 二叉搜索树中的插入操作(二叉查找树/插入)

1. 题目 给定二叉搜索树&#xff08;BST&#xff09;的根节点和要插入树中的值&#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 保证原始二叉搜索树中不存在新值。 注意&#xff0c;可能存在多种有效的插入方式&#xff0c;只要树在插入后仍保持为二叉搜索…

docker的简单操作和端口映射

docker的简单操作和端口映射&#xff1a;https://www.cnblogs.com/lixaingyang/p/11976827.html docker的简单操作和端口映射 一&#xff1a;简介 Docker镜像 在Docker中容器是基于镜像启动的 镜像是启动容器的核心 镜像采用分层设计&#xff0c;最顶层为读写层 使用快照COW技…

Android官方开发文档Training系列课程中文版:管理Activity的生命周期之启动一个Activity

原文地址 : http://android.xsoftlab.net/training/basics/activity-lifecycle/index.html 导言 用户通过导航退出或者返回应用的时候&#xff0c;应用中Activity的生命周期会在不同的状态之间变换。举个例子&#xff0c;当Activity初次启动的时候&#xff0c;它会来到系统的…

论文浅尝 | 利用多语言 wordnet 上随机游走实现双语 embeddings

论文笔记整理&#xff1a;谭亦鸣&#xff0c;东南大学博士生&#xff0c;研究方向为知识图谱问答。来源&#xff1a;Knowledge Based System链接&#xff1a;https://www.sciencedirect.com/science/article/abs/pii/S0950705118301412?via%3Dihub双语word embedding将两种语言…

实践中学到的最重要的机器学习经验!

文 | 微调源 | 知乎问答今天我们讨论一个很有实际意义的问题&#xff1a;你在实践中学到的最重要的机器学习经验是什么&#xff1f;以下回答来自知乎优秀答主微调。1.永远保持怀疑机器学习是最容易得到错误结论的一种解决方案。和编程、做表格、或者纯粹的数学建模不同&#xf…

Android官方开发文档Training系列课程中文版:管理Activity的生命周期之暂停和恢复Activity

原文地址 : http://android.xsoftlab.net/training/basics/activity-lifecycle/pausing.html 在APP的正常使用过程中&#xff0c;在前台工作的Activity有时可能会被其他的可视化组件挡住&#xff0c;而引起Activity进入Paused状态。举个例子&#xff0c;当一个半透明的Activit…

Leaf:美团分布式ID生成服务开源

Leaf是美团基础研发平台推出的一个分布式ID生成服务&#xff0c;名字取自德国哲学家、数学家莱布尼茨的一句话&#xff1a;“There are no two identical leaves in the world.”Leaf具备高可靠、低延迟、全局唯一等特点。目前已经广泛应用于美团金融、美团外卖、美团酒旅等多个…

LeetCode 658. 找到 K 个最接近的元素(二分查找)

1. 题目 给定一个排序好的数组&#xff0c;两个整数 k 和 x&#xff0c;从数组中找到最靠近 x&#xff08;两数之差最小&#xff09;的 k 个数。返回的结果必须要是按升序排好的。如果有两个数与 x 的差值一样&#xff0c;优先选择数值较小的那个数。 示例 1:输入: [1,2,3,4,…

负数的开方到底等于多少?

文&#xff1a;杨树森知乎编&#xff1a;小鹿鹿lulu负数的开方到底等于多少?举个栗子拿出小本本, 一通变换,得到:Really? 且看下面详解乘方来源于乘法&#xff0c;我们可以归纳地定义&#xff0c;设 是一个域&#xff0c;, 则上述的域 可以是有理数域 , 实数域, 或复数域 前两…

综述 | 知识图谱实体链接:一份“由浅入深”的综述

本文转载自公众号&#xff1a;PaperWeekly。 作者丨Nicolas单位丨追一科技 AI Lab 研究员研究方向丨信息抽取、机器阅读理解本文介绍实体链接&#xff08;Entity Linking&#xff09;这一技术方向&#xff0…

Android官方开发文档Training系列课程中文版:管理Activity的生命周期之停止和重启Activity

原文地址 : http://android.xsoftlab.net/training/basics/activity-lifecycle/stopping.html#Start 在activity的生命周期内&#xff0c;适当的停止和重新启动activity是一个非常重要的过程&#xff0c;它可以确保用户能感觉到APP一直是存活状态&#xff0c;并且不会丢失他们…

selenium.common.exceptions.WebDriverException: Message: ‘chromedriver’解决

selenium.common.exceptions.WebDriverException: Message: chromedriver’解决&#xff1a; https://blog.csdn.net/weixin_44318830/article/details/103339273 今天在做selenium测试的时候,可能是很久没用了,直接报了这个异常! 相信很多第一次学习selenium的同学们也对这个异…

活动 Web 页面人机识别验证的探索与实践

在电商行业&#xff0c;线上的营销活动特别多。在移动互联网时代&#xff0c;一般为了活动的快速上线和内容的即时更新&#xff0c;大部分的业务场景仍然通过 Web 页面来承载。但由于 Web 页面天生“环境透明”&#xff0c;相较于移动客户端页面在安全性上存在更大的挑战。本文…

利用python提取网站曲线图数据

文章目录数据1数据2数据1 数据目标&#xff1a;曲线图 F12&#xff0c;如图位置输入JSON.stringify(dataSeries.dataPoints) copy&#xff0c;粘贴到data.txt 数据是一个列表&#xff0c;里面是多个字典 编写程序如下&#xff1a; import json as js datafile data1.txt…

论文浅尝 | HEAD-QA: 一个面向复杂推理的医疗保健数据集

论文笔记整理&#xff1a;谭亦鸣&#xff0c;东南大学博士生&#xff0c;研究方向为知识库问答。来源&#xff1a;ACL2019本文构建了一个面向复杂推理任务的多选问答数据集 HEAD-QA&#xff0c;该数据集中的问题来自一个西班牙的医疗保健专业测试&#xff0c;对于具备该方向专业…

Poor Man's BERT: 更小更快的Transformer模型

文 | sliderSun源 | 知乎NLP模型的大小不断增加&#xff0c;随之而来的是可用性降低&#xff0c;TinyBERT&#xff0c;MobileBERT&#xff0c;和DistilBERT都提出了一个独特的知识蒸馏框架&#xff0c;其共同目标是在保持性能的同时减小模型大小。尽管所有这些方法都以各自的方…