实用机器学习课程笔记(Stanford)

  1. 1. 概论
    1. 1.1 课程介绍
    2. 1.2 数据获取
    3. 1.3 网页数据抓取
    4. 1.4 数据标注
  2. 2. 机器学习模型
    1. 2.1 机器学习模型概览
    2. 2.2 决策树
    3. 2.3 线性模型
    4. 2.4 神经网络
    5. 2.5 卷积神经网络
    6. 2.6 循环神经网络
  3. 3. 模型评估
    1. 3.1 评估指标

Stanford 2021 秋季实用机器学习课程学习笔记。

1. 概论

1.1 课程介绍

Challenges

  • Formulate problem:关注最具影响力的行业问题(如自助超市、自动驾驶汽车等)。
  • Data:高质量数据的稀缺、隐私问题。
  • Train models:模型越来越复杂,需要大量数据,成本也越来越高。
  • Deploy models:计算量大,不适合实时推理。
  • Monitor:数据分布的变化、公平性问题。

Roles(不同类型的人在 ML 中的作用)

  • Domain experts(领域专家):具有商业洞察力,知道什么数据是重要的以及在哪可以找到它,确定一个 ML 模型真正的影响。
  • Data scientists:在 Data mining、Model training and deployment 方面做全栈的工作。
  • ML experts:定制最先进(state of the art,SOTA)的 ML models。
  • SDE(软件开发工程师):开发/维护数据管道、模型训练和服务管道。

Corse topics

本课程的内容为数据科学家需要的技术,但是没有大学传统的 ML/统计/编程方面的教学。

  • Data
    • 收集、处理数据。
    • 部署的时候场景发生变化导致数据不一样,如 covariate(协变量)、concepts、label 的改变。
    • 独立同分布之外的数据。
  • Train
    • 模型验证、融合、调优。
    • 迁移学习(Transfer learning)。
    • 多模态(Multi-modality):如何把不同的数据源融合起来做一个比较大的模型。
  • Deploy
    • 模型怎样部署。
    • 蒸馏(Distillation):将比较大的模型提取出精华做的小一点。
  • Monitor
    • 公平性,之后会讲模型的公平是什么含义。
    • 可解释性,怎样理解模型在干什么。

1.2 数据获取

Flow Chart for data acquisition

Discover what data is available

  • 找已经有的数据集。
  • 找基准数据集来检验我们的想法:
    • 例如要做一个新的调超参数的算法,可能需要找一些数据集,且数据集不能太大,要小一点的或者中等大小的,为了客观地检验算法还要考虑找不同方面的数据集。
    • 如果训练比较深的神经网络就需要非常大的数据集。
  • 收集新数据(做一个应用或产品很多时候没有现成的数据集)

Source of popular ML datasets

  • MNIST:手写数字。
  • ImageNet:百万级别的来自搜索引擎的图片,可训练较为深度的模型。
  • AudioSet:YouTube 上的一些声音的切片,用于做声音的分类。
  • Kinetics:YouTube 上的一些视频的切片,用于人的行为分类。
  • KITTI:摄像头或激光雷达等各种 sensor 记录下的交通场景。
  • Amazon Review:Amazon 产品的用户评论。
  • SQuAD:维基中的一些 Q-A 对。
  • Librispeech:1000小时的有声读物。

数据集两大来源:各个网站上爬取,采集数据。

Where to find datasets

  • Paperwithcodes Datasets:学术数据集与排行榜。
  • Kaggle Datasets:数据科学家提交的 ML datasets。
  • Google Dataset search:搜索网页上的数据集。
  • Various toolkits datasets(开源工具包):TensorFlow、HuggingFace。
  • 会议/公司的 ML 竞赛。
  • 自己组织的 Data lakes(数据湖)。

Datasets comparison

数据集 好处 坏处
学术数据集 数据干净、难度适中 选择面较小、太精简、规模小
竞赛数据集 更接近真实的 ML 应用 仍较精简,且只专注在较热门的应用
原生数据 很灵活 需要很多精力去预处理

Data integration

产品数据通常存放在不同的表中,因此要涉及到表的连接。

Table 1
ID Val 1 Val 2
1 1_val1 1_val2
2 2_val1 2_val2
Table 2
ID Val 3 Val 4
1 1_val3 1_val4
3 3_val3 3_val4
Inner Join T1 & T2
ID Val 1 Val 2 Val 3 Val 4
1 1_val1 1_val2 1_val3 1_val4
Left Join T1 & T2
ID Val 1 Val 2 Val 3 Val 4
1 1_val1 1_val2 1_val3 1_val4
2 2_val1 2_val2 / /

1.3 网页数据抓取

  • 一般不能用 curl,因为网站所有者能使用各种方法阻止。
  • 使用无头浏览器(一个没有 GUI 的网络浏览器):
1
2
3
4
5
6
7
from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
chrome_options.headless = True
chrome = webdriver.Chrome(chrome_options = chrome_options)

page = chrome.get(url)
  • 你需要大量的新 IP,可以通过云获得很多 IP。

1.4 数据标注

半监督学习Semi-Supervised Learning(SSL)

  • 重点关注有少量标记数据和大量未标记数据的场景。
  • 对没有标注的数据和有标注的数据的数据分布做一些假设:
    • 连续性假设(Continuity assumption):如果一个样本的特征和另外一个样本相似,那么这两个样本很可能具有相同的标号。
    • 聚类假设(Cluster assumption):数据具有内在的聚类结构,那么假设一个类里面具有相同的标号。
    • 流形假设(Manifold assumption):很有可能数据在本质上是在低维的一个流形上分布的。

自学习Self-training

主动学习Active Learning

  • 关注的场景与 SSL 相同,但有人工干预,即选择最有趣的数据(最重要的没有标号的数据)给标注工标注。
  • 不确定性抽样(Uncertainty sampling):选择一个最不确信的预测让人来判断。

Active Learning + Self-training

弱监督学习Weak Supervision

  • 半自动地生成标号,通常比手动标注的准确率差,但是也是好到可以训练一个还不错的模型。
  • 数据编程(Data programming):用启发式的方法赋予标号:
    • 关键字搜索、模式匹配、第三方模型。
    • 假设判断一个 YouTube 的评论是垃圾(spam)还是有用的东西(ham):
1
2
3
4
5
def check_out(x):
return SPAM if 'check out' in x.lower() else ABSTAIN

def sentiment(x):
return HAM if sentiment_polarity(x) > 0.9 else ABSTAIN

2. 机器学习模型

2.1 机器学习模型概览

ML 算法的种类

  • 监督学习(Supervised):训练有标签的数据来预测标签。
    • 自监督学习(Self-supervised):标签的生成来自于数据本身。
  • 半监督学习(Semi-supervised):在有标签和无标签的数据上进行训练,使用模型来预测无标签数据的标签。
  • 无监督学习(Unsupervised):在未标记的数据上进行训练。
  • 强化学习(Reinforcement):利用观察与环境互动的结果来采取行动以最大化收益。

本课程最多讨论的内容为监督学习。

监督学习的组成部分

  • 模型(Model):将输入映射到标签的参数化函数。
  • 损失(Loss):衡量模型在预测结果方面有多好,即衡量模型预测出来的值和真实值之间的差距,需要指导模型尽量向真实值靠近。
  • 目标函数(Objective):优化模型参数的目标,例如需要优化模型在训练集合上的所有预测结果的损失之和最小。
  • 优化(Optimization):解决 Objective 的算法,即把模型中没有指定的参数(可学习的参数)优化为合适的值,使得能够解决目标函数,也就是最小化损失。

监督学习的模型

  • 决策树(Decision trees):用树来做决定。
  • 线性模型(Linear methods):决策是根据输入特征的线性组合做出的。
  • 核方法(Kernel machines):使用核函数衡量两个样本的特征相似度,达到非线性的效果。
  • 神经网络(Neural Networks):使用神经网络学习特征表示。

2.2 决策树

优点:

  • 可以用来解释,即训练后的模型可以看到叶子结点是什么内容,决策是怎么一步步做下来的。
  • 能够处理数值和类别的特征。

缺点:

  • 非常不稳定,可能数据内产生了一点噪音后整棵树构建出来的样子就不一样了。
  • 如果数据特别复杂,会生成一个特别复杂的树,可以把整个数据里面的各种情况列出来,生成大量的节点,最后会导致过拟合。
  • 不容易并行计算。

随机森林

  • 训练多个决策树以提高稳定性。
    • 树是并行地独立训练的。
    • 对于分类问题可以用多数投票法(例如超过一半的树觉得类别是1,那么它就是1),对于回归问题可以在多棵树上取平均。
  • 为什么叫随机呢?
    • Bagging:随机抽取训练样本并进行替换。例如样本本来是 [1, 2, 3, 4, 5],做 Bagging 的时候在里面随机采样5个出来,但是采样可能是有重复的,采样到的结果为 [1, 2, 2, 3, 4],然后拿到这个 Bagging 出来的数据集后我们就在上面训练一棵树,然后一直重复训练 N 棵树为止。
    • 随机选择一个特征子集,即把 Bagging 出的数据拿出来之后,再从里面的特征中随机采样一些特征列出来(假设树是一个表,那么就是先随机采样出一些行,再随机采样出一些列)

2.3 线性模型

线性回归

  • 一个简单的房价预测模型:
    • 假设有3个特征:卧室数量 x1、浴室数量 x2、居住面积 x3
    • 预测价格为:y_hat = w1 * x1 + w2 * x2 + w3 * x3 + b
    • 权重 w1, w2, w3 和偏置 b 将从训练数据中学习。
  • 一般来说,给定数据 x = [x1, x2, ..., xp],线性回归的预测为:y_hat = w1 * x1 + w2 * x2 + ... + wp * xp + b = <w, x> + b(其中 wx 为长度为 p 的向量,<> 表示内积运算,wb 都是可学习参数)。
1
2
3
4
# weight w has shape (p, 1)
# bias b is a scalar
# data x has shape (p, 1)
y_hat = (x * w).sum() + b

线性回归目标函数

假设我们收集了 n 个训练样本 X = [x1, x2, ..., xn],其中每个 xi 均为长为 p 的向量,将其转置后即为一个 np 列的矩阵,其对应的标号为 y = [y1, ..., yn],是一个长为 n 的向量。

目标函数是最小化均方误差(MSE),即优化 w, b 的值使得 sum((yi - <xi, w> - b)**2) / n 最小。

线性回归在分类问题中的应用

回归的输出是一个连续的实数,而对于分类问题,我们要输出对某个样本的类别的预测。

多类别分类:

  • 假设标签为独热编码,即 y = [y1, y2, ..., ym],如果该样本为第 i 类则 yi = 1,否则 yi = 0
  • 预测结果 y_hat = [o1, o2, ..., om],其中 oi 表示预测该样本为第 i 类的概率。
  • 为每个类学习一个线性模型:oi = <x, wi> + bi
  • 最小化 MSE 损失函数:(y_hat - y)**2 / m
  • 预测结果所表示的类为 m 个概率中最大的那个,即 argmax(y_hat)

Mini-batch 随机梯度下降

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 'batch_size' 为批大小,'features' 为所有样本的特征即 X,'labels' 为标签
# 'features' shape is (n, p), `labels` shape is (n, 1)
def data_iter(batch_size, features, labels):
num_examples = len(features) # 样本数
indices = list(range(num_examples)) # 下标
random.shuffle(indices) # 随机打乱
for i in range(0, num_examples, batch_size):
batch_indices = torch.tensor(
indices[i:min(i + batch_size, num_examples)]
)
yield features[batch_indices], labels[batch_indices]

# w 用均值为0,方差为0.01的高斯分布初始化
w = torch.normal(0, 0.01, size=(p, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

for epoch in range(num_epochs):
for x, y in data_iter(batch_size, features, labels): # 随机取出一个 batch
y_hat = np.dot(x, w) + b
loss = ((y_hat - y)**2 / 2).mean()
loss.backward()
for param in [w, b]:
param -= learning_rate * param.grad
param.grad.zero_()

2.4 神经网络

神经网络就是将手工特征提取的部分换成了一个神经网络。

  • 神经网络通常需要更多的数据和更多的计算,一般都是大数个数量级
  • 可以选择不同的神经网络架构来更有效地抽取我们的特征:
    • 多层感知机。
    • 卷积神经网络。
    • 循环神经网络。
    • Transformers。
  • 设计神经网络以结合数据的先验知识。

线性模型到多层感知机(Multilayer Perceptron,MLP)

  • 引入一种全连接层(稠密层,dense),假设输入样本数量为 n,每个样本的特征长度为 m,那么全连接层具有两个可学习参数 w, b,其中 w 是一个 nm 列的实数矩阵,b 是一个长为 n 的向量。则全连接层的计算结果为:y = np.dot(w, x) + b
  • 线性回归可以认为是一个只有一个输出的全连接层。
  • Softmax 回归可以认为是一个有 C 个输出的全连接层,C 表示类别的数量。

多层感知机的目的是实现一个非线性的模型,但是如果只是简单使用多个全连接层是没用的,多个线性操作的叠加还是一个线性操作,因此还需要加入非线性函数(激活函数)。

  • 激活函数是一个基于元素的非线性函数:
    • sigmoid(x) = 1 / (1 + np.exp(-x))
    • relu(x) = max(x, 0)
    • 非线性的激活函数能让我们得到非线性模型。
  • 可以堆叠多个隐藏层(例如多个 dense 层和 activation 层堆叠),得到更深层次的模型。
  • 超参数:隐藏层数量 hidden layers,每个隐藏层的输出大小 outputs of each hidden layer(最后一层的输出无法改变)。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
def relu(×):
return torch.max(x, 0)

# 'num_hiddens' 为超参数,randn() 产生均值为0,方差为1的正态分布
w1 = nn.Parameter(torch.randn(num_inputs, num_hiddens) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens))
w2 = nn.Parameter(torch.randn(num_hiddens, num_outputs) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs))

H = relu(np.dot(x, w1) + b1)
Y = np.dot(H, w2) + b2

2.5 卷积神经网络

全连接层到卷积神经网络

  • 以一个图像识别任务为例,使用 MLP 模型学习 ImageNet(每张图像大小为300*300像素,有1000个类别),我们假设其中一个隐藏层具有10000个输出:
    • 它会产生10亿个可学习参数,这太大了!
    • 因为全连接的输出是所有输入元素的加权和,而且每个输出的权重是不一样的。
  • 识别图像中的物体:
    • 平移不变性:无论对象在哪里,输出都是相似的。
    • 局部性:像素与其周围像素的相关性比较高,因为图像中的物体都是连续性的。
  • 将先验知识构建到模型结构中:
    • 用更少的参数(#params)实现相同的模型容量。

卷积层(Convolution layer)

  • 局部性:从 k * k 大小的输入窗口计算输出,即做局部的计算。
  • 平移不变性:输出使用相同的 k * k 权重(核)。
  • 卷积层的模型参数不依赖于输入/输出的大小。
  • 一个卷积核可以被学习成去识别一个图像里面的模式,比如识别绿色通道中的某个块状物体,识别某个方向上的纹理

代码:

1
2
3
4
5
6
7
# both input `X` and weight `K` are matrices(矩阵)
h, w = K.shape # 一般长和宽都是相等的,例如3、5
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1)) # 卷积输出的矩阵
# stride = 1
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()

池化层(Pooling layer)

  • 卷积层对输入的位置很敏感,即输入中模式的转换/旋转会导致输出中模式类似地变化,因此我们需要一定的对未知移动的鲁棒性。
  • 池化层在大小为 k * k 的窗口中计算平均值/最大值/最小值。

代码:

1
2
3
4
5
6
7
8
9
# h, w: pooling window height and width
# mode: max or avg
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i:i + h, j:j + w].max()
elif mode == 'avg':
Y[i, j] = X[i:i + h, j:j + w].mean()

卷积神经网络(Convolutional Neural Networks,CNN)

  • 卷积神经网络的原理为叠加卷积层来提取特征。
    • 激活函数应用于每个卷积层之后。
    • 使用池化操作来降低位置敏感性。
  • 现代 CNN 是具有各种超参数和层连接的深度神经网络(AlexNet, VGG, inception, ResNet, MobileNet)。

2.6 循环神经网络

全连接层到循环神经网络

  • 语言模型:给出一个句子前面的一些词,预测下一个词是什么。例如:hello -> worldhello world -> !
  • 单纯使用 MLP 不能很好地处理序列信息,例如长度的变化和时序的变化。

循环神经网络的原理为将上一个全连接层输出的状态复制一份作为隐藏状态 H,与下一个输入状态进行拼接后再进行预测。即:h_t = RNN(W_hh * h' + W_hx * x_t + b_h),其中 h' 为隐藏状态,x_t 为当前输入。

代码:

1
2
3
4
5
6
7
8
9
10
W_xh = nn.Parameter(torch.randn(num_inputs, num_hiddens) * 0.01)
W_hh = nn.Parameter(torch.rand(num_hiddens, num_hiddens) * 0.01)
b_h = nn.Parameter(torch.zeros(num_hiddens))

H = torch.zeros(num_hiddens)
outputs = []

for X in inputs: # `inputs` shape : (num_steps, batch_size, num_inputs),num_steps表示时间维度
H = torch.tanh(np.dot(X, W_xh) + np.dot(H, W_hh) + b_h)
outputs.append(H)

3. 模型评估

3.1 评估指标

  • 损失(Loss)衡量模型在预测监督学习结果的方面有多好。
  • 评估模型性能的其他指标:
    • 模型相关的指标:例如分类的精度,物体检测的 mAP。
    • 商业相关的指标:例如收益,推理延迟(如模型能在100毫秒之内返回结果)。
  • 我们一般通过考虑多种指标来选择模型。

二分类的评估指标

  • Accuracy:正确的预测数量/样本总数
1
sum(y == y_hat) / y.size
  • Precision:预测结果为类 i 且实际结果也为类 i 的数量/预测结果为类 i 的数量
1
sum((y_hat == i) & (y == i)) / sum(y_hat == i)
  • Recall:预测结果为类 i 且实际结果也为类 i 的数量/实际结果为类 i 的数量
1
sum((y_hat == i) & (y == i)) / sum(y == i)
  • F1:平衡 Precision 和 Recall 的指标,为 Precision 和 Recall 的调和平均值:2pr / (p + r)

二分类中的 AUC 和 ROC

  • AUC 为 ROC 曲线下的面积,大小范围为 [0.5, 1]
  • 衡量模型分离这两个类的能力。
  • 选择决策阈值 x,如果输出 y_hat >= x 则预测为正类,否则为负类。

展示广告的商业指标

  • 最优化收入和客户体验。
    • Latency:广告应该与其他内容同时显示给用户。
    • ASN:平均每页显示的广告数量。
    • CTR:用户实际点击率。
    • ACP:广告商每次点击支付的平均价格。
  • 收益 = 页面浏览量 * ASN * CTR * ACP。