7月9日,虽然已是中国计算机学会(CCF)主办,雷锋网和香港中文大学(深圳)承办的第二届CCF-GAIR全球人工智能与机器人峰会的最后一天,但仍然不影响各位童鞋到场学习的激情。机器人专场不仅满座,连走道上都挤满了小伙伴。继Facebook田渊栋结束其演讲之后,阿里妈妈精准展示广告技术总监盖坤作为第二场主题演讲嘉宾,也上台为大家分享了在过去5、6年间阿里巴巴基于互联网大数据做的机器学习模型方面的一些探索,以及一些研究成果背后的思考。
盖坤这次给大家带来的演讲主题是《互联网大数据下的模型结构挑战》,主要分为以下几个部分:
1、互联网数据和经典模型
2、分片线性模型和学习算法MLR模型
3、大规模ID特征+MLR实践
4、深层用户兴趣分布网络
(因为盖坤讲的非常干货,所以这次雷锋网将其演讲全文和PPT都贴在了下文,以便未能到场的童鞋也能直观的“听”演讲。)
以下是盖坤本次主题演讲的原文,雷锋网做了不改变原意的编辑:
盖坤:大家好,非常高兴能来到CCF-GAIR的会场。今天想跟大家分享的是过去5、6年间在阿里做的基于互联网数据的机器学习模型方面的一些探索,还有除了研究结果之外背后的一些思考。
这是我今天主题分享的提纲。我会先介绍一下互联网大数据,因为自身主要做电商互联网的用户行为数据。那么,在这个经典业界处理方式下,阿里都做了哪些改进?其中主要包括提出分片线性机器学习算法,也称MLR。之后,我会讲一下大规模ID特征和MLR算法配合在业务里面的应用实践。最后,我会分享这两年,我们在深度学习网络上的一些进展,介绍下深层用户兴趣分布网络。
一、互联网数据和经典模型
典型问题:CTR预估
机器学习可以让互联网数据发挥出巨大价值,而其在工业界应用最早也最成功的一个案例,就是点击率(CTR)预估。CTR预估在广告、推荐、搜索等都是比较重要的业务,对业务指标和收入指标的影响非常巨大。
以CTR预估为例,在此有三种经典做法:
简单线性模型Logistic Regression
稀疏正则L1-Norm特征筛选
处理非线性:人工特征工程
经典方法一:ID特征
ID特征,这里指的是稀疏鉴别式特征。举个例子,假如有1亿个用户,可以把1亿个用户表示为1亿维的01向量,01向量的第一个用户就命中第一维,第二个用户就命中为第二维,所以一种特征可以用这种ID类表示展现成一个非常长的01稀疏向量。如果有很多组特征,就可以把这些向量拼起来,形成一个更长的向量。
就原始特征而言,一般用户量大的公司可能是上亿级,而大的互联网公司,是上亿、上十亿甚至上百亿级的。所以原始ID特征在表示上,可以轻松将其表示成十几亿或者几十亿级。此外,我们还可以做特征的交叉组合,只要工程能力够,可以轻松上千亿,这个特征维度很大。
经典方法二:逻辑回归
逻辑回归是线性模型加上非线性的变换,变成一个概率形式。逻辑回归在工业界使用的方式很不一样。第一,它能处理非常大规模的数据,所以其模型和数据都必须是并行处理的,这对工程和算法上的要求都特别高。第二,对于特别大的特征来讲,通常我们会用稀疏正则L1-Norm特征筛选的方法。
经典方法三:人工特征工程
如果想用这个经典方法将更多有用的信息尤其是非线性的压榨出来,还需要用到人工特征工程的方法。比如刚才说的两个特征,如果两个特征的交互对目标影响很大,那么拼起来的线性模型可能不够,我们就要做交叉等很多特征。
这些方法是我在5、6年前刚进阿里时看到的一个状态,那时候国内大多数公司基本上都在沿用这套方法做研发。但是这里面有两个问题:
1、人工能力有限,很难对非线性模式完全挖掘充分。
2、依赖人力和领域经验,方法推广到其他问题的代价太大,不够智能。
Kernel、Tree based、矩阵分解和分解机器模型和其存在的问题
1、Kernel方法:不适用工业界
Kernel方法是当时学术界使用的一些主流的非线性方法。为什么Kernel方法在工业界不怎么用?因为计算不可行。一般Kernel方法,其矩阵是数据量的平方级。当数据量特别大的时候,工业界只能使用线性级别。
2、Tree based方法:在ID特征上表现不够好
Tree based方法在一些低维的强特征上效果特别好,但在ID特征上反而作用不太好。
这里举一个例子:在推荐场景中,需要预估一个用户和一个宝贝的点击率,先不取历史行为就用用户ID和宝贝ID两种特征。有这两个特征,对于协同过滤的方法就已经够了。但是,如果用Tree based方法,要建树就会带来很多麻烦,树根到树叶的路径等价于是否是某个用户和是否是某个宝贝的联合判断。在这种情况下,它已经变成了一个历史记忆。这就是为什么Tree based的方法在稀疏大规模ID数据上表现不行的原因。
Facebook也做了一个方法,就是在强特征上用Tree based方法做数据筛选,再用一些LR聚合类的方法利用弱特征。
3、矩阵分解和分解机器模型:无法处理高阶关系
矩阵分解和分解机器模型,这两类模型其实有点共通。以分解机器模型为例,它主要处理的是有限次关系,经典的方法是二次关系。对于一些高阶关系是没法处理的。
二、分片线性模型和学习算法MLR模型
分片线性模型:优点、使用模型形式和其他
1、优点:可在大规模数据中挖掘推广性好的非线性模式
分片线性模型MLR是2011年我在阿里提出的方法。该模型的优点在于,可将整个数据分成不同的区域,在每个不同区域都用一个简单的模型预测,再将全部信息聚合起来,得到可以比较复杂的分片线性模型。如此一来,就能平衡欠拟合和过拟合的问题,从而在大规模数据中挖掘出推广性好的非线性信息。而其一个基本原则,就在于要使每分片对应足够量的样本。
如上图所示,我们训练了一些数据。其显示为一个菱形的分界面,用MLR模型能够得到一个很好的结果。这里稍微插一句,这个例子只是为了展示,其实这个例子非常不好学。分片线性模型里分片隶属度一般用软的非离散的函数,这种锐角折线而非平滑曲线会使得隶属度在局部变化非常剧烈而在其它地方又很平坦,给学习造成严重的局部极值问题,所以学习到这个结果是挺不容易的。
2、使用的模型形式:分而治之
上图这个模型我们参考了MOE的模型,不过我们的形式更加泛化。借此我们用一个函数做整个空间的区域划分,在其中有参数可以跟进数据自动学习,每个区域划分都含有一个预测器。当区域划分选择Softmax时,区域内则有LR预测,这是我们主要在用的模型之一。还有一种,是MOE&LR级联,这个模型也是我们非常主要使用的模型。
从神经网络的视角看,整个特征会学到表示所有分片隶属度的的向量,也会学到每个预测器的值,不同预测器会组成一个向量,最后是两个向量作为一个内积,变成一个预估值。这其实很像神经网络的Embedding方法,或者基本上可以判断是Embedding 方法的一种。
3、如何学习参数?
一个复杂的模型,实际上对于机器学习而言,重要的是这个模型是否工作,能不能学习?这个学习也和转化形式有关。其实跟逻辑回归一样,对于特别高维度的特征而言,我们希望学习的时候也有稀疏和泛化的作用并能做特征选择,所以选择了L21范数正则做分组稀疏
为什么要分组稀疏?因为每维特征对应一组参数,这组参数在训练的时候要同时为0,这个特征才真的意味着我们在使用的时候不用了,才能做特征选择。如果这个参数里面有任何一个不为0,这个特征是不能被过滤掉的,于是我们用分组稀疏。这是机器学习里面非常经典的方法,经验损失加上正则,用L1和L21范数同时做正则。
4、目标函数分析
存在难度和挑战:非凸、非光滑、高维度
有了这个目标函数,下面最关键的是怎么优化。这里的挑战在于,前面是一个非凸函数,后面的L1范数和L21范数都是非光滑函数,就会导致困难耦合不太好解。而如果是凸问题不可导,数学上凸问题都会有次梯度,可以用次梯度方法。但是这里不是凸问题,所以次梯度不存在。
为什么不用EM算法?
并且,在大规模的互联网大数据的情况下,维度也非常高。我们如何才能找到一个快速的求解方法?EM很经典,为什么不像传统MOE一样使用EM算法?
因为EM算法只适用于概率连乘的模型形式,而我们的方法对非正则部分可导的形式通用。其实EM算法是用E-Step把一个非凸问题变成一个凸问题,用M-Step来解这个问题,如果容易求解,EM就是合适。如果局限于MOE模型,它就会转化成凸问题,它的正则还是带着的,就变成一个参数量非常大的非光滑的凸问题,维度特别高。然而,超大维度非光滑的凸问题非常不好求解。所以这个非凸问题用EM转化并不比原始问题好求解。我们也就没有用EM,因为其并不能给实际求解带来任何的便利性。
MLR算法的特性和实验
这个算法适用于一般的经验损失加上L21正则再加上1范数正则的函数,在此其中,其关键点在于怎样求解。首先,我们证明了这个函数是处处方向可导的,虽然它可能不是处处可导的,但是它处处方向可导。这种情况下,就可以用这个方法。
为什么处处方向可导?
比如说L21范数在数学上会形成一个圆锥点,圆锥点那个点是没有切面的,所以它不可导。但是从它出发沿任何一个方向都有切线,所以其方向可导,而所有部分都方向可导,叠加起来就是处处方向可导。
这个证明也可以从我们的论文里求证,借此我们就能求出方向可导的最速下降方向。在此用最速下降方向代替梯度,用LBFGS做一个二阶加速。在其中,如OWL-QN,这是LR+L1正则,是微软提出的一个经典方法。我们像它一样进行象限约束,约束一次更新最多到达象限边界,下一次才能跨到这个象限。而Line Search是一个经典方法。我们会对收敛性做一个强保证,如果二阶加速不能下降,会直接用最速下降方向进行补偿搜索,直到两种方法都不能下降的时候才停止。
1、MLR特性:5大特点
结合前文,可将MLR的特点总结如下五点:
分而治之;
分片数足够多时,有非常强的非线性能力;
模型复杂度可控:有较好泛化能力;
具有自动特征选择作用;
可以适用于大规模高维度数据;
实验1:聚类和分类联动
如图,这是演示的一次实验,图中第一张图表示为原始数据。像逻辑回归、二阶方法,对于高度的非线性方法都不太适合,所以基本上其结果没有什么区分能力,但是MLR能够做到非常好的区分。而利用K-means先做聚类再做分类的方法,也没办法做很好的区域划分——我们先给K-means用4分片,但其区域怎么划分和后面怎么预测不联动,所以它就变成上图第二排第二个的分界面。我们再把K-means加上10分片,其实也没有变成一个很完美的分界面。
实验2:高阶拟合
这里是一个高阶拟合应用。我们用了一组数据来验证3个ID组合的方式。3个ID组合时,Libfm是没有办法很好抓住这个组合的特性的,但是借用MLR就可以很好的实现。
2、MLR 和LR 、GBDT模型的对比
如图,是一个实际业务数据的对比。在推荐场景里,我们的MLR和LR相比而言,在CTR预估和CVR(转化率)预估上的效果都有一个非常明显的提升。和GBDT(雷锋网(公众号:雷锋网)注:一种迭代的决策树算法)对比,这是一个稠密数据的对比,大概是400多维的稠密数据。小维度稠密数据上GBDT表现还是不错的,到400多维的时候,MLR在预测性能上就已经优于GBDT。我们特意取了MLR还未收敛,训练集准确率和GBDT相同时候的模型,会发现测试集性能已经优于GBDT。
三、大规模ID特征+MLR实践
再来说说具体的实践。当用户用到宝贝维度时,对于阿里来讲是预估一个用户对一个宝贝的CTR或者转化率。在此其中的特征设计,一般设置的是ID特征。对于用户的行为,我们会用这些元素来表示:他访问、收藏、购买过哪个店铺、哪个类目等等,一系列的行为就会变成ID特征,来表示用户行为。用户除了行为之后,还有一个用户属性特征,比如性别、年龄、地域等等。
大规模ID特征:为什么不用用户ID?
如果用用户ID做特征的话,在建模的时候,每个用户ID会带来一个Embedding向量,这个向量可以称为用户的兴趣点。在训练的时候,通过用户兴趣点去拟合训练集中正样本宝贝的兴趣点。其实这个东西是在兴趣点的空间里做了一个历史记忆,虽然兴趣点本身会有一定的聚合作用,但其本质上还是历史记忆的作用。所以我们认为推广性并不好。
如果用行为ID去拟合正样本宝贝兴趣点,我们认为,从历史行为兴趣点到后续行为兴趣点这种模式的拟合是更具有推广意义,在实际业务中也会更有用。
那么,为什么会倾向于用户行为ID而不是用户ID。当然用户ID也有用,其是在训练的时候可帮助减少训练时的偏差,做一个偏置项。如果行为还不足够表达数据的全部特性,用户ID用来做偏置辅助训练,而我们在做预测的时候是完全用用户的行为ID来做的,这样才有更好的推广性。
如上图最下方所示,这是一个实际业务上的对比,MLR,也就是LS-PLM是第一行,LR是第二行。一般来讲,在工业界生产环境里面,训练集和测试集按时间分开,前一个时间段的数据做训练,后一个时间段做测试。上图显示的是连续7天的测试结果,MLR都在第一行,相比LR,其明显在AUC上都有提升1个点以上。
MLR如何能用的更好,就此我想给大家分享几招↓
MLR实践
▪ Trick One:结构化先验
首先是结构化先验。在实际应用中,我们一般只用用户特征做聚类,只用广告特征做分类,就会有非常好的直观意义。这样一来,就把用户分成不同的群体,每个群体做一个LR的预估。
实验显示,分组训练比不做分组全放开所有参数直接训练效果要好。后面我们在分组模型的基础上,再放开所有参数做refine效果更好。因为全放开寻优空间特别大,很难找到一个比较好的路径和比较好的点,所以通过结构化先验会使其找到一个比较好的点,在其基础上把参数全放开,会有更大的自由度,整个训练过程也会处理得更好。
前面也有提及,我们在实际应用的时候会有一个模型级联,在其中会有两种特征放在后面的级联里面:
▪ 位置偏差:在预测的时候,为了计算考虑,我们不会考虑位置之间的协同性。比如说做一个位置归一的点击率排序,根据排序的顺序放在第一位、第二位、第三位,位置偏差只在训练时去偏置,使用时是不用的。
▪ 强特征:有一些将用户行为序列的模型用来强特征,这些特征跟点击率非常相关。我们发现,如果直接放在原始特征里面去学,并没有直接和目标放在一个线性偏置里那么好。从模型能力上来讲,如果训练方法能够找到全局最优解那都可以放在非线性部分不用放在线性部分,但是我们发现,如果它跟最终目标有一个比较短的路径连接,对于整个寻优是更有帮助的。
▪ Trick Two:Common Feature
Common Feature是在使用过程中一个非常重要的方法。比如,在淘宝的场景中可能会推荐200个宝贝或者几十个宝贝,我们将一个用户和一个宝贝组成一个样本,这样对应几十或上百个样本。实际上,同一个用户在一天或一星期内或在一段时间之内可能会多次访问淘宝,其用户特征有大部分是冗余的。
我们发现,Common Feature在一些情况下其实可以不用展开,如果每个样本都展开表示成一个完整的向量,就需要多次复制用户特征。而在不展开的情况下,可以极大的节省存储空间。像MLR,在其背后运用的是矩阵运算,而Common Feature在矩阵运算部分计算也是共用的,可以节省。这样一来,不仅可以节省存储,也可以节省计算。
为此,我们还做了一次实际对比。我们用不展开的结构化数据来表示数据存储,结果表明,在训练算法里内存量的占用有一个非常明显的下降,每台机器从90GB下降到3GB,而每一轮时间也因为计算量减少从120s变成10s。
在过去几年,以MLR为核心的预估模型的持续迭代和优化,是直通车定向、钻展等业务线提升的主要动力之一。
四、新结构:深层用户兴趣网络分布
(注:如雷锋网此前报道,深度兴趣网络是盖坤团队在CTR预估方面利用深度学习达到的最新进展。通过观察阿里巴巴采集的用户历史行为数据,盖坤团队发现有两个指标对广告CTR预测准确率有重大影响,一个是“多样性(Diversity)”,一个用户可以对很多不同品类的东西感兴趣;另一个指标是“部分对应(Local activation)”,只有一部分的数据可以用来预测用户的点击偏好,比如系统自动向用户推荐的太阳镜会跟用户买的泳衣产生关联,但是跟用户买的书就没什么关系了。)
深度学习
最后一部分,我稍讲一下深度学习。
▪ 如何看待深度学习?
其实前面也介绍了MLR从模型设计到算法设计到应用。模型设计和算法设计是耦合的。对复杂模型,加上设计优化方法整个工作是比较重的。如果有一个很好的模型,没有优化方法也是不行的。而深度学习一个很重要的特性,就是用户方法和模型是解耦的,这些方法和模型设计不是绑定的。
第一个是解耦,第二是模型设计组件化。组件化可以自己分层搭建,也可以自己设计,开发者也可以根据大牛事先设计组件来搭建,从而组合出以前完全不能想像的复杂模型。
借助深度学习的以上两点特征,可以Handle原来完全没法实现的复杂模型。
▪ 复杂就足够了么?
如果只是拟合能力跟最终的应用效果有关,单隐层神经网络在数学上,其拟合能力是可以无限高的。虽然它拟合能力足够,记忆性非常强,但其泛化能力不够。深度学习里有两个非常关键的东西:
▪ 第一是深度和宽度。相较而言,深度网络比宽度网络,至少在实际实践中的泛化推广能力更好。
▪ 第二是模型结构和数据匹配度。深度神经网络里面网络结构非常关键,比如图像中CNN几乎是主导,而LSTM在对应的应用领域就展现出非常好的性能。
这些都是整个学术界和业界已经有的基础能力,而在互联网行为数据上,我们还要考虑CNN、LSTM是否足够,这些模型结构和互联网行为数据并不是直接完全匹配的。那么,在互联网行为数据下,我们应该用什么样的网络结构组件?
用户兴趣分布
▪ 用户兴趣表示
在此其中,我们做了一个工作,就是用户兴趣分布表示。前文有提及,用户行为一般会先表示为ID,经典的方法就是每个ID会取一个embedding向量,这个embedding 向量典型的方法会有Pooling和RNN,来聚合成一个固定长度向量。
前面的向量相当于用户兴趣点,后面的目标广告也会embedding出来一个目标宝贝兴趣点。这两个兴趣向量拼起来,可在后面再接一个比较复杂的神经网络。而一个问题在于,一个K维的向量最多能表达K个独立的兴趣,用户的兴趣纷纭复杂,独立的兴趣也非常多,却用一个向量表示,怎么能够增大兴趣的容纳能力?简单的方法就是增加K或者增大embedding 向量空间的维度。但是这里会带来一个问题,一是极大地增大计算负担,二是增大维度可能会导致过拟合。所以,我们的动机是,能不能在低维空间表达非常复杂的用户兴趣?
这里有一个想法,用户的兴趣不再用K维向量的一个点来表示,而是用一个分布来表示。目标宝贝兴趣点也在同样的空间里用点来表示。这样,互相独立的宝贝兴趣点可以放在并不是正交的方向上,所以K维空间也可以容纳理论上无限多个独立的兴趣。
▪ 用户兴趣分布
就此,来看一下实际数据。用户的行为序列在电商行为上有两个:
第一,用户是多需求并发的。
第二,用户在看一个单独商品的时候,其实只跟其中一个或部分兴趣有关,并没有跟背后的所有兴趣都有关。
我们把用户兴趣的向量点表示成一个X的函数,这个X就是测试点,在不同测试点上用户兴趣向量是不同的,这样它就变成一个分布,因为它跟X有关。在预估模型场景里,X就是我们要预估的宝贝。这样来看,用户兴趣其实是用Embedding 加Pooling 的方式,把用户行为蕴含的embedding 向量固定并叠加起来,在叠加前面加一个系数,该系数与目标有关。在此其中,我们要用预估的目标反向激活和过滤用户的历史行为,把整个长序列变成相关的子序列,再就子序列来做一个处理。
那么,到底怎么学习?这里面就要设置模型和参数,利用数据去学习。为了实现用户兴趣多峰分布的目的,我们根据用户行为数据特点设计了反向局部激活网络,其中反向激活权重用一个带参数的神经网络来实现。完成整个网络设计后,发现局部激活想法等价于NLP里提出的Attention机制,可以看做实现用户兴趣多峰分布的一种带attention网络。
深层用户兴趣分布网络
这是整个用户兴趣分布网络。用户的历史行为和要预估的广告密切相关,我们会用广告激活历史行为,利用权重调制,变成子序列,子序列上面再做Pooling建模。这里稍微介绍细节部分,在激活的时候要拿历史行为的兴趣向量和目标的兴趣向量连接起来。通过简单的多层全连接,我们发现内积的形式并不能完全很好的学出来,所以就把内积人工的添加到此结构里。
▪ 方法1:利用结构化数据
这是我们实际在用的更复杂的网络,主要探索运用了结构化数据。在历史行为上,如果用户点击过一个宝贝,这个宝贝及其相关数据如图片、文本、评论等,以及用户的行为时间、行为场景包括是在搜索场景还是推荐行为去点击的,我们都会把整个结构化的数据打包起来,做一个整个反向激活的函数。
拿时间举例,我们会做一个时间差,时间差越小,激活应该更大。还有哪些场景对预估更有帮助,哪些场景是你随便点击的,都放在反向激活里。
▪ 方法2:机器学习的自适应正则
在实际业务中使用深度学习的时候,我们发现深度学习可能会过拟合,尤其是在大规模的ID特征上,参数量非常大,模型特别复杂,随便一用就发现过拟合特别严重。所以我们希望找一些方法,比如在机器学习里的经典的正则类方法。
正则方法在稀疏数据深度学习上的使用,还没有一个公认的好方法。在这其中,其特征是稀疏的,很多特征是0,每个样本只有局部特征非零。直接使用正则,不管特征是不是0都是要正则的,要梯度计算。
假如说一个样本,有100亿维度,非0的也要算一遍,一个样本都很难算出来,更别说要几百亿样本一起算。如果0值特征有这么多计算,计算是不可接受的。我们设计的正则方法只在非0值上计算,此外,正则还跟频次有关,频次越高正则压制越少,出现频次越低的特征,正则压制越大。
另外我们把Prelu也做了一个改进。Prelu是一个折线,我们中间将折点变成光滑变化的,光滑方式也跟数据分布有关,整个激活函数变化之后的效果会更好。
▪ 方法3:激活权重展示
这是一个反向激活权重的展示,在此要预估的是一件衣服的点击率。真实的用户历史行为是这些,我们用目标衣服反向激活,发现预估CTR跟某些东西完全不相关,那就可以不用,而有些东西就比较相关。
用户兴趣分布展示:聚类性非常好
这是用户实际训练出来的兴趣分布,我们做了一个低维展示。如图,颜色越暖分布兴趣度越高,颜色越深兴趣度越低,在这个方法中,整个兴趣空间的聚类性都特别好,基本上一类宝贝的兴趣点都聚在一起。值得注意的是,它是多峰的,比如说这两个峰比较高,另外两个峰都比较低,从而呈现一个多峰的性质。
实现的正则效果
这是我们的正则效果,这个蓝线表示不用正则或者压制过拟合的方法在大维度上直接训练深度学习的结果。我们发现,训练之后其训练损失一下子就下来了,但是测试损失也同步增高了。对此,我们试了很多方法,最上面的黄线是我们提出的正则方法,其比很多方法都好。而且在大规模特征下,简单的用频次做过滤比Dropout的方法也会好一些,但不如自适应正则。
这是刚才提出的整个深度学习方法得出的效果,最上面的绿线是叠加了我刚才讲的一系列用户兴趣分布、函数改进、正则改进等呈现的效果。当然,这里的全部数据都在论文里。
如前文所示,基本上讲完了阿里妈妈一路下来从线性模型、非线性模型再到深度学习的考虑和实际业务的应用。
最后稍微做个广告。现在阿里巴巴对人工智能非常重视,我们既重视目前业务上的应用效果,也重视未来长期的储备。我所在的团队就是精准展示广告部,我们会分机器学习模型算法、机器学习平台、视觉图像、NLP、广告机制和策略、客户端优化、在线引擎和工程架构等方向。除了今天讲的模型的进展之外,我们去年在OCR ICDAR上也刷新了最好的成绩(雷锋网注:ICDAR Robust Reading竞赛是当前OCR(图中文字识别)技术领域全球最具影响力的比赛。),OCPC算法将在下个月KDD大会跟大家见面。
本文作者:李秀琴
本文转自雷锋网禁止二次转载,原文链接