深度学习——推荐算法基础原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习——推荐算法基础原理相关的知识,希望对你有一定的参考价值。


摘要

互联网和信息计算的快速发展,衍生了海量的数据,我们已经进入了一个信息爆炸的时代,每时每刻都有海量信息产生,然而这些信息并不全是个人所关心的,用户从大量的信息中寻找对自己有用的信息也变得越来越困难。另一方面,信息的生产方也在绞尽脑汁的把用户感兴趣的信息送到用户面前,每个人的兴趣又不尽相同,所以可以实现千人千面的推荐系统应运而生。简单来说,推荐系统是根据用户的浏览习惯,确定用户的兴趣,通过发掘用户的行为,将合适的信息推荐给用户,满足用户的个性化需求,帮助用户找到对他胃口但是不易找到的信息或商品。

推荐系统在互联网和传统行业中都有着大量的应用。在互联网行业,几乎所有的互联网平台都应用了推荐系统,如资讯新闻/影视剧/知识社区的内容推荐、电商平台的商品推荐等;在传统行业中,有些用于企业的营销环节,如银行的金融产品推荐、保险公司的保险产品推荐等。根据QM报告,以推荐系统技术为核心的短视频行业在2019年的用户规模已超8.2亿,市场规模达2千亿,由此可见这项技术在现代社会的经济价值。

深度学习——推荐算法基础原理_相似度

推荐系统的目标

随着现代工业和互联网的兴起,长尾经济变得越来越流行。在男耕女织的农业时代,人们以“个性化”的模式生产“个性化”的产品;在流水线模式的工业化时代,人们以“规模化”的模式生产“标准化”的产品;而在互联网和智能制造业不断发展的今天,人们以“规模化”的模式生产“个性化”的产品,极大地丰富了商品种类。在此情况下,用户的注意力和消费力变成极为匮乏的资源。如何从海量的产品和服务中选择自己需要的,成为用户第一关心的事,这就是推荐系统的价值所在。但每个人的喜好极具个性化,例如年轻人偏爱健身的内容,而父母一代偏爱做菜的内容,如果推荐内容相反,用户会非常不满。正所谓此之甘露,彼之砒霜,基于个性化需求进行推荐是推荐系统的关键目标。

深度学习——推荐算法基础原理_推荐系统_02

推荐系统的基本概念

构建推荐系统本质上是要解决“5W”的问题。如下图示例,当用户在晚间上网阅读军事小说时,系统在小说的底部向他推荐三国志游戏,并给出了推荐理由“纸上谈兵不如亲身实践”。

深度学习——推荐算法基础原理_数据_03

哪些信息可以用于推荐

观察只保留两个核心问题的推荐任务示例,思考有哪些信息可以用于推荐? 图中蕴含的数据可以分为三种:

  1. 每个用户的不同特征,如性别、年龄;
  2. 物品的各种描述属性,如品牌、品类;
  3. 用户对部分物品的兴趣表达,即用户与物品的关联数据,如历史上的评分、评价、点击行为和购买行为。

结合这三种信息可以形成类似“女性A 喜欢 LV包”这样的表达。

深度学习——推荐算法基础原理_特征向量_04

基于3的关联信息,人们设计了“协同过滤的推荐算法”。基于2的内容信息,设计出“基于内容的推荐算法”。现在的推荐系统普遍同时利用这三种信息,下面我们就来看看这些方法的原理。

常用的推荐系统算法

常用的推荐系统算法实现方案有三种:

协同过滤推荐(Collaborative Filtering Recommendation)

该算法的核心是分析用户的兴趣和行为,利用共同行为习惯的群体有相似喜好的原则,推荐用户感兴趣的信息。兴趣有高有低,算法会根据用户对信息的反馈(如评分)进行排序,这种方式在学术上称为协同过滤。协同过滤算法是经典的推荐算法,经典意味着简单、好用。协同过滤算法又可以简单分为两种:

基于用户的协同过滤:

根据用户的历史喜好分析出相似兴趣的人,然后给用户推荐其他人喜欢的物品。假如小李,小张对物品A、B都给了十分好评,那么可以认为小李、小张具有相似的兴趣爱好,如果小李给物品C十分好评,那么可以把C推荐给小张,可简单理解为“人以类聚”。

基于物品的协同过滤:

根据用户的历史喜好分析出相似物品,然后给用户推荐同类物品。比如小李对物品A、B、C给了十分好评,小王对物品A、C给了十分好评,从这些用户的喜好中分析出喜欢A的人都喜欢C,物品A、C是相似的,如果小张给了A好评,那么可以把C也推荐给小张,可简单理解为“物以群分”。

基于内容过滤推荐(Content-based Filtering Recommendation)

基于内容的过滤是信息检索领域的重要研究内容,是更为简单直接的算法,该算法的核心是衡量出两个物品的相似度。首先对物品或内容的特征作出描述,发现其相关性,然后基于用户以往的喜好记录,推荐给用户相似的物品。比如,小张对物品A感兴趣,而物品A和物品C是同类物品(从物品的内容描述上判断),可以把物品C也推荐给小张。

组合推荐(Hybrid Recommendation)

以上算法各有优缺点,比如基于内容的过滤推荐是基于物品建模,在系统启动初期往往有较好的推荐效果,但是没有考虑用户群体的关联属性;协同过滤推荐考虑了用户群体喜好信息,可以推荐内容上不相似的新物品,发现用户潜在的兴趣偏好,但是这依赖于足够多且准确的用户历史信息。所以,实际应用中往往不只采用某一种推荐方法,而是通过一定的组合方法将多个算法混合在一起,以实现更好的推荐效果,比如加权混合、分层混合等。具体选择哪种方式和应用场景有很大关系。

深度学习——推荐算法基础原理_推荐系统_05

如何实现推荐

如何根据上述数据实现推荐系统呢?首先思考下,实现推荐系统究竟需要什么?

如果能将用户A的原始特征转变成一种代表用户A喜好的特征向量,将电影1的原始特征转变成一种代表电影1特性的特征向量。那么,我们计算两个向量的相似度,就可以代表用户A对电影1的喜欢程度。据此,推荐系统可以如此构建:

深度学习——推荐算法基础原理_推荐系统_06

这样设计的核心是两个特征向量的有效性,它们会决定推荐的效果。

如何获得有效特征

如何获取两种有效代表用户和电影的特征向量?首先,需要明确什么是“有效”?

对于用户评分较高的电影,电影的特征向量和用户的特征向量应该高度相似,反之则相异。

我们已经获得大量评分样本,因此可以构建一个训练模型如下图所示,根据用户对电影的评分样本,学习出用户特征向量和电影特征向量的计算方案(灰色箭头)。

深度学习——推荐算法基础原理_数据_07

  1. 第一层结构:特征变换,原始特征集合变换为两个特征向量。
  2. 第二层结构:计算向量相似度。(计算相似度是代表两个向量的之间的相似程度为多少?)为确保结果与电影评分可比较,两个特征向量的相似度从【0~1】缩放5倍到【0~5】。
  3. 第三层结构:计算Loss,计算缩放后的相似度与用户对电影的真实评分的“均方误差”。

以在训练样本上的Loss最小化为目标,即可学习出模型的网络参数,这些网络参数本质上就是从原始特征集合到特征向量的计算方法,如灰色箭头所示。根据训练好的网络,我们可以计算任意用户和电影向量的相似度,进一步完成推荐。

从原始特征到特征向量之间的网络如何设计?

深度学习——推荐算法基础原理_相似度_08

将每个原始特征转变成Embedding表示,再合并成一个用户特征向量和一个电影特征向量。计算两个特征向量的相似度后,再与训练样本(已知的用户对电影的评分)做损失计算。

但不同类型的原始特征应该如何变换?有哪些网络设计细节需要考虑?我们将在后续几节结合代码实现逐一探讨,包括四个小节:

  1. 数据处理,将MovieLens的数据处理成神经网络理解的形式。
  2. 模型设计,设计神经网络模型,将离散的文字数据映射为向量。
  3. 配置训练参数并完成训练,提取并保存训练后的数据特征。
  4. 利用保存的特征构建相似度矩阵完成推荐。

模型设计介绍

神经网络模型设计是电影推荐任务中重要的一环。它的作用是提取图像、文本或者语音的特征,利用这些特征完成分类、检测、文本分析等任务。在电影推荐任务中,我们将设计一个神经网络模型,提取用户数据、电影数据的特征向量,然后计算这些向量的相似度,利用相似度的大小去完成推荐。

神经网络模型的设计包含如下步骤:

  1. 分别将用户、电影的多个特征数据转换成特征向量。
  2. 对这些特征向量,使用全连接层或者卷积层进一步提取特征。
  3. 将用户、电影多个数据的特征向量融合成一个向量表示,方便进行相似度计算。
  4. 计算特征之间的相似度。

依据这个思路,我们设计一个简单的电影推荐神经网络模型:

深度学习——推荐算法基础原理_相似度_09


该网络结构包含如下内容:

  1. 提取用户特征和电影特征作为神经网络的输入,其中:
  • 用户特征包含四个属性信息,分别是用户ID、性别、职业和年龄。
  • 电影特征包含三个属性信息,分别是电影ID、电影类型和电影名称。
  1. 提取用户特征。使用Embedding层将用户ID映射为向量表示,输入全连接层,并对其他三个属性也做类似的处理。然后将四个属性的特征分别全连接并相加。
  2. 提取电影特征。将电影ID和电影类型映射为向量表示,输入全连接层,电影名字用文本卷积神经网络得到其定长向量表示。然后将三个属性的特征表示分别全连接并相加。
  3. 得到用户和电影的向量表示后,计算二者的余弦相似度。最后,用该相似度和用户真实评分的均方差作为该回归模型的损失函数。

衡量相似度的计算有多种方式,比如计算余弦相似度、皮尔森相关系数、Jaccard相似系数等等,或者通过计算欧几里得距离、曼哈顿距离、明可夫斯基距离等方式计算相似度。余弦相似度是一种简单好用的向量相似度计算方式,通过计算向量之间的夹角余弦值来评估他们的相似度,本节我们使用余弦相似度计算特征之间的相似度。在不同的场景下使用的不懂的有利于的完成更好的推荐的功能,这个科研工作的一个热点方向。


 为何如此设计网络呢?

  1. 如何将“数字”转变成“向量”?
    如NLP章节的介绍,使用词嵌入(Embedding)的方式可将数字转变成向量。
  2. 如何合并多个向量的信息?例如:如何将用户四个特征(ID、性别、年龄、职业)的向量合并成一个向量?
    最简单的方式是先将不同特征向量(ID 32维、性别 16维、年龄 16维、职业 16维)通过4个全连接层映射到4个等长的向量(200维度),再将4个等长的向量按位相加即可得到1个包含全部信息的向量。这个涉及的到数据矩阵的升维的操作,同时这个涉及的矩阵轮的相关知识需要自行补充。
    电影类型的特征是将多个数字(代表出现的单词)转变成的多个向量(6个),可以通过相同的方式合并成1个向量。
  3. 如何处理文本信息?
    如NLP章节的介绍,使用卷积神经网络(CNN)和长短记忆神经网络(LSTM 处理的是简单的文本信息,但是如果是复杂文本信息呢?需要用什么网络处理?)处理文本信息会有较好的效果。因为电影标题是相对简单的短文本,所以我们使用卷积网络结构来处理电影标题。
  4. 尺寸大小应该如何设计? 这涉及到信息熵的理念:越丰富的信息,维度越高。所以,信息量较少的原始特征可以用更短的向量表示,例如性别、年龄和职业这三个特征向量均设置成16维,而用户ID和电影ID这样较多信息量的特征设置成32维。综合了4个原始用户特征的向量和综合了3个电影特征的向量均设计成200维度,使得它们可以蕴含更丰富的信息。当然,尺寸大小并没有一贯的最优规律,需要我们根据问题的复杂程度,训练样本量,特征的信息量等多方面信息探索出最有效的设计。(矩阵设计成为多少维度这个是没有固定的计算方法,需要依据问题的复杂程度,训练样本量,特征的信息量等多方面信息探索出最有效的设计

Embedding介绍

原理为:实际上,Embedding层和Conv2D, Linear层一样,Embedding层也有可学习的权重,通过矩阵相乘的方法对输入数据进行映射。Embedding中将输入映射成向量的实际步骤是:

  1. 将输入数据转换成one-hot格式的向量;
  2. one-hot向量和Embedding层的权重进行矩阵相乘得到Embedding的结果。

Embedding是一个嵌入层,将输入的非负整数矩阵中的每个数值转换为具有固定长度的向量

import paddle
from paddle.nn import Linear, Embedding, Conv2D
import numpy as np
import paddle.nn.functional as F

# 声明用户的最大ID,在此基础上加1(算上数字0)
USR_ID_NUM = 6040 + 1
# 声明Embedding 层,将ID映射为32长度的向量
usr_emb = Embedding(num_embeddings=USR_ID_NUM,
embedding_dim=32,
sparse=False)
# 声明输入数据,将其转成tensor
arr_1 = np.array([1], dtype="int64").reshape((-1))
print(arr_1)
arr_pd1 = paddle.to_tensor(arr_1)
print(arr_pd1)
# 计算结果
emb_res = usr_emb(arr_pd1)
# 打印结果
print("数字 1 的embedding结果是: ", emb_res.numpy(), "\\n形状是:", emb_res.shape)


[1]
Tensor(shape=[1], dtype=int64, place=CPUPlace, stop_gradient=True,
[1])
数字 1 的embedding结果是: [[-0.02908065 0.02972135 0.00829487 0.02207392 0.00958551 -0.00077017
0.00740909 0.01082573 0.01397826 -0.01737736 0.00206096 -0.02563335
0.01654972 -0.00394134 -0.01858945 -0.02632484 -0.00535294 0.02170646
-0.00065703 -0.01276188 0.02922116 0.02545989 0.00814354 -0.01493532
-0.0240198 -0.02508464 0.01944372 0.0245777 -0.01260571 0.01378552
-0.00929949 0.02869129]]
形状是: [1, 32]

使用Embedding时,需要注意​​num_embeddings​​​和​​embedding_dim​​​这两个参数。​​num_embeddings​​​表示词表大小;​​embedding_dim​​表示Embedding层维度。

下面展示了另一个使用Embedding函数的案例。该案例从0到9的10个ID数字中随机取出了3个,查看使用默认初始化方式的Embedding结果,再查看使用KaimingNormal(0均值的正态分布)初始化方式的Embedding结果。实际上,无论使用哪种参数初始化的方式,这些参数都是要在后续的训练过程中优化的,只是更符合任务场景的初始化方式可以使训练更快收敛,部分场景可以取得略好的模型精度。

# 声明用户的最大ID,在此基础上加1(算上数字0)
USR_ID_NUM = 10
# 声明Embedding 层,将ID映射为16长度的向量
usr_emb = Embedding(num_embeddings=USR_ID_NUM,
embedding_dim=16,
sparse=False)
# 定义输入数据,输入数据为不超过10的整数,将其转成tensor
arr = np.random.randint(0, 10, (3)).reshape((-1)).astype(int64)
print("输入数据是:", arr)
arr_pd = paddle.to_tensor(arr)
emb_res = usr_emb(arr_pd)
print("默认权重初始化embedding层的映射结果是:", emb_res.numpy())

# 观察Embedding层的权重
emb_weights = usr_emb.state_dict()
print(emb_weights.keys())

print("\\n查看embedding层的权重形状:", emb_weights[weight].shape)

# 声明Embedding 层,将ID映射为16长度的向量,自定义权重初始化方式
# 定义KaimingNorma初始化方式
init = paddle.nn.initializer.KaimingNormal()
param_attr = paddle.ParamAttr(initializer=init)

usr_emb2 = Embedding(num_embeddings=USR_ID_NUM,
embedding_dim=16,
weight_attr=param_attr)
emb_res = usr_emb2(arr_pd)
print("\\KaimingNormal初始化权重embedding层的映射结果是:", emb_res.numpy())
输入数据是: [1 4 9]
默认权重初始化embedding层的映射结果是: [[-0.07559231 0.46109134 -0.17617545 -0.2632709 0.04440361 0.03021485
-0.33481532 0.46221858 0.18059582 -0.310695 0.35020006 -0.2682178
-0.09613737 -0.41793132 -0.29280508 -0.12745944]
[-0.38570142 0.166713 -0.34719235 -0.16140386 -0.06184858 -0.20724228
-0.06870237 0.44924378 -0.38813472 0.3347426 0.40100622 0.05968314
-0.40234727 -0.04549411 -0.41187727 -0.23398468]
[-0.35217947 0.17998767 0.2391913 0.25739622 0.44642985 0.2946385
-0.17868212 -0.32654923 0.39072788 -0.4247006 0.11755955 0.40622634
0.37872875 -0.3500846 0.33671618 -0.382438 ]]
odict_keys([weight])

查看embedding层的权重形状: [10, 16]
\\KaimingNormal初始化权重embedding层的映射结果是: [[-0.28677347 -0.1705432 0.2987513 0.24275354 -0.6326506 -0.45437163
-0.07351629 -0.21466267 0.63450587 -0.32486862 0.5489589 -1.3371551
-0.1845428 -0.3407158 0.01930108 -0.19336407]
[ 0.5956444 -0.2708108 0.27161372 -0.4332114 -0.473155 -0.5902645
-0.7067252 -0.29935208 -0.40748447 -0.02663262 0.7250387 0.37857506
0.1831376 -0.17772828 -0.22422215 -0.03368116]
[-0.68832195 0.75668186 -0.57853657 0.18433066 0.03109945 0.14204665
0.13284403 -1.57638 0.25036728 -0.32798365 0.104678 -0.28829753
-0.7802544 0.30158752 0.35971668 -0.54211533]]

上面代码中,我们在[0, 10]范围内随机产生了3个整数,因此数据的最大值为整数9,最小为0。因此,输入数据映射为每个one-hot向量的维度是10,定义Embedding权重的第一个维度USR_ID_NUM为10。

这里输入的数据shape是[3, 1],Embedding层的权重形状则是[10, 16],Embedding在计算时,首先将输入数据转换成one-hot向量,one-hot向量的长度和Embedding层的输入参数size的第一个维度有关。比如这里我们设置的是10,所以输入数据将被转换成维度为[3, 10]的one-hot向量,参数size决定了Embedding层的权重形状。最终维度为[3, 10]的one-hot向量与维度为[10, 16]Embedding权重相乘,得到最终维度为[3, 16]的映射向量。我们也可以对Embeding层的权重进行初始化,如果不设置初始化方式,则采用默认的初始化方式。

神经网络处理文本数据时,需要用数字代替文本,Embedding层则是将输入数字数据映射成了高维向量,然后就可以使用卷积、全连接、LSTM等网络层处理数据了,接下来我们开始设计用户和电影数据的特征提取网络。

提供用户特征

用户特征网络主要包括:

  1. 将用户ID数据映射为向量表示,通过全连接层得到ID特征。
  2. 将用户性别数据映射为向量表示,通过全连接层得到性别特征。
  3. 将用户职业数据映射为向量表示,通过全连接层得到职业特征。
  4. 将用户年龄数据影射为向量表示,通过全连接层得到年龄特征。
  5. 融合ID、性别、职业、年龄特征,得到用户的特征表示。

在用户特征计算网络中,我们对每个用户数据做embedding处理,然后经过一个全连接层,激活函数使用ReLU,得到用户所有特征后,将特征整合,经过一个全连接层得到最终的用户数据特征,该特征的维度是200维,用于和电影特征计算相似度。

开始构建用户ID的特征提取网络,ID特征提取包括两个部分。首先,使用Embedding将用户ID映射为向量;然后,使用一层全连接层和ReLU激活函数进一步提取用户ID特征。 相比较电影类别和电影名称,用户ID只包含一个数字,数据更为简单。这里需要考虑将用户ID映射为多少维度的向量合适,使用维度过大的向量表示用户ID容易造成信息冗余,维度过低又不足以表示该用户的特征。理论上来说,如果使用二进制表示用户ID,用户最大ID是6040,小于2的13次方,因此,理论上使用13维度的向量已经足够了,为了让不同ID的向量更具区分性,我们选择将用户ID映射为维度为32维的向量。

1. 提取用户ID特征

# 自定义一个用户ID数据
usr_id_data = np.random.randint(0, 6040, (2)).reshape((-1)).astype(int64)
print("输入的用户ID是:", usr_id_data)

USR_ID_NUM = 6040 + 1
# 定义用户ID的embedding层和fc层
usr_emb = Embedding(num_embeddings=USR_ID_NUM,
embedding_dim=32,
sparse=False)
usr_fc = Linear(in_features=32, out_features=32)

usr_id_var = paddle.to_tensor(usr_id_data)
usr_id_feat = usr_fc(usr_emb(usr_id_var))

usr_id_feat = F.relu(usr_id_feat)
print("用户ID的特征是:", usr_id_feat.numpy(), "\\n其形状是:", usr_id_feat.shape)
输入的用户ID是: [3673  603]
用户ID的特征是: [[0. 0.01973414 0.02144782 0. 0. 0.
0.00363597 0. 0. 0. 0.00861626 0.03429735
0. 0.01516718 0.03690353 0. 0. 0.01882378
0. 0. 0.01090848 0.02734157 0. 0.01510335
0. 0. 0.00086916 0.00083421 0.0375373 0.01950407
0. 0.0036423 ]
[0.00177084 0.01983142 0. 0. 0. 0.00400646
0.02201955 0. 0. 0. 0. 0.
0. 0.00673456 0.00300174 0. 0.02012531 0.
0.00057964 0.00807733 0. 0. 0. 0.
0.00551907 0.01994854 0.01152299 0.01468143 0. 0.02226564
0.01047609 0. ]]
其形状是: [2, 32]

注意到,将用户ID映射为one-hot向量时,Embedding层参数size的第一个参数是,在用户的最大ID基础上加上1。原因很简单,从上一节数据处理已经发现,用户ID是从1开始计数的,最大的用户ID是6040。并且已经知道通过Embedding映射输入数据时,是先把输入数据转换成one-hot向量。向量中只有一个 1 的向量才被称为one-hot向量,比如,0 用四维的on-hot向量表示是[1, 0 ,0 ,0],同时,4维的one-hot向量最大只能表示3。所以,要把数字6040用one-hot向量表示,至少需要用6041维度的向量。

融合用户特征

特征融合是一种常用的特征增强手段,通过结合不同特征的长处,达到取长补短的目的。简单的融合方法有:特征(加权)相加、特征级联、特征正交等等。此处使用特征融合是为了将用户的多个特征融合到一起,用单个向量表示每个用户,更方便计算用户与电影的相似度。上文使用Embedding加全连接的方法,分别得到了用户ID、年龄、性别、职业的特征向量,可以使用全连接层将每个特征映射到固定长度,然后进行相加,得到融合特征。

这里使用全连接层进一步提取特征,而不是直接相加得到用户特征的原因有两点:

  • 一是用户每个特征数据维度不一致,无法直接相加;
  • 二是用户每个特征仅使用了一层全连接层,提取特征不充分,多使用一层全连接层能进一步提取特征。而且,这里用高维度(200维)的向量表示用户特征,能包含更多的信息,每个用户特征之间的区分也更明显。

上述实现中需要对每个特征都使用一个全连接层,实现较为复杂,一种简单的替换方式是,先将每个用户特征沿着长度维度进行级联,然后使用一个全连接层获得整个用户特征向量,两种方式的对比见下图:

深度学习——推荐算法基础原理_推荐系统_10

相似度计算

计算得到用户特征和电影特征后,我们还需要计算特征之间的相似度。如果一个用户对某个电影很感兴趣,并给了五分评价,那么该用户和电影特征之间的相似度是很高的。

衡量向量距离(相似度)有多种方案:欧式距离、曼哈顿距离、切比雪夫距离、余弦相似度等,本节我们使用忽略尺度信息的余弦相似度构建相似度矩阵。余弦相似度又称为余弦相似性,是通过计算两个向量的夹角余弦值来评估他们的相似度,如下图,两条红色的直线表示两个向量,之间的夹角可以用来表示相似度大小,角度为0时,余弦值为1,表示完全相似。

深度学习——推荐算法基础原理_数据_11

博文参考

深度学习基础-机器学习基本原理

前言

深度学习是机器学习的一个特定分支。我们要想充分理解深度学习,必须对机器学习的基本原理有深刻的理解。

大部分机器学习算法都有超参数(必须在学习算法外手动设定)。机器学习本质上属于应用统计学,其更加强调使用计算机对复杂函数进行统计估计,而较少强调围绕这些函数证明置信区间;因此我们会探讨两种统计学的主要方法: 频率派估计和贝叶斯推断。同时,大部分机器学习算法又可以分成监督学习无监督学习两类;本文会介绍这两类算法定义,并给出每个类别中一些算法示例。

本章内容还会介绍如何组合不同的算法部分,例如优化算法、代价函数、模型和数据 集,来建立一个机器学习算法。最后,在 5.11 节中,我们描述了一些限制传统机器学习泛化能力的因素。正是这些挑战推动了克服这些障碍的深度学习算法的发展。

5.1 学习算法

机器学习算法是一种能够从数据中学习的算法。这里所谓的“学习“是指:“如果计算机程序在任务 $T$ 中的性能(以 $P$ 衡量)随着经验 $E$ 而提高,则可以说计算机程序从经验 $E$ 中学习某类任务 $T$ 和性能度量 $P$。”-来自 Mitchell (1997)

5.1.1 任务 $T$

从 “任务” 的相对正式的定义上说,学习过程本身不能算是任务。学习是我们所谓的获取完成任务的能力。机器学习可以解决很多类型的任务,一些非常常见的机器学习任务列举如下:

  1. 分类:在这类任务中,计算机程序需要指定某些输入属于 $k$ 类中的哪一类,例如图像分类中的二分类问题,多分类、单标签问题、多分类多标签问题。
  2. 回归:在这类任务中,计算机程序需要对给定输入预测数值。为了解决这个任务,学习算法需要输出函数 $f : \\mathbbR^n \\to \\mathbbR$。除了返回结果的形式不一样外,这类 问题和分类问题是很像的。
  3. 机器翻译
  4. 结构化输出
  5. 异常检测
  6. 合成和采样
  7. 去噪
  8. 密度估计或概率质量函数估计
  9. 输入缺失分类
  10. 转录
  11. 缺失值填补

5.1.2 性能度量 $P$

为了评估机器学习算法的能力,我们必须设计其性能的定量度量,即算法的精度指标。通常,性能度量 $P$ 特定于系统正在执行的任务 $T$。

对于诸如分类、缺失输入分类和转录任务,我们通常度量模型的准确率(accu- racy)。准确率是指该模型输出正确结果的样本比率。我们也可以通过错误率(error rate)得到相同的信息。错误率是指该模型输出错误结果的样本比率。

我们使用测试集(test set)数据来评估系统性能,将其与训练机器学习系统的训练集数据分开。

值得注意的是,性能度量的选择或许看上去简单且客观,但是选择一个与系统理想表现能对应上的性能度量通常是很难的。

5.1.3 经验 $E$

根据学习过程中的不同经验,机器学习算法可以大致分类为两类

  • 无监督(unsuper-vised)算法
  • 监督(supervised)算法

无监督学习算法(unsupervised learning algorithm)训练含有很多特征的数据集,然后学习出这个数据集上有用的结构性质。在深度学习中,我们通常要学习生成数据集的整个概率分布,显式地,比如密度估计,或是隐式地,比如合成或去噪。 还有一些其他类型的无监督学习任务,例如聚类,将数据集分成相似样本的集合。

监督学习算法(supervised learning algorithm)也训练含有很多特征的数据集,但与无监督学习算法不同的是数据集中的样本都有一个标签(label)或目标(target)。例如,Iris 数据集注明了每个鸢尾花卉样本属于什么品种。监督学习算法通过研究 Iris 数据集,学习如何根据测量结果将样本划分为三个不同品种。

半监督学习算法中,一部分样本有监督目标,另外一部分样本则没有。在多实例学习中,样本的整个集合被标记为含有或者不含有该类的样本,但是集合中单独的样本是没有标记的。

大致说来,无监督学习涉及到观察随机向量 $x$ 的好几个样本,试图显式或隐式地学习出概率分布 $p(x)$,或者是该分布一些有意思的性质; 而监督学习包含观察随机向量 $x$ 及其相关联的值或向量 $y$,然后从 $x$ 预测 $y$,通常是估计 $p(y | x)$。术语监督学习(supervised learning)源自这样一个视角,教员或者老师提供目标 $y$ 给机器学习系统,指导其应该做什么。在无监督学习中,没有教员或者老师,算法必须学会在没有指导的情况下理解数据。

无监督学习和监督学习并不是严格定义的术语。它们之间界线通常是模糊的。很多机器学习技术可以用于这两个任务。

尽管无监督学习和监督学习并非完全没有交集的正式概念,它们确实有助于粗略分类我们研究机器学习算法时遇到的问题。传统地,人们将回归、分类或者结构化输出问题称为监督学习。支持其他任务的密度估计通常被称为无监督学习。

表示数据集的常用方法是设计矩阵(design matrix)。

5.1.4 示例: 线性回归

我们将机器学习算法定义为,通过经验以提高计算机程序在某些任务上性能的算法。这个定义有点抽象。为了使这个定义更具体点,我们展示一个简单的机器学习示例: 线性回归(linear regression)。

顾名思义,线性回归解决回归问题。 换句话说,目标是构建一个系统,该系统可以将向量 $x \\in \\mathbbR$ 作为输入,并预测标量 $y \\in \\mathbbR$ 作为输出。在线性回归的情况下,输出是输入的线性函数。令 $\\haty$ 表示模型预测值。我们定义输出为

$$\\haty = w^⊤x \\tag5.3$$

其中 $w \\in \\mathbbR^n$ 是参数(parameter)向量。

参数是控制系统行为的值。在这种情况下,$w_i$ 是系数,会和特征 $x_i$ 相乘之 后全部相加起来。我们可以将 $w$ 看作是一组决定每个特征如何影响预测的权重 (weight)。

通过上述描述,我们可以定义任务 $T$ : 通过输出 $\\haty = w^⊤x$ 从 $x$ 预测 $y$。

我们使用测试集test set)来评估模型性能如何,将输入的设计矩 阵记作 $\\textitX$(test),回归目标向量记作 $y$(test)。

回归任务常用的一种模型性能度量方法是计算模型在测试集上的 均方误差(mean squared error)。如果 $\\haty$(test) 表示模型在测试集上的预测值,那么均方误差表示为:

$$MSE_test = \\frac1m \\sum_i(\\haty^(test)-y^(test))_i^2 \\tag5.4$$

直观上,当 $\\haty^(test)$ = $y^(test)$ 时,我们会发现误差降为 0。

图 5.1 展示了线性回归算法的使用示例。

5.2 容量、过拟合和欠拟合

机器学习的挑战主要在于算法如何在测试集(先前未观测的新输入数据)上表现良好,而不只是在训练集上表现良好,即训练误差和泛化误差读比较小,也可理解为算法泛化性比较好。所谓泛化性(generalized)好指的是,算法在在测试集(以前未观察到的输入)上表现良好。

机器学习算法的两个主要挑战是: 欠拟合underfitting)和过拟合overfitting)。

  • 欠拟合是指模型不能在训练集上获得足够低的误差。
  • 而过拟合是指训练误差和和测试误差之间的差距太大。

通过调整模型的容量capacity),我们可以控制模型是否偏向于过拟合或者欠拟合。通俗地讲,模型的容量是指其拟合各种函数的能力。容量低的模型可能很难拟合训练集,容量高的模型可能会过拟合,因为记住了不适用于测试集的训练集性质。

一种控制训练算法容量的方法是选择假设空间(hypothesis space),即学习算法可以选择作为解决方案的函数集。例如,线性回归算法将其输入的所有线性函数的集合作为其假设空间。我们可以推广线性回归以在其假设空间中包含多项式,而不仅仅是线性函数。这样做就增加模型的容量。

当机器学习算法的容量适合于所执行任务的复杂度和所提供训练数据的数量时,算法效果通常会最佳。容量不足的模型不能解决复杂任务。容量高的模型能够解决复杂的任务,但是当其容量高于任务所需时,有可能会过拟合。

图 5.2 展示了上述原理的使用情况。我们比较了线性,二次和 9 次预测器拟合真实二次函数的效果。

提高机器学习模型泛化性的早期思想是奥卡姆剃刀原则,即选择“最简单”的那一个模型。

统计学习理论提供了量化模型容量的不同方法。在这些中,最有名的是 Vapnik- Chervonenkis 维度(Vapnik-Chervonenkis dimension, VC)。VC 维度量二元分类 器的容量。VC 维定义为该分类器能够分类的训练样本的最大数目。假设存在 $m$ 个 不同 $x$ 点的训练集,分类器可以任意地标记该 $m$ 个不同的 $x$ 点,VC 维被定义为 $m$ 的最大可能值。

因为可以量化模型的容量,所以使得统计学习理论可以进行量化预测。统计学习理论中最重要的结论阐述了训练误差和泛化误差之间差异的上界随着模型容量增长而增长,但随着训练样本增多而下降 (Vapnik and Chervonenkis, 1971; Vapnik, 1982; Blumer et al., 1989; Vapnik, 1995)。这些边界为机器学习算法可以有效解决问题提供了理论 验证,但是它们很少应用于实际中的深度学习算法。一部分原因是边界太松,另一部分原因是很难确定深度学习算法的容量。由于有效容量受限于优化算法的能力,所以确定深度学习模型容量的问题特别困难。而且我们对深度学习中涉及的非常普遍的非凸优化问题的理论了解很少。

虽然更简单的函数更可能泛化(训练误差和测试误差的差距小),但我们仍然必须选择一个足够复杂的假设来实现低训练误差。通常,随着模型容量的增加,训练误差会减小,直到它逐渐接近最小可能的误差值(假设误差度量具有最小值)。通常,泛化误差是一个关于模型容量的 U 形曲线函数。如下图 5.3 所示。

5.2.1 没有免费午餐定理

机器学习的没有免费午餐定理Wolpert,1996)指出,对所有可能的数据生成分布进行平均,每个分类算法在对以前未观察到的点进行分类时具有相同的错误率。换句话说,在某种意义上,没有任何机器学习算法普遍优于其他任何算法

上述这个结论听着真的让人伤感,但庆幸的是,这些结论仅在我们考虑所有可能的数据生成分布时才成立。如果我们对实际应用中遇到的概率分布类型做出假设,那么我们可以设计出在这些分布上表现良好的学习算法

这意味着机器学习研究的目标不是找一个通用学习算法或是绝对最好的学习算法。反之,我们的目标是理解什么样的分布与人工智能获取经验的 “真实世界” 相关,什么样的学习算法在我们关注的数据生成分布上效果最好

总结:没有免费午餐定理清楚地阐述了没有最优的学习算法,即暗示我们必须在特定任务上设计性能良好的机器学习算法。

5.2.2 正则化

所谓正则化,是指我们通过修改学习算法,使其降低泛化误差而非训练误差的方法。

正则化是一种思想(策略),它是机器学习领域的中心问题之一,其重要性只有优化能与其相媲美。

一般地,正则化一个学习函数 $f(x;\\theta)$ 的模型,我们可以给代价函数添加被称为正则化项(regularizer)的惩罚。如果正则化项是 $\\Omega(w) = w^\\topw$,则称为权重衰减(weight decay)。

例如,我们可以加入权重衰减(weight decay)来修改线性回归的目标函数,如偏好于平方 $L^2$ 范数较小权重的目标函数形式:

$$J(w) = MSE_train + \\lambda w^⊤w \\tag5.18$$

其中 $J(w)$ 是目标函数,$w$ 是权重参数。$\\lambda$ 是超参数,需提前设置,其控制我们对较小权重的偏好强度。当 $\\lambda = 0$,我们没有任何偏好。$\\lambda$ 越大,则权重越小。最小化 $J(w)$ 会导致权重的选择在拟合训练数据和较小权重之间进行权衡

和上一节没有最优的学习算法一样,一样的,也没有最优的正则化形式。反之,我们必须挑选一个非常适合于我们所要解决的任务的正则形式。

5.3 超参数和验证集

超参数的值不是通过学习算法本身学习出来的,而是需要算法定义者手动指定的

5.3.1 验证集的作用

通常,80% 的训练数据用于训练,20% 用于验证。验证集是用于估计训练中或训练后的泛化误差,从而更新超参数

5.3.2 交叉验证

一个小规模的测试集意味着平均测试误差估计的统计不确定性,使得很难判断算法 A 是否比算法 B 在给定的任务上做得更好。解决办法是基于在原始数据上随机采样或分离出的不同数据集上重复训练和测试,最常见的就是 $k$-折交叉验证,即将数据集分成 $k$ 个 不重合的子集。测试误差可以估计为 $k$ 次计算后的平均测试误差。在第 $i$ 次测试时, 数据的第 $i$ 个子集用于测试集,其他的数据用于训练集。算法过程如下所示。

5.4 估计、偏差和方差

统计领域为我们提供了很多工具来实现机器学习目标,不仅可以解决训练集上 的任务,还可以泛化。基本的概念,例如参数估计、偏差和方差,对于正式地刻画泛化、欠拟合和过拟合都非常有帮助。

5.4.1 点估计

点估计试图为一些感兴趣的量提供单个 ‘‘最优’’ 预测。一般地,感兴趣的量可以是单个参数也可以是一个向量参数,例如第 5.1.4 节线性回归中的权重,但是也有可能是整个函数。

为了区分参数估计和真实值,我们习惯将参数 $\\theta$ 的点估计表示为 $\\hat\\theta$。

令 $x^(1), . . . , x^(m)$ 是 $m$ 个独立同分布(i.i.d.)的数据点。 点估计(point esti-mator)或统计量(statistics)是这些数据的任意函数: $$ \\hat\\theta_m =g(x^(1),...,x^(m)). \\tag5.19 $$

5.4.2 偏差

估计的偏差定义如下: $$ bias(\\hat\\theta_m) = E(\\hat\\theta_m) − \\theta, \\tag5.19 $$ 其中期望作用在所有数据(看作是从随机变量采样得到的)上,$\\hat\\theta$ 是用于定义数据生成分布的 $\\theta$ 的真实值。如果 $bias(\\hat\\theta_m) = 0$,那么估计量 $\\hat\\theta_m$ 则被称为是无偏 (unbiased),同时意味着 $E(\\hat\\theta_m) = \\theta$。

5.4.3 方差和标准差

方差记为 $Var(\\hat\\theta)$ 或 $\\sigma^2$,方差的平方根被称为标准差。

5.4.4 权衡偏差和方差以最小化均方误差

偏差和方差度量着估计量的两个不同误差来源。偏差度量着偏离真实函数或参数的误差期望。而方差度量着数据上任意特定采样可能导致的估计期望的偏差。

偏差和方差的关系和机器学习容量、欠拟合和过拟合的概念紧密相联。用 MSE 度量泛化误差(偏差和方差对于泛化误差都是有意义的)时,增加容量会增加方差,降低偏差。如图 5.6 所示,我们再次在关于容量的函数中,看到泛化误差的 U 形曲线。

5.5,最大似然估计

与其猜测某个函数可能是一个好的估计器,然后分析它的偏差和方差,我们更希望有一些原则,我们可以从中推导出特定的函数,这些函数是不同模型的良好估计器。最大似然估计就是其中最为常用的准则。

5.6 贝叶斯统计

到目前为止,我们已经描述了频率统计(frequentist statistics)和基于估计单一 $\\theta$ 值的方法,然后基于该估计作所有的预测。 另一种方法是在进行预测时考虑所有可能的 $\\theta$ 值。 后者属于贝叶斯统计(Bayesian statistics)的范畴。

如 5.4.1 节中讨论的,频率派的视角是真实参数 $\\theta$ 是未知的定值,而点估计 $\\hat\\theta$ 是考虑数据集上函数(可以看作是随机的)的随机变量。

贝叶斯统计的视角完全不同。贝叶斯用概率反映知识状态的确定性程度。数据集能够被直接观测到,因此不是随机的。另一方面,真实参数 $\\theta$ 是未知或不确定的, 因此可以表示成随机变量。

5.7 监督学习算法

回顾 5.1.3 节内容,简单来说,监督学习算法是给定一组输入 $x$ 和输出 $y$ 的训练 集,学习如何关联输入和输出。在许多情况下,输出 $y$ 可能难以自动收集,必须由人类“监督者”提供,但即使训练集目标是自动收集的,该术语仍然适用。

5.8 无监督学习算法

回顾第5.1.3节,无监督算法只处理 “特征’’,不操作监督信号。监督和无监督算法之间的区别没有规范严格的定义,因为没有客观的测试来区分一个值是特征还是监督者提供的目标。通俗地说,无监督学习的大多数尝试是指从不需要人为注释的样本的分布中提取信息。该术语通常与密度估计相关,学习从分布中采样、学习从分布中去噪、寻找数据分布的流形或是将数据中相关的样本聚类。

5.8.1 PCA 降维

PCA(Principal Component Analysis)是学习数据表示的无监督学习算法,常用于高维数据的降维,可用于提取数据的主要特征分量。

PCA 的数学推导可以从最大可分型和最近重构性两方面进行,前者的优化条件为划分后方差最大,后者的优化条件为点到划分平面距离最小。

5.8.2 k-均值聚类

另外一个简单的表示学习算法是 $k$-均值聚类。$k$-均值聚类算法将训练集分成 $k$ 个靠近彼此的不同样本聚类。因此我们可以认为该算法提供了 $k$-维的 one-hot 编码向量 $h$ 以表示输入 $x$。当 $x$ 属于聚类 $i$ 时,有 $h_i = 1$,$h$ 的其他项为零。

$k$-均值聚类初始化 k 个不同的中心点 $μ^(1), . . . , μ^(k)$,然后迭代交换以下两个不同的步骤直到算法收敛。

  1. 步骤一,每个训练样本分配到最近的中心点 $μ^(i) $ 所代表的聚类 $i$。
  2. 步骤二,每一个中心点 $μ^(i) $ 更新为聚类 $i$ 中所有训练样本 $x^(j)$ 的均值。

关于聚类的一个问题是聚类问题本身是病态的。这是说没有单一的标准去度量聚类的数据在真实世界中效果如何。我们可以度量聚类的性质,例如类中元素到类中心点的欧几里得距离的均值。这使我们可以判断从聚类分配中重建训练数据的效果如何。然而我们不知道聚类的性质是否很好地对应到真实世界的性质。此外,可能有许多不同的聚类都能很好地对应到现实世界的某些属性。我们可能希望找到和 一个特征相关的聚类,但是得到了一个和任务无关的,同样是合理的不同聚类。

例如,假设我们在包含红色卡车图片、红色汽车图片、灰色卡车图片和灰色汽车图片的数据集上运行两个聚类算法。如果每个聚类算法聚两类,那么可能一个算法将汽车和卡车各聚一类,另一个根据红色和灰色各聚一类。假设我们还运行了第三个聚类算法,用来决定类别的数目。这有可能聚成了四类,红色卡车、红色汽车、灰色卡 车和灰色汽车。现在这个新的聚类至少抓住了属性的信息,但是丢失了相似性信息。 红色汽车和灰色汽车在不同的类中,正如红色汽车和灰色卡车也在不同的类中。该聚类算法没有告诉我们灰色汽车和红色汽车的相似度比灰色卡车和红色汽车的相似度更高,我们只知道它们是不同的。

5.9 随机梯度下降

几乎所有的深度学习算法都用到了一个非常重要的优化算法: 随机梯度下降 (stochastic gradient descent, SGD)。

机器学习中反复出现的一个问题是好的泛化需要大的训练集,但大的训练集的 计算代价也更大。

机器学习算法中的代价函数通常可以分解成每个样本的代价函数的总和。

随机梯度下降的核心是,梯度是期望,而期望可使用小规模的样本近似估计。具体来说,在算法的每一步,我们从训练集中均匀抽出一小批量(minibatch)样本 $B=x^(1),...,x^(m′)$。小批量的数目 $m′$ 通常是一个相对较小的数,一般为 $2^n$(取决于显卡显卡)。重要的是,当训练集大小 m 增长时,$m′$ 通常是固定的。我们可能在拟合几十亿的样本时,但每次更新计算只用到几百个样本。

梯度下降往往被认为很慢或不可靠。以前,将梯度下降应用到非凸优化问题被认为很鲁莽或没有原则。但现在,我们知道梯度下降用于深度神经网络模型的训练时效果是不错的。优化算法不一定能保证在合理的时间内达到一个局部最小值,但它通常能及时地找到代价函数一个很小的值,并且是有用的。

随机梯度下降在深度学习之外有很多重要的应用。它是在大规模数据上训练大型线性模型的主要方法。对于固定大小的模型,每一步随机梯度下降更新的计算量 不取决于训练集的大小 m。在实践中,当训练集大小增长时,我们通常会使用一个更大的模型,但这并非是必须的。达到收敛所需的更新次数通常会随训练集规模增大而增加。然而,当 m 趋向于无穷大时,该模型最终会在随机梯度下降抽样完训练 集上的所有样本之前收敛到可能的最优测试误差。继续增加 m 不会延长达到模型可能的最优测试误差的时间。从这点来看,我们可以认为用 SGD 训练模型的渐近代价是关于 m 的函数的 $O(1)$ 级别。

5.10 构建机器学习算法 pipeline

几乎所有的深度学习算法都可以被描述为一个相当简单的 pipeline:

  1. 特定的数据集
  2. 代价函数
  3. 优化过程
  4. 神经网络模型。

参考资料

以上是关于深度学习——推荐算法基础原理的主要内容,如果未能解决你的问题,请参考以下文章

推荐算法的基于协同过滤的推荐

协同过滤算法介绍及算法实现

传统机器学习和前沿深度学习推荐模型演化关系介绍

推荐算法之基于物品的协同过滤

推荐算法---模式场景

10种传统机器学习算法