“等式到代码”机器学习项目演练—第 2 部分非线性可分问题
数学方程式背后的详细解释,为您的机器学习或深度学习之旅奠定实用的数学基础
大家好!这是“等式到代码”演练的第 3 部分。这次
在第一部分中,我们谈到了如何利用线性回归解决线性可分问题。我们学习了向量表示、标准化、添加偏差、sigmoid 函数、对数似然函数和更新参数。
这次我们要解决一个非线性可分问题。如果你没有看过第一部分,这完全没问题。第 2 部分是独立的。但是如果你想更好地理解第 2 部分,最好先读第 1 部分。
[## Python 中的“等式到代码”机器学习项目演练—第 1 部分线性可分…
数学方程式背后的详细解释,为你的机器学习或学习建立实用的数学基础
towardsdatascience.com](/an-equation-to-code-machine-learning-project-walk-through-in-python-part-1-linear-separable-fd0e19ed2d7)
内容结构如下。*
表示如果您已经完成第 1 部分,可以跳过这一步。
- 看数据
- 非线性可分问题
- 标准化*
- 添加偏差和多项式项
- Sigmoid 函数*
- 似然函数*
- 更新参数θ*
- 绘制直线
- 精度
- 摘要
1 看数据
下面是数据, non_linear_data.csv
x1,x2,y
0.54508775,2.34541183,0
0.32769134,13.43066561,0
4.42748117,14.74150395,0
2.98189041,-1.81818172,1
4.02286274,8.90695686,1
2.26722613,-6.61287392,1
-2.66447221,5.05453871,1
-1.03482441,-1.95643469,1
4.06331548,1.70892541,1
2.89053966,6.07174283,0
2.26929206,10.59789814,0
4.68096051,13.01153161,1
1.27884366,-9.83826738,1
-0.1485496,12.99605136,0
-0.65113893,10.59417745,0
3.69145079,3.25209182,1
-0.63429623,11.6135625,0
0.17589959,5.84139826,0
0.98204409,-9.41271559,1
-0.11094911,6.27900499,0
首先,我们需要绘制这些数据,看看它是什么样子的。我们创建一个 Python 文件,并将其命名为 non_logistic_regression.py。
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("non_linear_data.csv", delimiter=',', skiprows=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# plot data points
plt.plot(train_x[train_y == 1, 0], train_x[train_y == 1, 1], 'o')
plt.plot(train_x[train_y == 0, 0], train_x[train_y == 0, 1], 'x')
plt.show()
运行上面的脚本后,您应该会看到下图。
似乎我们不能用一条直线来分离 X 和 o。我们把这样的问题称为非线性可分问题,其中数据不是线性可分的。
2 非线性可分问题
在第 1 部分中,我们使用线性函数来解决线性可分问题。
linear function
但是对于非线性可分问题,线性函数过于简单,难以处理。所以我们引入了多项式逻辑回归,它在逻辑回归中增加了一个多项式项。
general form
我们用θ来表示参数。左边的θ标记表示函数 f(x)有参数θ。右边的θ表示有两个参数。最后一项是多项式项,它使模型推广到非线性可分数据。
注意我们在 non_linear_data.csv 中有 x1 和 x2 两个特征。我们选择 x1 作为多项式项。所以功能应该变成低于形式。
a specific form fit to our data
我们初始化 4 个参数
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", *delimiter*=',', *skiprows*=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
**theta = np.random.randn(4)**
3 标准化
为了使训练快速收敛,我们使用标准化,也叫 z - **评分。**我们是按列来做的。
- 𝜇在每一栏都很刻薄
- 𝜎是每列的标准偏差
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", *delimiter*=',', *skiprows*=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
theta = np.random.randn(4)**# standardization
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)****def standardizer(x):
return (x - mu) / sigma****std_x = standardizer(train_x)**
4 添加偏差和多项式项
我们需要添加一个偏差和多项式项来构建数据矩阵。我们添加一个常数 x0=1,以便对齐矢量表示。
a specific form fit to our data
vector representation
您可以在第 1 部分找到更多的矢量表示细节: 3 矢量表示。
为了使计算更简单,我们把 x 转换成矩阵。
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", delimiter=',', skiprows=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
theta = np.random.randn(4)# standardization
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)
def standardizer(x):
return (x - mu) / sigma
std_x = standardizer(train_x)**# add x0 and x1^2 to get matrix
def to_matrix(x):
x0 = np.ones([x.shape[0], 1])
x3 = x[:, 0, np.newaxis] ** 2
return np.hstack([x0, x, x3])****mat_x = to_matrix(std_x)** **# dot product
def f(x):
return np.dot(x, theta)**
我们用 x3 来表示x1*x1
。
std_x
的尺寸为(20, 2)
。在to_matrix(std_x)
之后,mat_x
的尺寸为(20, 4)
。至于点积部分,结果的维度是(4,)
。所以点生成的结果应该是(20, 4) x (4,) -> (20,)
,这是一个包含 20 个样本预测的一维数组。
5 Sigmoid 函数
下面是矢量表示
然后我们将基于它建立一个更强大的预测函数,sigmoid 函数。
我们用 z 来表示线性函数,并将其传递给 sigmoid 函数。sigmoid 函数将给出每个数据样本的概率。我们的数据中有两个类,一个是1
,另一个是0
。
我们可以看到模型基于线性函数部分预测样本。
我们可以写下面的代码
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", delimiter=',', skiprows=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
theta = np.random.randn(4)# standardization
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)
def standardizer(x):
return (x - mu) / sigma
std_x = standardizer(train_x)# add x0 and x1^2 to get matrix
def to_matrix(x):
x0 = np.ones([x.shape[0], 1])
x3 = x[:, 0, np.newaxis] ** 2
return np.hstack([x0, x, x3])
mat_x = to_matrix(std_x)**# change dot production to sigmoid function
def f(x):
return 1 / (1 + np.exp(-np.dot(x, theta)))**
6 似然函数
如果您对方程的解释不感兴趣,或者您已经在第 1 部分中阅读过,那么您可以跳过这一步
好了,我们准备了数据、模型(sigmoid ),还需要什么?是的,一个目标函数。目标函数可以指导我们如何以正确的方式更新参数。对于 sigmoid(逻辑回归),我们通常使用对数似然作为目标函数
等等,等等…这些东西到底是怎么回事!
不要慌。冷静点。
让我们把它拆开。
- 1->2(如何从第 1 行到第 2 行):
log(ab) = log a + log b
- 2->3:
log(a)^b = b * log a
- 3->4:由于我们只有两个类,y=0 和 y=1,所以我们可以使用下面的等式:
3->4
- 4->5:我们使用下面的变换使等式更具可读性
所以我们得到了最后一部分。
别忘了我们为什么开始这个。目标函数可以指导我们如何以正确的方式更新参数。
我们需要用这个来计算损耗,以更新参数。更具体地说,我们需要计算对数似然函数的导数。这里我直接给出最后的更新方程式。(如果你对如何得到这个方程感兴趣,这个视频应该会有帮助)
第六步,最重要的方程就是这个。如果你不明白如何做到这一点,这是完全可以的。我们需要做的就是把它写成真正的代码。
7 更新参数θ
如果您已经阅读了第 1 部分,可以跳过这一步
这一步非常重要。不要慌。我们会破解它。
θj 是第 j 个参数。
- η是学习率,我们设为 0.001 (1e-3)。
- n 是数据样本的数量,在我们的例子中,我们有 20 个。
- I 是第 I 个数据样本
因为我们有三个参数,所以可以写成三个方程。我们用 x3 来代表x1*x1
。
:=
符号就像=
。你可以在这里找到解释。
最难的部分是σ(求和符号),所以为了更好地理解,我扩展了σ。
仔细看。
我给等式中的三个部分涂上颜色,因为我们可以用矩阵来表示它们。看第一行红色和蓝色的部分,我们更新了θ0。
我们把红色部分和蓝色部分写成列向量。
因为我们有 20 个数据样本,所以f
的维数是(20,1)
。x0
的尺寸为(20,1)
。我们可以用转置写矩阵乘法。
所以维度应该是(1, 20) x (20, 1) -> (1,)
。我们得到一个标度来更新θ0。
x1
和x2
也是列向量。我们可以把它们写成一个 X 矩阵。
θ是一个行向量
回到等式。
我们可以写为
把它写成一个等式。
类似 Numpy 数组的版本可能容易理解。
让我们做一点计算,以确保尺寸是正确的。
θ: (1, 4)
f^T: (1, 20)
x: (20, 4)dot production: (1, 20) x (20, 4) -> (1, 4)
一切看起来都那么正确。让我们写代码。其实就两行。
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", delimiter=',', skiprows=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
theta = np.random.randn(4)# standardization
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)
def standardizer(x):
return (x - mu) / sigma
std_x = standardizer(train_x)# add x0 and x1^2 to get matrix
def to_matrix(x):
x0 = np.ones([x.shape[0], 1])
x3 = x[:, 0, np.newaxis] ** 2
return np.hstack([x0, x, x3])
mat_x = to_matrix(std_x)# sigmoid function
def f(x):
return 1 / (1 + np.exp(-np.dot(x, theta)))# update times
epoch = 2000# learning rate
ETA = 1e-3# update parameter
**for _ in range(epoch):
** """
f(mat_x) - train_y: (20,)
mat_x: (20, 4)
theta: (4,)
dot production: (20,) x (20, 4) -> (4,)
"""
**theta = theta - ETA * np.dot(f(mat_x) - train_y, mat_x)**
奇怪的事?还记得我们在代码前写了什么吗?
dot production: (1, 20) x (20, 4) -> (1, 4)The dimension changes make sense here.
但是为什么我们写代码的时候要用(20,) x (20, 4) -> (4,)
?
实际上,这不是真正的数学符号,这是 Numpy 符号。而且如果你用的是 TensorFlow 或者 PyTroch 的话,应该很熟悉。
(20,)
表示这是一个包含 20 个数字的一维数组。它可以是行向量,也可以是列向量,因为它只有一维。如果我们将其设置为二维数组,像(20, 1)
或(1, 20)
,我们可以很容易地确定(20, 1)
是列向量而(1, 20)
是行向量。
但是为什么不显式设置维度来消除歧义呢?
好吧。相信我,我第一次看到这个的时候就有接缝问题。但是经过一些编码实践,我想我知道原因了。
因为这样可以节省我们的时间!
我们以(20,) x (20, 4) -> (4,)
为例。如果我们想得到(1, 20) x (20, 4) -> (1, 4)
,我们需要对(20,) x (20, 4) -> (4,)
做什么?
- 将(20,)转换为(1,20)
- 计算(1,20) x (20,4) -> (1,4)
- 因为(1,4)是一个二维列向量,我们需要将其转换为一维数组。(1,4) -> (4,)
老实说,这很令人沮丧。为什么我们不能一步到位?
对,所以我们才能写(20,) x (20, 4) -> (4,)
。
好了,我们来看看 numpy.dot() doc 是怎么说的。
numpy.dot() :如果 a 是一个 N 维数组, b 是一个 1 维数组,那么它就是 a 和 b 最后一个轴上的和积。
嗯,事实上我不明白。但是 np.matmul() 描述了与(20,1)或(1,20)的整形类似的计算,以执行标准的 2d 矩阵乘积。也许我们能得到一些灵感。
np.matmul() :如果第一个参数是一维的,那么通过在它的维数前加上 1,它被提升为一个矩阵。在矩阵乘法之后,前置的 1 被移除。
哈,这就是缺失的部分!所以在我们的例子中,(20,)
变成了(1, 20)
,因为(20,4)
的第一维度是 20。还有(1, 20) * (20, 4) -> (1, 4)
。然后前置 1 被删除,所以我们得到(4,)
。一步到位。
8 画这条线
在更新参数 2000 次后,我们应该绘制结果来查看我们的模型的性能。
我们将一些数据点做为 x1,根据我们所学的参数计算 x2。
# plot line
x1 = np.linspace(-2, 2, 100)
**x2 = - (theta[0] + x1 * theta[1] + theta[3] * x1**2) / theta[2]**plt.plot(std_x[train_y == 1, 0], std_x[train_y == 1, 1], 'o') # train data of class 1
plt.plot(std_x[train_y == 0, 0], std_x[train_y == 0, 1], 'x') # train data of class 0
**plt.plot(x1, x2, linestyle='dashed') # plot the line we learned** plt.show()
9 准确性
在第 2 部分中,我们使用准确性来评估我们的模型性能如何。
import numpy as np
import matplotlib.pyplot as plt# read data
data = np.loadtxt("linear_data.csv", delimiter=',', skiprows=1)
train_x = data[:, 0:2]
train_y = data[:, 2]# initialize parameter
theta = np.random.randn(4)# standardization
mu = train_x.mean(axis=0)
sigma = train_x.std(axis=0)
def standardizer(x):
return (x - mu) / sigma
std_x = standardizer(train_x)# add x0 and x1^2 to get matrix
def to_matrix(x):
x0 = np.ones([x.shape[0], 1])
x3 = x[:, 0, np.newaxis] ** 2
return np.hstack([x0, x, x3])
mat_x = to_matrix(std_x)# sigmoid function
def f(x):
return 1 / (1 + np.exp(-np.dot(x, theta)))**# classify sample to 0 or 1
def classify(x):
return (f(x) >= 0.5).astype(np.int)**# update times
epoch = 2000# learning rate
ETA = 1e-3**# accuracy log
accuracies = []**# update parameter
for _ in range(epoch): theta = theta - ETA * np.dot(f(mat_x) - train_y, mat_x) **result = classify(mat_x) == train_y
accuracy = sum(result) / len(result)
accuracies.append(accuracy)****# plot accuracy line
x = np.arange(len(accuracies))
plt.plot(x, accuracies)
plt.show()**
classify(x)
:如果概率大于 0.5,我们认为是真的result
:包含列表形式的预测,[真,假,…]accuracy = sum(result) / len(result)
:计算当前历元中预测的正确样本数。
最后,我们绘制了精度线。
我们可以看到这条线在 1000 个周期后变得稳定。
10 摘要
如果你已经看过第 1 部分,你会发现第 2 部分很容易理解。你可以在下面找到完整的代码。留下评论让我知道我的文章是否易懂。请继续关注我的下一篇关于随机梯度下降的文章。
查看我的其他帖子 中 同 一个分类查看 !
GitHub:bramble Xu LinkedIn:徐亮 博客:bramble Xu
“等式到代码”机器学习项目演练—第 3 部分 SGD
用 Python 实现随机梯度下降(SGD)和小批量梯度下降的详细说明
from Shutterstock
大家好!这是“等式到代码”演练的第 3 部分。
在前面的文章中,我们在中谈到了线性可分问题在第一部分,在第二部分中谈到了非线性可分问题。这次我们将根据等式实现随机梯度下降(SGD) 。
第 3 部分是独立的。但对于 part 2 中重复的内容我就不做过多解释了。如果你觉得有些东西很难理解,我推荐你先阅读 part 2 。
内容结构如下。*
表示如果您已经完成第 2 部分,可以跳过这一步。
- 预览*
- 随机梯度下降
- 小批量梯度下降
- 摘要
1 预览
如果您已经阅读了第 2 部分,您可以跳过这一步
首先,我们看看我们在第 2 部分做了什么。
这里是数据, non_linear_data.csv
x1,x2,y
0.54508775,2.34541183,0
0.32769134,13.43066561,0
4.42748117,14.74150395,0
2.98189041,-1.81818172,1
4.02286274,8.90695686,1
2.26722613,-6.61287392,1
-2.66447221,5.05453871,1
-1.03482441,-1.95643469,1
4.06331548,1.70892541,1
2.89053966,6.07174283,0
2.26929206,10.59789814,0
4.68096051,13.01153161,1
1.27884366,-9.83826738,1
-0.1485496,12.99605136,0
-0.65113893,10.59417745,0
3.69145079,3.25209182,1
-0.63429623,11.6135625,0
0.17589959,5.84139826,0
0.98204409,-9.41271559,1
-0.11094911,6.27900499,0
数据如下图所示。
在对数据作图后,我们发现一条直线无法将 X 和 o 分开,这类问题被称为非线性可分问题,数据不是线性可分的。
所以我们引入多项式 logistic 回归,在线性函数中增加一个多项式项。
polynomial function
我们用θ来表示参数。左边的θ标记表示函数 f(x)有参数θ。右边的θ表示有两个参数。最后一项是多项式项,它使模型推广到非线性可分数据。
注意,我们在 non_linear_data.csv 中有 x1 和 x2 两个特征。我们选择 x1 作为多项式项。所以功能应该变成低于形式。
a specific form fit to our data
然后我们引入标准化。
- 𝜇在每一栏都很刻薄
- 𝜎是每列的标准偏差
对于预测模型,我们使用 sigmoid 函数。下面是矢量表示。
我们用 z 来表示线性函数,并将其传递给 sigmoid 函数。sigmoid 函数将给出每个数据样本的概率。我们数据中有两个类,一个是1
,另一个是0
。
好了,我们准备了数据、模型(sigmoid ),还需要什么?是的,一个目标函数。目标函数可以指导我们如何以正确的方式更新参数。对于 sigmoid(逻辑回归),我们通常使用对数似然作为目标函数。更具体地说,我们需要计算对数似然函数的导数。这里我直接给出最后的更新方程式。(如果你对如何得到这个方程感兴趣,这个视频应该会有帮助)
θj 是第 j 个参数。
- η是学习率,我们设为 0.001 (1e-3)。
- n 是数据样本的数量,在我们的例子中,我们有 20 个。
- I 是第 I 个数据样本
类似 Numpy 数组的版本可能容易理解。
我们绘制模型线和精度线。
model line
accuracy line
下面是我们在第 2 部分之后留下的全部代码。
如果你觉得有些东西难以理解,你可以阅读第 2 部分获得详细解释。
2 随机梯度下降法
我们使用 SGD 的主要原因是为了避免局部最小值。
the parameter is trapped in a local minimum
基本思想是通过在每次更新中随机选择一个数据来更新参数。所以参数更容易走出局部极小值。
gradient descent
这是梯度下降形式。我们可以看到,为了更新θj,我们使用了整个训练数据(σ部分)。代码如下。
# initialize parameter
theta = np.random.randn(4)# update parameter
**for _ in range(epoch):
theta = theta - ETA * np.dot(f(mat_x) - train_y, mat_x)**
但是在 SGD 中,我们一次只用一个数据。
stochastic gradient descent
这里的k
是指我们随机选取的数据。
# initialize parameter
theta = np.random.randn(4)# update parameter
for _ in range(epoch): # sgd
**p = np.random.permutation(len(mat_x))
for x, y in zip(mat_x[p, :], train_y[p]):
theta = theta - ETA * (f(x) - y) * x**
- p 包含整个数据集的随机索引列表,例如,[ 5,12,17,14,8,9,10,2,13,18,15,16,1,0,6,11,7,4,3,19]
- for 循环每次取一个数据来更新参数θ
你可以这样想 SGD。在每个历元中,梯度下降和 SGD 都使用整个数据集来更新参数。用完整有序数据梯度下降更新参数。但是 SGD 用一个随机选择的数据来更新参数,这样更容易走出局部最小值。
精确线。我们可以看到收敛比梯度下降快。
3 小批量梯度下降
SGD 是好的,但是由于每次用一个数据更新参数,计算效率不高。
使用整体数据会造成局部极小问题(梯度下降),每次使用一个数据效率低。这就是为什么我们使用小批量梯度下降。
与 SGD 不同,我们可以用几个数据样本更新参数。这里的K
是包含m
个随机选择的数据样本的索引集。
我们有 20 个数据样本,我们将批量大小m
设为 5。
**import math**# initialize parameter
theta = np.random.randn(4)**# batch size
batch = 5****# calculate steps based on batch size
steps = int(math.ceil(len(train_x)/batch))**# update parameter
for _ in range(epoch):
**p = np.random.permutation(len(mat_x))
shuffle_x = mat_x[p]
shuffle_y = train_y[p]****for step in range(steps):
x = shuffle_x[step:step + batch, :]
y = shuffle_y[step:step + batch]
theta = theta - ETA * np.dot(f(x) - y, x)**
请注意,我们必须在每个时期混洗数据。该计算与通过矩阵乘法的梯度下降相同。如果你感兴趣,你可以在第一部分或第二部分找到详细的解释。
精确度线
收敛速度与梯度下降相同。但是计算效率更高。
4 摘要
在第 3 部分中,我们讨论了如何实现 SGD 和小批量梯度下降。你可以在下面找到完整的代码。留下评论让我知道我的文章是否易懂。请继续关注这个关于正则化的“公式到代码”系列的最后一篇文章。
查看我的其他帖子 中等 同 一个分类查看 !
GitHub:bramble Xu LinkedIn:徐亮 博客:bramble Xu
“等式到代码”机器学习项目演练—第 4 部分正则化
用 Python 从头开始实现正则化的详细说明
大家好!这是“公式到代码”演练的第 4 部分,也是本系列的最后一部分。
在前面的文章中,我们谈到了中的线性可分问题中的第一部分、第二部分中的非线性可分问题、第三部分中的随机梯度下降(SGD) 。就像其他部分一样,第 4 部分是独立的,您可以忽略前面的文章。
在第 4 部分中,我们将讨论如何实现回归问题的正则化,这可以使我们的模型更加健壮。
下面是完整的代码,regression _ without _ regulation . py和regression _ with _ regulation . py。
内容结构如下。
- 正规化
- 伪造一些数据样本
- 预处理
- 没有正规化的执行
- 正规化实施
- 摘要
1 正规化
如果我们的模型过于复杂,它会很好地拟合训练数据,但在新数据中会失败。我们把这种问题称为过拟合。
from ISCG8025
为了“不是很好地拟合训练数据”(上图中间),我们通常使用一些技术来避免过度拟合,如交叉验证、剔除、批量标准化等。
这一次,我们将讨论 L2 正则化项,它在大多数机器学习模型中被广泛使用。
2 伪造一些数据样本
我们使用 beblow 多项式函数来伪造一些数据样本。
为了让数据更加真实,我们在其中加入了一些噪声。你可以在代码中看到。
import numpy as np
import matplotlib.pyplot as plt# random seed to make sure reimplement
np.random.seed(0)# the real model line
def g(x):
return 0.1 * (x + x**2 + x**3)# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05# plot
x = np.linspace(-2, 2, 100)
plt.plot(train_x, train_y, 'o')
plt.plot(x, g(x), linestyle='dashed')
plt.ylim(-1, 2)
plt.show()
虚线表示我们想要建模的真实线。
3 预处理
在第一步中,我们谈到了当模型过于复杂时,需要进行调整。例如,上面的实线是 3 次多项式函数。
a polynomial function of degree 3
但是如果我们选择一个 10 次多项式函数,这个模型可能会更复杂。
a polynomial function of degree 10
因为我们有 10 度和一个偏项,所以我们也有 11 个参数。
我们实现这个来模拟复杂的情况。
import numpy as np
import matplotlib.pyplot as plt# random seed to make sure reimplement
np.random.seed(0)# the real model line
def g(x):
return 0.1 * (x + x**2 + x**3)# add noise to the model for faking data
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(len(train_x)) * 0.05# standardization
mu = train_x.mean()
std = train_x.std()
def standardizer(x):
return (x - mu) / std
**std_x = standardizer(train_x)**
# get matrix
def to_matrix(x):
return np.vstack([
np.ones(x.size),
x,
x ** 2,
x ** 3,
x ** 4,
x ** 5,
x ** 6,
x ** 7,
x ** 8,
x ** 9,
x ** 10,
]).T**mat_x = to_matrix(std_x)**# initialize parameter
**theta = np.random.randn(mat_x.shape[1])**# predict function
def f(x):
**return np.dot(x, theta)**
- 标准化:首先我们标准化我们的数据
- 获取矩阵:我们把数据做成矩阵形式进行矩阵运算,模拟 10 次多项式函数
- 初始化参数:根据输入数据的大小初始化参数
- 预测函数:这是我们的预测函数,就像上面的等式一样。
4 未正规化的实施
我们使用均方误差(MSE)作为代价函数。
# cost function
def E(x, y):
return 0.5 * np.sum((y - f(x))**2)# initialize error
error = E(mat_x, train_y)
我们使用梯度下降来更新参数。
类似 Numpy 数组的版本可能容易理解。这里我只列出三个参数,只是为了看清楚这个方程。
代码
# learning rate
ETA = 1e-4# update parameter
for _ in range(epoch):
theta = theta - ETA * np.dot(f(X) - train_y, mat_x)
我们将代码组合在一起
# learning rate
ETA = 1e-4# initialize difference between two epochs
diff = 1######## training without regularization ########
while diff > 1e-6:
# mat_x = (20, 4)
# f(x) - y = (20,)
**theta = theta - ETA * (np.dot(f(mat_x) - train_y, mat_x))** current_error = E(mat_x, train_y)
diff = error - current_error
error = current_error# save parameters
theta1 = theta########## plot line ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))# plot the line without regularization
theta = theta1
plt.plot(z, f(to_matrix(z)), linestyle='dashed')
plt.show()
我们可以看到我们学到了什么。
下面是完整的代码,regression _ without _ regulation . py
5 正规化实施
L2 监管术语看起来是这样的
我们将代价函数和正则项结合在一起。
因为我们增加了正则项,所以我们也需要相应地改变更新方程。
注意,我们不使用 lambda 来更新偏差参数θ0。
代码
# regularization parameter
LAMBDA = 1# initialize difference between two epochs
diff = 1# initialize error
error = E(mat_x, train_y)######## training without regularization ########
while diff > 1e-6:
# notice we don't use regularization for theta 0
**reg_term = LAMBDA * np.hstack([0, theta[1:]])** # update parameter
**theta = theta - ETA * (np.dot(mat_x.T, f(mat_x) - train_y) + reg_term)** current_error = E(mat_x, train_y)
diff = error - current_error
error = current_error# save parameters
theta2 = theta########## plot the line with regularization ##########
plt.ylim(-1, 2)
plt.plot(std_x, train_y, 'o')
z = standardizer(np.linspace(-2, 2, 100))theta = theta2
plt.plot(z, f(to_matrix(z)))
plt.show()
模型看起来是这样的。
我们可以看到,在添加正则化后,模型线变得更加平滑,更像原始的 3 次线。
下面是完整的代码,regression _ with _ regulation . py
6 摘要
这是“等式到代码”走查项目的最后一篇文章。希望对你有帮助。留下评论让我知道我的文章是否易懂。感谢阅读。
查看我的其他帖子 中等 同 一分类查看 !
GitHub:bramble Xu LinkedIn:徐亮 博客:bramble Xu
基于深度学习的单幅图像超分辨率进化
从经典插值到具有生成对抗网络的深度学习方法
在计算机视觉领域中,从对应的低分辨率图像重建高分辨率照片级真实感图像一直是一项长期的挑战性任务。当只有一张低分辨率图像作为输入来重建其高分辨率图像时,这项任务变得更加困难。
什么是超分辨率?对来自的一幅高分辨率(HR)** 图像和一幅低分辨率(LR)图像的估计被称为超分辨率(SR)** 。换句话说,LR 是一个单幅图像输入,HR 是地面真实,SR 是预测的高分辨率图像。当应用 ML/DL 解决方案时,LR 图像通常是添加了一些模糊和噪声的下采样 HR 图像。
Photo by Robin Mathlener on Unsplash
进化的第 0 代:插值
首先,非常早期的解决方案是图像处理中的插值方法。这里,低分辨率图像使用一些插值方法,如最近邻法、双线性或双三次插值法,以 2 倍或 4 倍的因子调整大小。
“插值的工作原理是使用已知数据来估计未知点的值。图像插值在两个方向上起作用,并试图根据周围像素的值获得像素强度的最佳近似值。”— 塔尔图大学的数字图像处理电子书。
Figure: Effect of interpolation (source)
从上面的插图可以清楚地看出,合成的图像是模糊的,不真实的。
进化的第一代:SRCNN
随着全卷积神经网络(FCNN)在解决语义分割方面的成功,它在计算机视觉的其他领域迅速普及。FCNN 是一个后面没有任何密集连接(全连接层)的 CNN。每个 CNN 有两个主要功能块,I)特征提取器和 ii)分类器。CNN 后面的密集连接是分类器,其任务是将提取的特征映射到类别概率。我认为 FCNN 是 DL 中从输入图像生成/预测输出图的基本设计实践。输出图可以是语义分割图、风格转移图甚至超分辨率图。换句话说,FCNN 是一个图像到图像的映射引擎。FCNN 在超分辨率中的一个这样的初步应用是 SRCNN 。
在 SRCNN 中,首先使用双三次插值对图像进行上采样,然后馈送到简单的 FCNN。需要注意的是,这里不涉及池操作。因此,产生与上采样输入图像相同空间大小的输出。最后,我们计算目标 HR 图像与输出之间的 MSE 损失。
Figure: SRCNN Model (source)
进化的第二代:SRResNet 和用于上采样的子像素卷积
由于使用 SRCNN 在单幅图像的超分辨率方面取得了一些成功,激发了其他人对该架构进行进一步的改进。众所周知, ResNet (带跳跃连接的 CNN)比传统 CNN 更好。 SRResNets 用残差块代替简单卷积块。结果,精确度显著提高。
Figure: SRResNet Model (source)
许多深度学习模型还结合了转置卷积进行上采样。双线性和双三次上采样是不可学习的,这意味着,它只能在深度学习架构之前或之后使用,而不能在两者之间使用。可学习的上采样的其他优点是它的速度和准确性。
但是正如人们可能已经观察到的那样,上面用步进卷积梯度实现的上采样操作增加了零值来放大图像,这必须在以后用有意义的值来填充。更糟糕的是,这些零值没有梯度信息可以反向传播。
“应付那个问题,石等人。al 提出了我们认为是最近最有用的 convnet 技巧之一(至少在我作为一个生成模型研究者看来是这样!)他们提出了一个用于升级的子像素卷积神经网络层。这一层基本上使用常规卷积层,然后是一种称为相移的特定类型的图像整形。换句话说,他们在较低分辨率下计算更多的卷积,并将结果图的大小调整为放大的图像,而不是在像素之间放置零并进行额外的计算。这样就不需要无意义的零了。”—[https://github.com/atriumlts/subpixel
利用相移进行图像整形也叫“像素混洗”,将 H × W × C r 张量的元素重新排列,形成 rH × rW × C 张量,如下图所示。
Figure: Sub-pixel convolution operation (source)
进化的第三代:知觉丧失
在像超分辨率这样的应用中使用 MSE 或 MSE 类型的误差方法作为损失函数的主要缺点是它是按像素计算的。也就是说,它仅测量预测图像和目标图像中两个对应像素之间的变化。这鼓励寻找似是而非的解决方案的像素平均值,这些解决方案通常过于平滑,因此具有较差的感知质量。这个论点也适用于不仅仅使用 PSNR 作为质量指数,因为它也是按像素计算的。因此,我建议在比较这类任务中任何两种方法的性能时,不要只检查 PSNR。
感知损失通过基于来自预训练 CNN 模型的高级表示比较两幅图像来计算。该函数用于比较图像之间的高级差异,如内容和风格差异。
换句话说,目标和预测输入都通过预先训练的网络,并计算两个结果特征图之间的欧几里德距离(在同一阶段)。感知损失函数的工作原理是将所有像素之间的所有平方误差相加并取平均值。这与每像素损失函数相反,每像素损失函数将像素之间的所有绝对误差相加。
进化的第四代:SRGAN
生成对抗网络(GANs)提供了一个强大的框架来生成具有高感知质量的看似真实的自然图像。GAN 过程鼓励重建向搜索空间中包含照片级逼真图像的概率较高的区域移动,从而更接近自然图像流形。
SRGAN 是基于 GAN 的网络,其中生成器(G)学习从尽可能接近 HR 的 LR 图像生成 SR 图像。鉴别器(D)学习区分生成的 SR 图像和真实图像。G 利用 ResNet 和子像素卷积进行上采样。它还将感性损失与生成性或对抗性损失结合起来计算其损失。
Figure: Architecture of Generator and Discriminator Network in SRGAN. (source)
损失
Equation of modified perceptual loss in SRGAN. (source)
结论
研究使用深度学习估计单幅图像超分辨率的发展,显然,基于 ResNet 的 GAN 结合了感知损失和生成损失,并应用亚像素卷积进行上采样,可以生成更好的照片级逼真超分辨率图像。
显著的信誉
我要感谢 Katarzyna Kańska 关于*“单图像超分辨率”* : Youtube 视频— 你能增强一下吗?单幅图像超分辨率——Katarzyna kańska。
使用 Hyperopt 在 XGBoost、LightGBM 和 CatBoost 上优化超参数的示例
额外奖励:Hyperopt-Sklearn
Source: Pexels
我保证,这次会比上一次更高级:
TensorFlow 中结构化编程的一个例子
towardsdatascience.com](/a-gentle-implementation-of-reinforcement-learning-in-pairs-trading-6cdf8533bced)
介绍
梯度推进决策树(GBDT)
梯度推进是决策树上的附加训练技术。 XGBoost 的官方页面给出了非常清晰的概念解释。基本上,不是运行静态的单个决策树或随机森林,而是迭代地添加新的树直到无法实现进一步的改进。除了正则化之外,集合技术对于防止过拟合是至关重要的。尽管该模型可能非常强大,但仍有许多超参数需要微调。
XGBoost、LightGBM 和 CatBoost
这些是众所周知的梯度增强包。与通过遍历所有要素找到最佳分割的传统 GBDT 方法相比,这些包实现了基于直方图的方法,将要素分组到条柱中,并在条柱级别而不是要素级别执行分割。另一方面,他们也倾向于忽略稀疏输入。这些显著提高了它们的计算速度(更多细节见此处)。需要注意的几个关键点:
XGBoost :著名的 Kaggle 中奖包。树的生长是基于逐层的树修剪(树在一层的所有节点上生长),使用来自分裂的信息增益,为此需要对样本进行预分类,以便在每一步中计算所有可能分裂的最佳分数,因此比较耗时。
等级和树叶(树从特定的树叶开始生长)训练都是可用的。它允许用户选择一种叫做基于梯度的单侧采样(GOSS)** 的方法,这种方法根据最大梯度和一些具有较小梯度的随机样本来分割样本。背后的假设是梯度越小的数据点训练得越好。另一个关键算法是专有特征捆绑(EFB) ,它研究特征的稀疏性,并将多个特征组合成一个,而不会丢失任何信息,因为它们在一起决不非零。这些使得 LightGBM 比 XGBoost 更快。**
CatBoost :专为分类数据训练设计,也适用于回归任务。GPU 上的速度号称是这些库中最快的。在中将分类特征转换为数字中有多种方法。其速度的关键与两个 Os 挂钩: 遗忘树 和有序推进。不经意树是指采用对称二进制分裂的逐层树构建(即每层上的每片叶子都被一个特征分裂),而有序提升应用排列和顺序目标编码来转换分类特征。更多详情请参见此处此处和此处。**
贝叶斯优化
与作为强力方法的 GridSearch 或纯粹随机的 RandomSearch 相比,经典 贝叶斯优化通过高斯过程逼近目标函数(即随机样本被迭代地抽取(基于序列模型的优化(SMBO))并且样本之间的函数输出被置信区域逼近),在搜索最优参数时结合了随机性和后验概率分布。将在置信区域的高均值和方差处从参数空间中提取新样本,用于勘探和开发。查看此以获得更多解释。
远视
Hyperopt 是一个用于搜索空间优化的 python 库。目前它提供了两种优化算法: 1。随机搜索和 2。Parzen 估计器树(TPE ),这是一种贝叶斯方法,它使用 P(x|y) 而不是 P(y|x) ,在计算预期改善时,它基于对由阈值而不是一个阈值分隔的两个不同分布的近似(参见和)。它曾经适应高斯过程和回归树,但现在这些不再被实现。
******
UL: Feature binning; UR: Tree growing; BL: Bayesian Optimizing ; BR: Gradient-based One-Side Sampling**
履行
装置
查看以下安装指南:
远视示例
fmin()
是 hyperopt 中用于优化的主要功能。它接受四个基本参数并输出优化的参数集:
- 目标函数—
fn
- 搜索空间—
space
- 搜索算法—
algo
- (最大)评估数量—
max_evals
我们也可以将一个 Trials 对象传递给trials
参数,它跟踪整个过程。为了进行试验,目标函数的输出必须是至少包括关键字'loss'
和'status'
的字典,这两个关键字分别包含结果和优化状态。可以通过以下方式提取临时值:
trials.trials
-字典列表包含所有相关信息trials.results
-收集函数输出的字典列表trials.losses()
-损失清单(每次‘ok’试验的浮动)trials.statuses()
-状态字符串列表trials.vals
-采样参数字典
让我们看看下面的例子:
Example of hyperopt implementation
****
Example of hyperopt implementation - progress and the corresponding results
优化后的 x 为 0.5000833960783931 ,接近理论值 0.5 。正如你可能注意到的,样本在最小值附近更加浓缩。如果您将algo
切换到使用随机采样的hyperopt.rand.suggest
,那么这些点将在hp.uniform
下更均匀地分布。
还有几件事需要澄清:
搜索算法:或者hyperopt.tpe.suggest
或者hyperopt.rand.suggest
搜索空间: hp.uniform('x', -1, 1)
用标签‘x’定义一个搜索空间,它将在-1 和 1 之间被均匀采样。目前由 hyperopt 的优化算法识别的随机表达式是:
hp.choice(label, options)
:选项的指标****hp.randint(label, upper)
:随机整数【0,上)**hp.uniform(label, low, high)
:低/高值一致hp.quniform(label, low, high, q)
:round(uniform(.)/q)*q
(注意该值给出的是一个浮点数,而不是整数)hp.loguniform(label, low, high)
:exp(uniform(low, high)/q)*q
hp.qloguniform(label, low, high, q)
:round(loguniform(.))
hp.normal(label, mu, sigma)
:正态分布抽样hp.qnormal(label, mu, sigma, q)
:round(normal(nu, sigma)/q)*q
hp.lognormal(label, mu, sigma)
:exp(normal(mu, sigma)
hp.qlognormal(label, mu, sigma, q)
:round(exp(normal(.))/q)*q
详见本。
如果你想从远视空间采样,你可以调用hyperopt.pyll.stochastic.sample(space)
,其中space
是上面的hp
空间之一。
使用 Hyperopt 优化 XGBoost、LightGBM 和 CatBoost
下面是本文中的主要示例。所有三个 boosting 库都有一些相似的接口:
- 训练:
- 交叉验证:
cv()
- sci kit-学习 API:
-回归器:XGBRegressor()
,LGBMRegressor()
,CatBoostRegressor()
,
-分类器:XGBClassifier()
,LGBMClassifier()
,CatBoostClassifier()
以下示例使用回归器接口。让我们首先为所有三个库定义参数空间(reg_params
用于对象实例化;fit_params
为fit()
功能):
请注意,许多参数共享公共的参数名或别名。有关更多信息,请查看以下链接和相应的 API 页面:
一些基本参数:
learning rate
【X/L/C】:学习率(别名:eta
)max_depth
【X/L/C】:树木的最大深度n_estimators
【X/L/C】:升压迭代次数min_child_weight
【X/L】:一个孩子所需的最小体重总和min_child_samples
【信用证】:一叶数据的最小数量subsample
【X/L/C】:训练实例的子样本比率(注意,对于 CatBoost,只有在选择了泊松或伯努利bootstrap_type
时,才能使用该参数)colsample_bytree
【X/L】:树木建筑中柱子的子样比colsample_bylevel
【X/C】:树型建筑中各层柱子的子样比colsample_bynode
【X】:各节点列的子样率tree_method
【X】:树形构造法boosting
【L】:树形构造法boosting_type
[C]:Ordered
表示有序升压,或者Plain
表示经典early_stopping_rounds
【X/L/C】:用于fit()
的参数——如果验证数据的一个指标在最后early_stopping_rounds
轮中没有改善,则停止训练eval_metric
【X/L/C】:验证数据的评估指标
有关 CatBoost 中分类特征设置的更多设置,请查看参数页面中的 CTR 设置。
在设置参数之后,我们可以创建一个类HPOpt
,它用训练和测试数据实例化,并提供训练函数。这里我只包括回归变量的例子。您可以在课程中添加自己的分类、训练或交叉验证功能。
例如,给定预定义的数据帧x_train
、x_test
、y_train
、y_test
,我们可以通过调用process()
来运行优化过程:
额外奖励:Hyperopt-Sklearn
Hyperopt-Sklearn 是一个非常高级的优化包,目前仍在构建中。让我们来看一个官方例子:
source: https://hyperopt.github.io/hyperopt-sklearn/
你可能会好奇什么是any_classifier
?如果我们检查它的 GitHub 库:
似乎涵盖了 SVM 、 KNN 、随机森林甚至 XGBoost 等多个分类器和回归器。正如官方页面所说:
hyperopt 中可用的任何搜索算法都可以用来驱动估计器。也可以提供自己的算法或混合使用不同的算法。
基本上,它几乎为您搜索所有内容,包括模型和超参数。虽然这听起来很方便,但在把一切交给电脑之前,我会三思而行。但是,如果数据集和参数空间的大小不是很大,那么值得一试。
最后
这是对主要 boosting 库和 hyperopt 的介绍。在文档中有更多关于并行运行的主题,可以提高 GPU 和 MongoDB for hyperopt 的计算速度,您可能也会有所启发。
实施人工智能和机器学习的执行官指南
我在应用人工智能/机器学习支持业务目标方面学到的一些经验
作为首席分析官,我必须在业务需求和数据科学家之间架起一座桥梁。根据我的经验,如何弥合这一差距就是人工智能(AI)和机器学习的价值和前景实现程度的差异。以下是我学到的一些东西。
AI =机器学习(至少在 2019 年)
机器学习是一条通往人工智能的道路。至少到 2019 年,这是我所知道的唯一可行的路径。在未来几年,可能会有其他方法。这两个术语不可互换,但出于我们的目的,我将专注于机器学习。
机器学习是一类工具和方法,其中给计算机一个包含“答案”的大型训练数据集。然后,机器学习如何从输入的组合中获得答案。然后根据不同的测试数据集测试该模型,以确定其准确性。
机器学习作为一个类别可以包括适合这种方法的基本统计工具(例如线性回归)。它还包括神经网络、决策树和其他一些工具。
机器学习是你试图解决的问题的正确工具吗?
这一个在过去曾经绊倒过我。
例如,最近我有一个数据集,其中有许多从医院收集的数据,每个员工都有 50 个测量值(例如,他们是否按时上班,或者他们是否始终是当班唯一有经验的人),以及他们是否会在接下来的几周或几个月内辞职的指标。问题是:给定这个数据集,我们能否创建一个模型来预测哪些员工会在辞职前辞职,从而让医院能够及早干预?
我们花了几个月的时间审查数据集,并使用基本的数据可视化方法来确定一组规则。例如,刚被雇用的员工辞职的可能性是已经在医院工作了十年的员工的两倍。某些临床专业的员工和特定年龄段的员工有不同的平均辞职率。被要求每月两周或两周以上每周工作 60 小时以上的员工辞职的可能性要高 50%。
这个问题是机器学习的好候选吗?难道我们不能把这些规则组合起来,建立一个统计模型吗?
最终,我相信它是一个很好的候选,但类似的问题可能不会出现。加州理工学院教授亚塞尔·阿布·穆斯塔法描述了机器学习候选问题需要具备的三个品质:
1 -有足够的数据。
- 相对于其他选择,机器学习成为更好的方法,你有越多的数据来训练它。如果你只有几百行数据,它可能不工作或者不能有效地工作。
你的输入和你试图预测的东西之间有关系。
- 在我的例子中,我们对数据的视觉回顾显示有很多这样的关系。
3 -这种模式无法用简单的英语描述。
- 在我的例子中,这个不太清楚。因为我们能够用简单的英语描述许多模式,为什么我们不能在这些模式上建立一个模型呢?在我们的案例中,既有我们无法辨别的隐藏模式,也有我们无法辨别或描述的变量之间的关系。例如,如果一个人既工作了很多小时,又是轮班中最有经验的成员,那么两者的影响是相加的吗?
从这里开始并确保部署正确的工具可能会节省您很多时间。即使以上对于您的数据集来说是真的,它们真的足以证明对这种方法的投资吗?
从投资回报率的角度来看,预测一个事件发生的价值是否等于错误预测一个不发生的事件的成本?
数据分析师基于准确性比较和优化模型。准确性是在预测尽可能多的将要发生的事件和不正确地预测尽可能少的不会发生的事件之间的权衡。有一些方法可以调整模型的阈值,以便在模型运行后进行权衡,但是解释这样的结果需要一些脑力劳动。
对于业务所有者来说,更好的方法是在根据业务目标运行模型之前建立模型。在我们的例子中,正确预测将辞职的雇员的价值可能价值数千美元(即,避免用新雇员替换他们的价值),而错误预测雇员辞职的成本可能很小。然而,这是有门槛的:如果每年有 10%的员工辞职,我们对客户的了解告诉我们,我们不能识别超过 20%的高风险进行干预。这些标准需要从业务需求和术语(如 ROI)转化为模型输入(如惩罚矩阵)。
重要的一点是确定这种权衡的相对成本和价值,并确保构建的模型在此基础上进行优化。
最著名的机器学习实现之一,Netflix 奖,我相信忽略了这一点。该奖项颁给了能够最准确预测观众喜欢的电影的模型。在他们的案例中,准确性是公正的,不管我们给他们可能喜欢的电影打低分,还是给他们可能不喜欢的电影打高分。然而,这是正确的业务需求吗?如果网飞向我推荐五部电影,而我知道我会非常不喜欢其中的两部,作为一个用户,我很可能在未来对他们的任何推荐都打折扣。但是如果我看到了五部推荐给我的电影,而其中没有一部我知道我会喜欢的……那对我来说真的不是问题。
模型中需要稳定性吗?换句话说,如果输入中的一件小事发生变化,输出大幅波动是可以的吗?
以我的经验来看,模型越精确(至少按照机器学习对精确度的定义),投入产出关系就越不连续。
如果你有一系列照片,并且你想要一个机器学习模型来标记那些包括消防栓的照片,你可能很好地接受这种程度的不稳定性,因为没有用户会改变照片中的像素并期望输出保持相似的情况。
然而,对我们来说,某种程度的稳定是重要的。如果我们长期跟踪一名员工,我们不希望当他们的年龄从 31.1 岁到 31.2 岁到 31.3 岁时,他们的预测辞职风险每月都不可预测地上升。
您需要知道哪些输入字段对预测输出有贡献吗?或者有一个完整的黑匣子也可以吗?
神经网络是黑盒模型。你给它你的输入,它会返回一个输出;就是这样。你不知道它是如何得到输出的,也不知道在决定输出时哪些输入的权重最大。神经网络往往比其他模型更准确,但从业务需要来看,这额外的几个百分点的准确性值得你完全不透明吗?
其他模型,如线性回归和决策树,将向您显示导致输出的输入组合。数据分析师可能想要运行多个决策树,并获取所有输出的平均值。这可能会提高模型的准确性,但可能会降低了解其工作原理的能力。
我发现混合模型是获得两种方法优点的一种方式。一个模型是神经网络模型(带有一些阻尼因子以保持稳定性),它给出了周转风险值。另一个模型是确定关键驱动因素的线性回归。我们向用户显示两者的结果。存在一些风险,因为不能保证模型会匹配(换句话说,神经网络可能会识别其他模型无法识别驱动因素的高风险事件),但有一些方法可以解决这一问题。
总之……
上面的问题和讨论部分是基于我在试图弥合业务目标和分析团队之间的差距时的经历。商业目标需要艺术和科学的结合。机器学习背后的科学越来越商品化:模型可供任何人运行,并且有大量资源可用于获得数学上稳健的结果。但是你正在建立的事业不是数学上的。这是用户需求、营销需求以及集成和部署解决方案的实用性的混合。部署机器学习解决方案的艺术让我特别感兴趣,希望这些能给我一些思考。
也发表在strategister . blog上,在那里我分享了关于构建基于分析的产品和业务的想法。本文中提及或参考的任何书籍或其他资源都列在这里。
Kickstarter 最近怎么样?
使用 tidyverse 和 ggplot2 进行基本数据操作和可视化,使用 mediumR 发布
It’s a practice story!
我没有意识到从 R 直接导入到 Medium 后,桌子/桌子的形状会很差。如果有人曾经面临过这种情况,请给我一个链接供我参考!
我从 Kaggle 获得了 2018 年 1 月 Kickstarter 数据集。对于门外汉来说,也就是说,如果你一直生活在岩石下,Kickstarter 是一个项目众筹平台。所以你发布你想要实现的项目,它可以是艺术项目,音乐,电影,新玩意,艺术,食物食谱,视频游戏,等等。见鬼,曾经有个家伙在 Kickstarter 上建了一个页面来帮他做土豆沙拉。当这位老兄说他只需要 10 美元买一些土豆沙拉时,他得到了 55,000 美元。
因此,人们张贴他们想做什么样的东西,项目的细节,设定一个资助目标,并让人们“承诺”他们的项目。Kickstarter 遵循“全有或全无”的资助计划,这意味着如果到了资助截止日期,你的项目还没有达到目标,所有承诺的资金都将返还给贡献者。通常期限是 30 天或 60 天。但是如果你真的达到了你的融资目标,你会得到这笔钱,但是 Kickstarter 会给你 5%的提成。
所以今天我们将试着回答或提出更多的问题,有几点:
- Kickstarter 还是独立项目可行的资金来源吗?如果有,通常什么样的项目能成功获得资助?
- 如果项目资助失败,失败的可能性有多大?什么样的项目会失败?
我们首先对我们面临的数据集有一个概念。我们有从 2009 年 3 月到 2018 年 3 月的大约 378,000 个项目的数据(顺便提一下,Kickstarter 是 2009 年 4 月推出的,但无论如何)。
瞧,原始数据(名为“ks”):
ks## # A tibble: 378,661 x 16
## ID name category main_category currency deadline goal
## <int> <chr> <chr> <fct> <chr> <date> <dbl>
## 1 1.00e9 The ~ Poetry Publishing GBP 2015-10-09 1000
## 2 1.00e9 Gree~ Narrati~ Film & Video USD 2017-11-01 30000
## 3 1.00e9 Wher~ Narrati~ Film & Video USD 2013-02-26 45000
## 4 1.00e9 Tosh~ Music Music USD 2012-04-16 5000
## 5 1.00e9 Comm~ Film & ~ Film & Video USD 2015-08-29 19500
## 6 1.00e9 Mona~ Restaur~ Food USD 2016-04-01 50000
## 7 1.00e9 Supp~ Food Food USD 2014-12-21 1000
## 8 1.00e9 Chas~ Drinks Food USD 2016-03-17 25000
## 9 1.00e9 SPIN~ Product~ Design USD 2014-05-29 125000
## 10 1.00e8 STUD~ Documen~ Film & Video USD 2014-08-10 65000
## # ... with 378,651 more rows, and 9 more variables: launched <dttm>,
## # pledged <dbl>, state <fct>, backers <int>, country <chr>, `usd
## # pledged` <dbl>, usd_pledged_real <dbl>, usd_goal_real <dbl>,
## # wrap_main_category <chr>
因为我们想看看什么样的项目得到了资助,什么样的项目失败了,所以首先存储新的变量来区分失败和成功的项目是有意义的。
ks$wrap_main_category<-str_wrap(ks$main_category,width=5)
success.fail.bar <- ggplot(ks, aes(x=wrap_main_category, fill=state))
success.fail.bar + geom_bar() + theme_economist() + labs(x="Project Category",y="Count of Projects", title="Kickstarter Projects State")
我们看到,对于大多数项目类别,成功率将低于 50%。下面是更详细的数据。我们创建新的变量,计算每个类别中有多少项目,以及每个类别中有多少项目失败,然后简单地将它们相除,以找到失败率。
ks.all<- ks %>%
group_by(main_category)%>%
summarise(count=n()) %>%
arrange(desc(count))
ks.allfail<- ks.fail %>%
group_by(main_category)%>%
summarise(count=n()) %>%
arrange(desc(count))
ks.rate <- ks.all %>%
mutate(fail=ks.allfail$count/ks.all$count) %>%
arrange(desc(fail))
ks.rate## # A tibble: 15 x 3
## main_category count fail
## <fct> <int> <dbl>
## 1 Journalism 4755 0.787
## 2 Games 35231 0.742
## 3 Fashion 22816 0.729
## 4 Food 24602 0.700
## 5 Technology 32569 0.697
## 6 Publishing 39874 0.692
## 7 Theater 10913 0.685
## 8 Art 28153 0.658
## 9 Design 30070 0.649
## 10 Film & Video 63585 0.628
## 11 Comics 10819 0.619
## 12 Music 51918 0.534
## 13 Crafts 8809 0.497
## 14 Photography 10779 0.462
## 15 Dance 3768 0.380**note: the column "count" represents the amount of projects belonging to the category in the data-set, the column "fail" indicates how often projects belonging to that category fails**
事实证明,以新闻为主题的项目失败了很多。另一方面,我们得到了失败最少的舞蹈分类项目。两者都有相对较少的提议项目。为什么?或许这与筹资目标有关?人们会被那些有着巨大资金目标的项目吓住吗?或者,资助目标金额较小的项目是否被认为不够雄心勃勃?资金目标是答案吗?我们将抽取 1%的人口作为样本。
ks.sample <- sample_frac(ks,0.01)
viol <- ggplot(ks.sample,aes(x=state,y=goal),options(scipen=1000000))
viol + geom_violin(scale="area") + coord_cartesian(ylim=c(0,1000000)) +
theme_economist() + labs(x="Project Outcome",y="Funding Goal",title="Distribution of Funding States by Funding Goal")
事实证明不是。这只表明有一些疯狂的雄心勃勃的项目(这些项目失败了或被取消了)但筹资目标似乎并不真正影响成功。有道理。也许我们需要仔细看看。
viol + geom_violin(scale="area") + coord_cartesian(ylim=c(0,100000)) +
theme_economist() + labs(x="Project Outcome",y="Funding Goal",title="Distribution of Funding States by Funding Goal")
看,大部分成功资助的项目都处于资助目标的低端。相反,其他州(失败)分布得很好。这是否意味着更低的资助目标意味着更好的计算项目,或者仅仅是,更容易资助?也许我们应该看看他们离他们的筹资目标还有多远?
ks2 <- ks%>%
mutate(failhard=(ks$pledged/ks$goal)) %>%
filter(state!="successful", state!="live") %>%
select(ID:pledged,failhard,everything())
ks2## # A tibble: 241,906 x 17
## ID name category main_category currency deadline goal
## <int> <chr> <chr> <fct> <chr> <date> <dbl>
## 1 1.00e9 The ~ Poetry Publishing GBP 2015-10-09 1000
## 2 1.00e9 Gree~ Narrati~ Film & Video USD 2017-11-01 30000
## 3 1.00e9 Wher~ Narrati~ Film & Video USD 2013-02-26 45000
## 4 1.00e9 Tosh~ Music Music USD 2012-04-16 5000
## 5 1.00e9 Comm~ Film & ~ Film & Video USD 2015-08-29 19500
## 6 1.00e9 Chas~ Drinks Food USD 2016-03-17 25000
## 7 1.00e9 SPIN~ Product~ Design USD 2014-05-29 125000
## 8 1.00e8 STUD~ Documen~ Film & Video USD 2014-08-10 65000
## 9 1.00e8 Of J~ Nonfict~ Publishing CAD 2013-10-09 2500
## 10 1.00e9 The ~ Crafts Crafts USD 2014-10-02 5000
## # ... with 241,896 more rows, and 10 more variables: launched <dttm>,
## # pledged <dbl>, failhard <dbl>, state <fct>, backers <int>,
## # country <chr>, `usd pledged` <dbl>, usd_pledged_real <dbl>,
## # usd_goal_real <dbl>, wrap_main_category <chr>
我增加了一个名为“失败”的栏目,通过划分承诺金额和目标金额来显示一个项目离获得资助还有多远。但是这里没有显示。
我们添加了一个新列来计算项目资金目标的完成百分比。通过这种方式,我们可以衡量他们离获得资助还有多远。
ks.sample2 <- sample_frac(ks2,0.01)
viol2 <- ggplot(ks.sample2,aes(x=state,y=failhard),options(scipen=1000000))
viol2 + geom_violin(scale="area") + coord_cartesian(ylim=c(0,1)) +
theme_economist() + labs(x="Project Outcome",y="Funding Completion",title="How Hard did They Fail?")
大多数项目都失败了,甚至没有超过 25%。是否可以得出结论,不是资助目标太大,就是 Kickstarter 设定的资助期限太小?也许仅仅是因为这些项目没那么有趣。
总而言之,我们可以得出结论,坦率地说,60%的失败率是相当低的!我最初认为只有很小一部分项目能够成功获得资助。结果 40%的人达到了筹资目标。项目要么得到了资助,要么与目标相差甚远。显示它仍然是命中或错过,但嘿,40%的融资机会是相当大的,如果你问我。
我们下次再继续。毕竟,这是我第一次和 r 一起竞技。
ClinVar 数据库中人类遗传变异的探索
每一个生物的核心不是火,不是温暖的呼吸,不是“生命的火花”。它是信息,文字,指令。如果你想理解生活,不要去想充满活力、悸动的凝胶和渗出物,想想信息技术。理查德·道金斯
正如道金斯在他一贯直言不讳、经常嘲讽的感叹中所描述的那样,我们越来越认同这样一个事实,即 DNA 是最典型的信息分子——一种由 4 个字母组成的小型字母表中的密码,构成了一个人。从纯粹的有用性来看,这是后元古代时代使用最频繁的信息技术。
数十亿年前,生命采用 DNA 作为信息分子。一开始,生命并不像今天这样复杂,无论是在机体外部还是内部。随着复杂的身体模式和器官模式的进化,DNA 的数量也随之增长。增长是惊人的——从细菌的兆碱基到人类的千兆碱基。毕竟,这是增加由 4 个字母组成的线性字符串的复杂性的唯一方法。然而,继续“长度增长”战略来跟上复杂性是不可能的。为了应对这种情况,进化发明了其他现象,如体细胞超突变、重组和交替剪接,以增加多样性,而不会永远增加基因组的大小。
Genome size comparison (x-axis in log scale)
进化的变异就像股票市场的波动。没有前者,后者就不会存在。变异是进化的食物和饲料。随着新物种的进化,它们继承的 DNA(变体)与它们的前辈略有不同。当条件改变时,这些变异中的一些相对于其他种群获得优势,成为优势物种(T2 的胡椒蛾进化)。这是进化的潮起潮落——从一个进化到下一个。不管是好是坏,它必须继续下去。
脱氧核糖核酸
一个人活着。生物体的完整描述已经写在蛋里了。—悉尼·布雷内
DNA 是生命的蓝图;它携带了制造生物体所需的所有信息。这是你的基因组——总体规划——生命的秘密。
人类的 DNA 有 30 亿个碱基对长,由 4 个核苷酸碱基组成:腺嘌呤腺嘌呤、腺嘌呤腺嘌呤腺嘌呤、鸟嘌呤鸟嘌呤胞嘧啶。它所拥有的信息是它唯一的功能。为了制造蛋白质,DNA(更准确地说是 mRNA,它是 DNA 蛋白质编码区的代理)被破译为三联体或**密码子。**密码子是 3 个碱基的任意组合——也就是 4 个,加起来就是 64 密码子。每个密码子编码一个特定的氨基酸,由于只有 20 个氨基酸,有些氨基酸有不止一个密码子。这就是变体发挥作用的地方。DNA 序列的变异意味着氨基酸序列的改变、蛋白质组成的改变和一种无序状态。DNA 变异的这一方面对于评估个体对遗传条件的易感性至关重要。
为什么选择 ClinVar?
不久前,我们发现捕捉关于人口变化的洞察力是一个强有力的工具。它催生了生物学研究史上一些最重要的事业。 1000 个基因组, 1001 个基因组,瓶中基因组, OMIM ,宇宙, ClinVar 等。是一些例子。 ClinVar 是一个公共知识库,包含关于基因组变异及其表型的信息和证据。如果您对您的基因组进行测序,并将其与 ClinVar 数据集中的基因组位置进行比较,您可以找出您的遗传变异及其表型。截至 2019 年 11 月,数据库中有超过 50 万(准确地说是 502252)个条目。ClinVar 由国家生物技术信息中心(NCBI)管理。
是什么导致了变异?
Variation in the corn kernel color caused by transposons
玉米穗中的每一粒都是一次独立减数分裂的产物。这意味着,令人惊讶的是,一只耳朵可以捕捉到玉米植株的整个基因组。几乎就像数据科学家的仪表板。但是,有一个问题;籽粒的颜色似乎不遵循孟德尔遗传。原因可能是什么?通过她在玉米遗传学方面的开创性工作,她获得了 1970 年的国家科学奖章和 1983 年的诺贝尔奖,芭芭拉·麦克林托克展示了某些遗传元素可以改变基因组中的位置,从而产生非孟德尔遗传模式。这些元素被称为转座子,当它们从染色体的一部分跳到另一部分时,它们会产生复杂的遗传变异,如缺失、复制和倒位。在人类中, Alu 元素 是最丰富的转座子——约占我们基因组的 10%。
第二个主要原因是电离辐射和高能辐射。它们引起点突变(单核苷酸变异)和染色体断裂。
如何识别变体?
我们使用两种主要的方法来描述变异——基因组的和功能的——在这里我将着重于基因组方面。在计算基因组学中,通过将给定序列与参考基因组进行比对来识别变异。正如你可能会想到的,参考基因组是而不是完美的基因组——它是一个单倍体镶嵌图——它是由 13 个匿名捐赠者任意选择的一整套基因组序列拼接而成的。顾名思义,它是分析的参考。
我们通过称为变体调用的多步骤过程来找出 DNA 变体。分析的输出是一个变体调用格式文件,通常称为 VCF 。如果你想自己试试这个,建议你看一下银河平台。它是免费使用的,而且他们为初学者提供了很棒的入门教程。下面的分析来自参考基因组 GRCh37 的 ClinVar VCF 文件。
人类基因组中最常见的变异是什么?
The proportion of variant classes in our genome
每一个数据都有些令人困惑——计算需要一种’*剥洋葱’*的方法,一次一层。ClinVar 数据集可以大致分为七类变量。正如你所看到的,毫不奇怪,大约 90%的 ClinVar 数据集由单核苷酸变异体(SNVs)组成。snv 倾向于在基因组中累积一段时间,因为大多数 snv 都是不影响中心法则的微小缺失。另一方面,多核苷酸变异是致命的,尽管很罕见,它们是由复杂的基因组重排形成的——这是一个危险的策略。
所有的变异都是对我们有害的吗?
很明显,从图表来看,答案是否定的,不是全部。然而,缺乏变化是危险的;一会儿我会告诉你为什么。如果以上是真的,那么这个图表应该立即有意义。变异的影响也很大程度上取决于它在 DNA 中的变化类型和变异的位置。外显子或启动子中间的缺失将是灾难性的。然而,如果它位于内含子或 3’非翻译区,其影响可能是良性的。
SNVs 是什么原因造成的?
Different types of base conversions among the SNVs
臭氧是救生员,是上层大气中的一层面纱,保护我们的基因组免受紫外线的破坏。然而,一些更长的紫外线波长确实设法逃脱并落在我们身上。这个紫外线波长恰好在 T hymine 和 C ytosine 的吸收光谱内。辐射能的激发使它们与附近的碱基反应,产生嘧啶二聚体。暴露在阳光下的每一秒钟都会在我们的皮肤细胞中引发上百次这样的反应。但是我们有一个对策,*核苷酸切除修复,*切除损坏的碱基以减轻损害。如果这些得不到纠正,DNA 可能会永久变异。SNV 的另一个来源是碱基的错配,因为它们被紫外线、X 射线和γ射线电离。
这些事件属于两类和 颠换 。如图所示, 转换 是我们基因组中最常见的点突变(C - > T,G- > A,A- > G,T- > C)。
为什么缺失是致命的?
Shows what proportion of each variant contribute to pathogenicity
出生时患有啼哭综合症或猫哭综合症的婴儿经常像猫一样哭——这是 5 号染色体缺失的原因。高能辐射,如 x 射线和γ射线以及转座子会导致基因组损伤。结果往往是致命的,导致缺失。缺失会破坏 DNA 中编码信息的连续性,从而停止信息传递,并对细胞发育造成严重破坏。如图所示,大多数缺失都与致病性有关。
Number and size of deletions on human chromosomes
删除的最大大小似乎在 5KB 左右。可能存在选择偏差,使得任何大于 5Kb 的缺失都是致命的。
为什么染色体变异不同?
The variant landscape of human chromosomes
人类染色体是按大小递减的顺序编号的。也就是说 1 号染色体最大,22 号最小。从逻辑上来说,染色体越大,突变的几率越高,但事实并非如此,从直方图中可以明显看出。
谈到逻辑,19 世纪一些最伟大的头脑被生物学的逻辑玩弄于股掌之间——在他们努力破译遗传密码的过程中。大爆炸的创始人之一伽莫夫等人认为这是一个明显的组合学案例——20 个氨基酸&三胞胎(你可以在这里 阅读他 1954 年的自然论文 ),后来被克里克证明是错误的。逻辑没问题,但是想象力和实验性更好!说够了。
Human chromosomes
****看一看第 17 号染色体;它和 1 号染色体的变异一样多。这个很耐人寻味。期待一篇后续文章,我将对每个染色体的结构做一些挖掘。目前,我们可以得出结论,17 号染色体的突变率比其他染色体高得多。人们还可以观察染色体带,很快发现与其他染色体相比,17 的异染色质(暗带)非常少。
你可能已经注意到 Y 染色体缺乏变异;这是因为它在全基因组关联研究(GWAS)和全基因组/外显子组测序研究(WGS/WES)中代表性不足。
变异导致的紊乱有哪些?
首当其冲的是癌症和退化性疾病。缺失倾向于使个体倾向于不同形式的癌症。然而,有趣的是,在退行性疾病中没有缺失。
为什么变异会导致紊乱?
Pathogenic variants and their molecular consequences
DNA 美丽的双螺旋结构解决了信息存储的问题,但直到很久以后才解决了信息传递的问题。最初,一个学派认为它可能类似于莫尔斯电码。然而,没有人能找出莫尔斯电码中分隔单词的停顿的基因等价物。事实上,遗传密码中没有停顿。这是一个无限的信息——一个一维的核苷酸阵列,读作三元组,只有那些知道从哪里开始,什么时候停止的人才知道。这些基本原则结晶成了我们今天所知的 中心法则——从 DNA 到 RNA 到蛋白质的单向信息流。
正如你在 y 轴上看到的,这些变体可以在许多方面偏离中心教条,当它们偏离时,就会导致混乱。移码变异改变阅读框架,无义突变引入过早终止密码子,剪接变异影响 RNA 加工,等等。所有这些都会影响细胞功能。
你可能已经注意到在 frameshift_variant 类别中缺少 SNVs 这是因为 SNVs 是 到位 突变。
为什么有些染色体比其他的更具致病性?
Distribution pathogenic variants on human chromosomes
生存是一门艺术,我们的基因组是这门艺术的大师。进化的一个共同主题是在系统中引入冗余。我记得这个基因丝兰,我在加州大学戴维斯分校做博士后研究时广泛研究过它。细胞中有超过八个这种基因的副本,每次我突变一个,另一个就会打开并取代前者的位置。毕竟,没有植物能够在没有生长素的情况下存活,生长素是丝兰基因的产物,总共价值八份,你说呢!
染色体有各种类型,大的、小的、异色的、末端着丝粒的等等。每条染色体都有两对并不是偶然的——这是大自然创造备份的方式——就像我们会定期备份我们的电脑一样——你明白了。但是这个系统并不完美,看看 X 和 Y 染色体——在男性中,没有备份!如果你看一下图表,你可以看到 X 染色体上的高致病性变异负担,也许是其独特性的结果。我们很幸运有备份,否则每一个突变都会对我们的生活产生不利影响。
上图还表明,2 号和 17 号染色体有突变热点,这使它们极易发生变异。此外,这些热点可能藏有一些关键基因。
哪些基因受变异影响最大?
一些基因比其他基因更容易重排,因为它们在染色体上的位置和它们的序列,如 CpG 岛。这里,都与乳腺癌有关的 BRCA1 和 BRCA2 的缺失水平最高。乳腺癌是全球女性中最常见的癌症,这是由于在 BRCA 位点的染色体重排增加。如果你是一个男人,不要认为你摆脱了困境。根据疾病预防控制中心的说法,携带 BRCA 突变的男性更有可能患高级别前列腺癌、胰腺癌和乳腺癌。
不再平衡!
Top variant genes and their allele frequencies
达尔文的自然选择理论,一个令人困惑的简单想法,可以解释生命的整体,它的设计,复杂性和多样性。然而,它未能解释机会变异是如何产生并代代相传的。尽管达尔文和孟德尔是同时代的人,但没有人看到解释自然选择的明显联系。根据 Hardy-Weinberg 平衡,如果没有自然选择的作用,一个群体中等位基因的频率应该保持不变,这在这个星球的大部分生命中都是如此。疫苗等发现扭转了局面;现在,是人类的选择决定了微观进化。因此,我们将在图表中看到导致严重疾病的变异频率上升。
等位基因频率是变异在人群中流行程度的指标。频率越高,表明该等位基因在人群中出现的范围越广。在图表中,你可以看到小提琴图中较高的隆起,表明概率在变化。
变体似乎太麻烦了;我们不能摆脱他们吗?
“生命不会被遏制。生命挣脱了束缚。它扩张到新的领域,冲破障碍,痛苦地,甚至危险地。”伊恩·马尔科姆博士,侏罗纪公园
抛开陈词滥调,我有一个故事给你:20 世纪 70 年代的玉米穗腐病。一种叫做玉米小斑病菌的玉米疫病菌摧毁了美国的玉米种植带,美国 85%的玉米都种植在这里。据估计,这一连锁反应给美国经济造成了数千万美元的损失。
那里会发生什么?玉米是如何变得容易受到广泛的真菌攻击的?美国科学院进行的一项研究发现,玉米带中的大多数玉米植物都来自“德克萨斯雄性不育细胞质”,也就是 T 细胞质。换句话说,所有植物的 T 细胞质在遗传上是一致的。
将 T-细胞质导入玉米植株是一种极好的(?)促进高产、杂交玉米种子快速和有利可图的生产的方法。公司立即采用了它,并将其商业化,却没有完全了解其潜在的后果。当玉米小斑病菌的一个新品系进化时,它被证明是完美的 T 细胞质杀手,因为玉米群体中没有变异——想要深入研究,这里的就是论文。你看,克隆和 CRISPR 婴儿并不能解决我们的健康问题。我们不应该努力消灭变异,而是学会与之共存——真正的解决方案是 个性化医疗 。
我是 Aneesh。我是 Insight Data Science 的健康数据科学研究员。我开始写这篇文章时,脑子里想的是数据探索。原来我也有一些故事要分享。如果你今天学到了什么,我会很高兴。下次再聊!
神经网络玩电子游戏的探索
A brief look at a curiosity-driven model playing Mortal Kombat 3 for the Sega Genesis. The curiosity-driven model is the player on the left.
感谢我的团队成员:Benjamin Guo、 Christian Han 、 Cooper Shearer 、【Justin Qu】和 Kylar Osborne 。
介绍
电子游戏不仅仅是好玩。它们为神经网络提供了一个平台,可以学习如何与动态环境交互并解决复杂的问题,就像在现实生活中一样。几十年来,视频游戏一直被用来评估人工智能的表现,最近又出现在新闻中,像 DeepMind 这样的公司成功开发了能够击败顶级电子竞技专业人士的人工智能系统。
我们的团队希望探索各种机器学习算法如何在玩一些我们最喜欢的经典视频游戏时发挥作用。我们的目标不是创建特定游戏的最佳模型,而是观察它们的行为特征以及它们对不同游戏任务的适应性。
背景
在我们开始深入我们项目的细节之前,让我们看看这些模型是如何在基础层面上工作的,以及我们是如何与视频游戏交互的。
强化学习
强化学习是机器学习的一个领域。它不同于监督学习,因为不需要标记的输入和输出。相反,代理在环境中执行一些动作,环境返回一个观察和一个奖励。基于这种奖励,代理人可以学习继续展示其当前行为或避免它。当代理人试图最大化它的报酬时,这个反馈循环继续。
Diagram detailing the agent-environment system in reinforcement learning
为了把它放在一个更具体的环境中,让我们想象一个真人快打的游戏,代理人是我们的战士,环境由对手和舞台组成。如果我们的战士出拳并且能够降低对手的生命值,那么我们可能会因为我们的行动而得到奖励。另一方面,如果我们的战士跑了,而对手能够踢我们并降低我们的健康水平,那么我们可能会因为我们的行动而受到惩罚。
与视频游戏交互
为了将机器学习算法与视频游戏相结合,我们利用了由 OpenAI 开发的增强学习工具 Gym 和 Gym Retro 。Gym 允许我们创建前面提到的代理环境系统,而 Gym Retro 允许我们通过访问游戏中的变量和保存状态,从 Atari、Nintendo Entertainment System 和 Sega Genesis 等游戏机上模拟和运行复古游戏。
神经网络可以访问预定义的输入,每个输入都使代理执行一个动作。例如,对于世嘉创世纪控制台上的真人快打 3,神经网络只能从原始世嘉创世纪控制器上的六个按钮和方向箭头中进行选择。每个按钮都与一个特定的动作相关联(例如,“A”按钮对应一个低踢动作)。通过使用这些输入与环境交互,神经网络能够从观察和奖励中学习;最终,它能够学会如何正确应对各种情况并赢得比赛。
输入预处理
这些算法将视频游戏的每一帧作为图像输入。一个单独的关卡可能由成千上万的帧组成,而每一个单独的帧已经包含了大量的信息。因此,这个项目的一个主要方面是预处理这些图像输入,以平衡训练时间和神经网络的性能。减少计算的预处理方法有效,但是一些能提高性能的更先进的技术(不包括边缘检测)似乎对我们的模型没有帮助。
缩放输入和限制颜色
为了减少计算时间,同时保持数据的基本特征,我们缩小了许多图像的尺寸,并去掉了颜色。例如,Sega Genesis 模拟器的原始大小为 320x224 像素。我们把它缩小到一半大小,去掉了颜色。
Reducing input image size by half and removing colors
限制输入
对于每个游戏,都有我们不希望代理采取的特定动作和按钮。例如,在刺猬索尼克中,使用“向上箭头”将允许索尼克向上看,而在训练时,我们发现有些情况下只会向上看,而不会通过关卡。为了加快培训过程,我们限制了可以获得的输入。
Sonic really likes looking at those clouds…
跳帧
我们实际上忽略了一些作为输入给出的帧,因为不是所有的帧都包含重要的信息。例如,看看下面的 4 帧序列。很难区分前两帧。
Sequence of frames before applying frame skipping
通过跳过一些帧,我们能够保留足够的数据来辨别重要的特征,如运动,同时减少计算和训练时间。
Sequence of frames after applying frame skipping. Frames in yellow are used for input while frames that are crossed out are ignored.
框架堆叠
通过观察这张单一的图像,几乎不可能判断跳跃的角色正在向哪个方向移动。
通过帧堆叠,我们可以将多个帧组合成模型的单个输入。我们的模型实际上是基于一系列“堆叠在一起”的帧而不是单个帧来选择动作。这使得模型能够辨别角色移动的方向或速度。与我们的其他预处理方法不同,这项技术实际上增加了计算量,但通过帧堆叠获得的信息超过了成本。
Sequence of frames that have been skipped and stacked before being used as a single input for the neural network
背景去除
虽然我们的大部分预处理旨在减少信息以降低计算复杂度,但背景去除背后的想法是减少噪声。我们发现,一些受过训练的人工智能在达到不同背景的新水平时,表现出不同寻常的行为。
我们尝试了来自 OpenCV 库的许多不同的背景去除算法;然而,目前不存在用于去除动态背景的算法。除了去除背景之外,另一种方法是用不同的背景在不同的层次上训练人工智能
The background removal seems to be effective until the background begins scrolling
目标跟踪
在我们没有成功去除背景后,我们考虑简单地跟踪《真人快打 3》中的玩家对象和对手。不幸的是,OpenCV 库中现有的跟踪器要么将每帧的处理时间增加了 20 倍,要么无法保持对所需目标的锁定。此外,他们需要在对象上放置一个初始启动框,这需要手动选择或需要一些对象检测软件。
除了这些缺点,物体跟踪将只适用于真人快打 3,那里总是只有 2 个角色,没有其他相关的物体。在《刺猬索尼克》和《超级马里奥兄弟》中,简单地追踪主角会移除相关的环境信息,如 Goombas 或 powerups。
The object tracker first loses track of the original fighter and begins tracking the opponent. Then, it gets stuck on the light fixture in the background.
目标检测
为了克服物体跟踪器的缺点,我们决定尝试使用一个名为 YOLOv3 的物体检测库。YOLOv3 有几个版本,每个版本都有不同大小的预训练神经网络。虽然基线版本在识别真人快打的人形时工作得很好,但在单帧上运行需要大约 5 秒钟,这使得在我们当前的硬件上几乎不可能进行训练。(客观地说,我们目前的训练速度超过每秒 60 帧。)我们还尝试了 YOLOv3 的“微型”版本,它包括一个更小的神经网络,这被证明足够快;然而,由于分辨率较低,它无法始终如一地识别字符。
除了准确性较低之外,它完全无法检测出《超级马里奥兄弟》和《刺猬索尼克》中任何有用的东西,因为它没有经过训练,无法识别这两款游戏中的各种敌人和物品。由于缺乏时间,我们无法实现某种对象检测预处理,因为这需要我们的团队不仅要重新训练模型,还要找到并制作所有重要游戏对象的训练集。
边缘检测
降低噪声的另一种尝试是通过边缘检测。边缘图将灰度帧转换成二进制帧,进一步降低了输入的复杂性。然而,生成边缘图确实给每一步增加了一点开销。最初,我们的团队担心丢失了太多的细节,神经网络将无法从真人快打的对手中识别出自己,但简单的测试证明情况并非如此。当与模型结合时,这种预处理技术允许我们在《真人快打 3》上获得最佳结果。
Edge detection proved to be much more effective than we initially believed
神经网络
为了观察机器学习算法在玩视频游戏时的表现,我们使用了三个模型:来自 NEAT-Python 的增强拓扑的神经进化(NEAT) 、来自 OpenAI 的基线的近似策略优化(PPO) ,以及来自加州大学伯克利分校、爱丁堡大学和 OpenAI 的研究人员的好奇心驱动的神经网络。
我们在世嘉创世纪控制台的真人快打 3 上训练了所有这些模型。此外,我们能够在 Sega Genesis 的刺猬索尼克上训练 NEAT,我们能够在 Sega Genesis 的刺猬索尼克和任天堂娱乐系统的超级马里奥兄弟上训练好奇心驱动的神经网络。
NEAT(扩充拓扑的神经进化)
NEAT 是一个使用基因组描述个体网络的前馈网络。该算法使用适应度函数通过世代进化网络。在训练过程中,通过高分基因组之间的繁殖以及一些突变来产生后续世代。添加节点和连接的快速实现允许基因组网络在结构上适应和增长,这提供了优于固定大小网络的优势。
我们使用 NEAT 的 Python 实现在《真人快打 3》和《刺猬索尼克》上进行训练。NEAT 由一个配置文件初始化,该文件定义了常量,如输入/输出数量、突变概率和权重参数。前馈网络的输入是游戏屏幕的图像,输出是按钮按压。一个奖励函数累积起来决定每个基因组的适合度。
我们成功训练了一个整齐的网络,打败了刺猬索尼克的第一关。我们还在《真人快打 3》上对它进行了训练,但由于技术困难,无法恢复视频文件。
Full gameplay for NEAT on Sonic The Hedgehog
Lucas Thompson 在 NEAT 上的视频帮助我们编写代码,也极大地提高了我们有效训练的能力。
基线
OpenAI Baselines 库实现了各种各样的强化学习算法,基于我们在相关项目中看到的成功,我们选择使用 PPO2 模型。
在使用基线时,我们发现尽早提出一个合理的奖励函数是很重要的。我们最终不得不在项目期间多次修改我们的奖励函数,这使得当我们想要测试新方法时,很难比较模型的性能,因为奖励的比例不一致。我们发现,最好的奖励功能是奖励和惩罚几乎相等,奖励应该立即给予,而不是在一集结束时给予。当前奖励功能监控双方战士的健康和比赛胜利,当检测到变化时,立即给予奖励或惩罚。
在让奖励函数工作之后,我们想把重点放在输入的预处理上,这是我们前面讨论过的。大量预处理的目标是减少模型在 GPU 内存中的大小。我们在具有 8 GB 板载 RAM 的视频卡上训练了这个模型,并且出乎意料地容易超出可用内存。我们需要并行训练模型,以使训练时间合理,通常有 16 个环境,因此当涉及到 GPU 内存时,模型大小的任何变化都会放大 16 倍。对图像进行缩放和灰度缩放可以大幅减少输入尺寸,但是当您通过帧堆叠再次增加图像尺寸时,这些增益大多会丢失。帧堆叠的性能提升超过了空间的合理性,所以我们开始跳过帧来降低内存占用。影响模型大小的其他因素是 nsteps 变量,它控制模型优化的范围,以及 nminibatches 变量,我们认为它采用整个范围并将其分成更小的块,用于梯度下降以更新策略。增加 nsteps 会增加模型在内存中的大小,但是增加 nminibatches 会减少模型在内存中的大小;我们认为这是因为一旦小批次被处理,帧就不再存储在存储器中。
一旦模型能够适应内存,我们就开始优化超参数。我们发现 0.00005 的学习率效果很好。我们尝试了高达 0.00025 的不同值,这使得这些模型最初快速降低了它们的误差,但是它们在大约 300 万个时间步长之后明显变慢,并且在大约 1000 万个时间步长之后被具有更小学习速率的模型超过。
在我们尝试的优化中,最令人惊讶的是边缘检测带来的性能提升。在我们看来,边缘检测器似乎删除了太多的细节,但用边缘检测器训练的模型击败了我们以前的所有尝试。
我们成功地训练了我们的基线网络,以击败《真人快打 3》中的前四关。
Full gameplay for Baselines on Mortal Kombat 3. The model is the Kabal character on the left.
要查看我们 PPO2 模型的代码,请查看git lab。这个代码是基于一个由AurelianTactics开发的项目,在那里他使用 PPO 来玩魂斗罗 3。
好奇心
好奇心驱动的神经网络不是通过使用奖励函数来学习,奖励函数必须手动构建,然后进行测试,这可能是一个乏味且耗时的过程,而是通过能够正确预测给定其当前状态下其行为的结果将会发生什么来学习。这些模型具有内在的动机;他们总是试图最小化自己的预测误差。这与试图最大化一些用户定义的奖励的外部激励模型形成对比。例如,考虑一个好奇的代理玩超级马里奥兄弟的情况。代理自然会想要探索整个级别,以便通过移动和跳跃来最小化预测将会发生什么的错误,探索级别与在马里奥中完成它们是一样的。
我们必须在游戏中训练好奇心驱动的神经网络,以确保代理知道正确的输入是什么。我们还必须增加对某些游戏机显示分辨率的支持。对于如何学习特征,代码中有各种选项:像素、随机特征、变分自动编码器、逆动态特征。在研究论文中一个有趣的结果是,仅仅使用像素作为特征通常会产生最差的性能。事实上,随机特征在比较中被证明是非常有效的,并且是默认的特征学习方法。由于时间和计算的限制,我们选择在我们训练的每个游戏中使用这个默认的方法。在未来,使用其他特征学习方法并比较由此产生的代理的性能将是有趣的。
好奇心驱动的神经网络在《超级马里奥兄弟》中表现最佳,达到了第三级。另一方面,扮演刺猬索尼克的特工总是会在第一关被卡住。我们认为这是由于游戏中非常动态的背景(例如,动画瀑布,波光粼粼的水,旋转的花,滚动的云)。相比之下,《超级马里奥兄弟》中的背景基本上是静态的。不过,这个结果并不太令人意外。研究论文简要讨论了这一特殊的局限性。《真人快打 3》尽管接受训练的时间最少,但也有相对静态的背景,玩这个游戏的代理人往往可以达到第二关。
A curious agent playing Sonic the Hedgehog becomes easily distracted by the busy background. Here, the agent most likely thinks the animation of the waterfall is a result of its own actions. It then gets stuck trying to minimize its error in predicting how the waterfall will change as a result of running and jumping around.
我们成功地训练了一个好奇心驱动的网络,达到了《凡人快打 3》的第二关和《超级马里奥兄弟》的第三关,但我们无法击败《刺猬索尼克》中的任何关卡。
Full gameplay for Curiosity on Mortal Kombat 3. The model is the Shang Tsung character on the left.
Full gameplay for Curiosity on Sonic The Hedgehog
Full gameplay for Curiosity on Super Mario Bros.
我们对于好奇心驱动的神经网络的代码大部分是从最初的实现中在创造者的 GitHub 上找到的。Lucas Thompson 的 视频教程 有助于我们理解代码库。
结论
最终,预处理、边缘检测和基线的结合在《真人快打 3》上产生了最好的结果,让我们击败了前四关。NEAT 是最容易使用的;设置好之后,我们真正需要做的就是调整超参数以提高性能。基线要困难得多,因为设计一个有效的奖励函数比我们预期的更具挑战性。最后,由于缺乏文档,好奇号很难使用,但它很容易训练,因为不需要外部奖励。好奇号在效率方面的表现受到了动态背景的负面影响,但它仍然能够通过关卡取得进展。
Results for furthest level reached for each of the models on each game
我们在前面的章节中提到了一些我们遇到的挑战,但是在整个项目中,培训时间是我们最大的挑战。这是这个项目的一个瓶颈,即使我们做了预处理工作。
对于这个项目,我们能够使用真人快打 3 作为我们的控制游戏,但我们希望在未来通过包括更多的游戏和更多样化的游戏类型来扩展这一点。我们也想看看这些模型有多通用;换句话说,有没有可能有一个单一的模型可以擅长许多不同的游戏?
虽然不如我们自己玩电子游戏有趣,但我们在整个项目中学习、失败和成功都度过了一段美好的时光。
英俊的公司主管人工智能图解指南
如何将机器学习从概念验证转移到核心组织能力
Shut up Siri, just shut up (Image credit: North By Northwest)
如今,许多公司都在机器学习方面取得进展。最近深度学习的进步和可用数据的大规模增加使图像识别和自然语言处理取得了飞跃,这使得 AI*几乎在任何地方都受到了企业的关注。ML 已经超越了人类,使公司能够处理大规模的服务请求,这是 100%人工服务台根本不可能做到的。它在从欺诈检测到医学图像分析,从机器翻译到个性化推荐等领域都有成功的应用。由于相当多的人工智能头条新闻是由 GAFA 公司制造的,所以当你开始探索人工智能在你的业务中的应用时,作为一名高管或服务经理,你很自然地会关注他们。除了遵循这种方法的明显问题——你的公司可能仍然是一个很大程度上的离线努力——还有一些较少讨论的问题我想在这篇文章中解决。
*AI =应用机器学习
Only 5 percent of artificial intelligence is actually about machines learning (source: [1])
首先,大型科技报纸标题中宣传的收益混淆了他们成功基础上的巨大事业和多年发展、人员运作、投资和失败项目。当然,这不应该成为你开始探索机器学习应用的障碍,但在建立你的第一个机器学习团队或赞助你的第一个概念证明时,记住这一点可能是有用的——ML 远未成熟,一些项目需要大量的前期投资才能在行业环境中应用。举个例子,如果我要将上面的图表转换到没有适当数据基础设施的 LSE 环境中,这大约相当于 10 个 FTE 工作两年才能接近一个基本的可扩展机器学习平台。所有这些时间和金钱只会为您购买一些基础设施(不包括模型)。一旦你的团队达到这一点,期望他们全职工作于数据管道、变更管理、操作、集成和模型开发。这对伦敦政治经济学院来说是一笔巨大的投资——根据你的抱负、规模和地理位置,在 100 万欧元到 1000 万欧元之间。包括数据基础设施(您的数据湖/护城河/沼泽/排水沟)所需的前期投资,这样一项工作的预计成本可能会很快达到数千万欧元。
We‘re bad enough at forecasting when there is a reference class to base the forecast on (source: [2]).
奇怪的是,我见过的企业中采用机器学习的最常见方法是盲目飞行(一个明显的例外是 Ronny Fehling 在空中客车对工业化人工智能的愿景;他后来转到了波士顿咨询公司。看起来,围绕人工智能的大肆宣传已经让典型的董事会成员免除了明智的项目管理和长期战略思考的责任。这是一个危险的情况,因为许多这些“人工智能无处不在”的投资直接来自每个人都在投资人工智能的事实,而不是来自可行的商业案例和发布战略。我们都知道,FOMO 就像金融市场一样,充其量也是不可预测的。随着数据被比作石油(剧透——它不是,不同的外部性),人工智能被比作电力(也不正确,许多日常工作不需要认知能力),人工智能被比作烹饪(对于从业者),我想提出一个新的类比,希望让你更好地理解人工智能的采用将在未来五十年内在全球经济中采取的轨迹:飞行。
POC for a business experiment in the bicycle industry, ca 1903 (Image credit: Wikipedia)
尽管目前人们对基于无人机的即时送货兴奋不已(让我无人机送面包圈),但人们很容易忘记,飞行用了 100 多年才成为真正的商品。即使我们在不久的将来达到这一点,预计商业航空公司在 2019 年产生的 8550 亿美元空中收入的大部分将来自运输人员——这是一种与第一家商业航空公司一样古老的商业模式。同样,当我们看机器学习时,以营业收入和股票价格衡量,对我们 21 世纪世界的主要附加值贡献大体上仍然是付费广告。这回避了一个问题,即我们是否可以期待机器学习的工业应用在未来几年快速发展,超越基于个性化的应用。很多人都在押注物联网(IoT)应用。虽然物联网确实产生了大量数据,但如果没有规模经济和适当的基础设施,该领域中 ML 应用的价值将不会超过其成本。与 POC 不同,工业规模的 ML 系统控制需要质量控制、持续维护和持续改进,如果 ML 提供的改进微不足道,这将是一个沉重的代价。也就是说,我不认为运行智能冰箱的空中交通控制塔的 ML 模拟在经济上是可行的。到目前为止,预测性维护是 ML 广泛采用的消费者领域之外的一个应用。另一方面,消费者领域的 ML 应用已经一次又一次地证明了自己。人机交互从 ML 中受益匪浅。我们正在目睹人工智能通过搜索引擎、智能助手、智能相机和自动驾驶等工具,成为这个星球上绝大多数人类与机器的主要消费者界面。
这是一个危险的情况,因为许多这些“人工智能无处不在”的投资直接来自每个人都在投资人工智能的事实,而不是来自可行的商业案例和发布战略。
回到飞行的类比,除了操作飞机的机组人员,飞机还需要地勤人员和足够的基础设施,以确保飞机飞行路线上的人员和货物与经济的其他部分相联系。换句话说,航空公司是由航空业之外更大的价值链和生态系统支撑的。ML 也是如此——它不存在于真空中。负责开发和维护模型的运营团队(数据科学家、数据工程师、机器学习经理、业务分析师等)是企业价值链和由企业应用程序、业务流程、数据基础设施和计算资源组成的更广泛的 IT 生态系统的一部分。虽然对设计和建造机场的人来说显而易见,但这些外部性在机器学习项目中经常被公然忽视。尽管设计良好的机器学习算法肯定不会损害你的成功机会,但如果没有将模型预测正确整合到内部或面向客户的业务流程中——机器学习 UI 和 UX——以及更广泛的价值链和生态系统,你的项目几乎肯定会失败。事实上,在缺乏经验证据的情况下(我知道这一点),我敢打赌,许多 ML 项目的成功或失败更多地受到公司发起人和利益相关者的影响,而不是 ML 团队本身在项目期间设法产生的任何东西。
A simple cyclical business model (image by author)
这使我想到了第二点。用机器学习创造价值往往是一个组织问题,而不是技术问题。因此,这不是机器学习实践者可以独立于组织的其他部分解决的问题。许多旨在创造商业价值的机器学习项目失败了,因为它们需要业务人员和技术人员之间的合作。这意味着,冒险进入这个勇敢的 21 世纪新数字世界的公司不仅需要采用新的和不熟悉的技术(人工智能),而且他们还需要从组织分工(和冰山风险管理)转向更灵活的由价值创造而不是业务功能绘制的组织线(见这篇麦肯锡的文章对基于平台的组织的介绍)。一旦你成功地完成了这些转变,就可以从你对机器学习的押注(投资)中获得难以置信的回报,比如客户互动的改善、成本效率和总体的惊喜。由于当今公司拥有的数字工具不再需要最直接的人与人之间的互动,任何跨职能团队都可以通过数字界面直接与客户互动,不再需要曾经代表公司的销售、人力资源或服务人员。这个逻辑既适用于主要客户是内部客户的团队(如人力资源或财务),也适用于拥有外部客户的团队(销售、服务交付等)。).
Image credit: North by Northwest
重申一下,人工智能需要嵌入到业务流程中,才能创造价值。因此,这意味着接触、改变和增强在公司 IT 环境中实现的确定性业务逻辑。坦率地说,这将导致大量的工作,以及在这些工作之上更多意想不到的工作。此外,除了对现有业务流程进行重新设计之外,人工智能驱动的运营产品还需要一个机器学习平台,以促进嵌入公司产品、业务和运营中的大量预测流程的快速开发、部署和监控。这意味着端到端的数据可追溯性、用于近实时流程的低延迟数据流,以及跨职能团队对贯穿整个组织的所有数据流的数据访问。从这个意义上说,机器学习应用与之前的自动化浪潮有很大不同。自动化认知和概率能力的引入带来了对数据驱动过程的质量控制的需求的增加。不幸的是,这需要业务利益相关者和技术专家之间更多更好的合作。
The machine learning lifecycle (image by author)
奇怪的是,公司通常会将 ML 项目成败的部分留给数据科学家。无论这位数据科学家是外部承包商还是内部员工,他或她通常都不具备处理公司政治的能力,并且通常缺乏对现有业务流程进行更改的公司授权。这导致了那些可怕的无法交付任何商业价值的 MLPOCs。受过大学和研究生教育的数据科学家应用他们在学术界学到的工作流来解决业务问题。有人在某个地方找到了一台服务器,在没有监控的情况下安排了模型,而数据科学家则继续进行下一个 MLPOC。大家都很开心(我们做了 AI!),而且什么都没有真正改变。这是一个非常黑白分明的表示,但它凸显了人工智能产业化的一个主要挑战。如果没有适当的设计和项目执行,机器学习项目就有陷入无附加值的 ML 概念证明(MLPOC)的风险,在这种情况下,高管们在 FOMO 创作 ML 项目,数据科学家应用他们在研究生院学到的知识,没有人愿意负责确保项目产生真正的 ROMLIs(机器学习投资回报)。
从这个意义上说,机器学习应用与之前的自动化浪潮有很大不同。自动化认知和概率能力的引入带来了对数据驱动过程的质量控制的需求的增加。
Life’s an adventure (image by author)
简而言之,今天被资助的机器学习努力的随意性是导致灾难的原因。最重要的是,并不是你组织中的每个人都是那种无望的乐观主义者,他们认为人工智能有潜力通过自动化日常认知任务来改善世界范围内的工作条件,从而将我们人类解放出来从事更有趣的工作。有很多人害怕自动化会接管他们的工作,害怕失去决策权,或者只是害怕改变,这导致了旷日持久的政治阴影和战壕战争,这些都减缓了机器接管世界的速度(大胆的悲伤表情符号)。人工智能从业者和消费者的长期风险是,在一系列过于慷慨的承诺和令人失望的结果之后,企业将在未来几十年继续照常运营。这是一种耻辱,因为这意味着你的客户将被迫继续生活在 20 世纪 80 年代的科技时代。总而言之,任何机器学习项目要想成功,都需要具备几个前提条件:
对于 ML 团队来说,
- 机器学习模型可以利用的数据基础设施。
- 用于训练机器学习模型的计算基础设施。
- 将模型预测整合到应用中的生产途径。
- 监控和 AB 测试基础设施,以衡量模型预测对业务和分析 KPI 的影响。
在商业方面,
- 识别业务流程,在这些流程中,可以应用足够多的 ROMLI 来保证所做的工作:高容量、低延迟、高成本、常规认知、危险等。业务流程。
- 围绕可以通过机器学习增强或促进的业务流程,协调跨职能利益相关方。
- 开发机器学习模型可以操作的硬约束——认知界限。
- 监控业务 KPI 并向 ML 团队提供(最好是基于统计的)反馈。
从上面的要点可以看出,ML 团队在这方面的工作很简单。困难的部分是调整和改变你的组织,以允许你充分利用机器学习技术进步提供的机会。这是今天大多数 ML 项目继续搁浅的地方。由于 ML 团队或其直接赞助者通常没有跨部门业务流程的授权,如果你想认真对待 ML,你需要亲自监督和指导这些项目,或者任命具有足够广泛授权的人来发现和促进现有业务流程的 ML 支持的变化,或者开发基于 ML 能力的新流程。
免责声明:我是一名自由职业的机器学习工程师,因此机器学习在组织中成功落地并为我的客户提供最大的 ROMLI(机器学习投资回报)符合我的最佳利益。吃块饼干吧。
截图来自阿尔弗雷德·希区柯克 1959 年的《西北偏北》。
泊松回归模型图解指南
和使用 Python 的泊松回归教程
在本文中,我们将讨论以下主题:
- **基于计数的数据的特征:**计数数据集是世界上最常见的一些数据。我们将看看是什么使基于计数的数据不同。
- 预测数量的回归模型:我们来详细看看泊松回归模型。负二项式(NB)回归模型是另一种常用的基于计数的数据模型。我将在以后的文章中讨论这个问题。
- **关于泊松回归的 Python 教程:**我将带你一步步学习如何使用 statsmodels 的 GLM 类在 Python 中创建泊松回归模型,以及如何在真实世界数据集上训练它。
在我们开始之前,有几个要点…
- 对于关于泊松回归的 Python 教程,向下滚动到本文的最后几节。
- Python 代码的 Github 要点是这里的。
- 本文中使用的一个骑自行车者计数的真实世界数据集是这里的。****
- 关于随机变量、泊松过程和模拟泊松过程的 Python 程序,点击这里:
泊松过程:你需要知道的一切
现在让我们开始吧!
什么是基于计数的数据?
基于计数的数据包含以特定速率发生的事件。发生率可能会随着时间的推移或从一次观察到下一次观察而变化。以下是一些基于计数的数据示例:
Data source: Wikipedia: potentially habitable exoplanets (Image by Author)
- 每小时通过十字路口的车辆数量,
- 每月去诊所看病的人数,
- 每月发现的类地行星数量。
计数数据集具有以下特征:
- ****整数数据:数据由非负整数组成:[0… ∞]普通最小二乘回归等回归技术可能不适合对这类数据建模,因为 OLSR 最适合处理实数,如-656.0、-0.00000345、13786.1 等。
- ****偏斜分布:数据可能包含大量的数据点,但只有几个值,从而使频率分布相当偏斜。例如,参见上面的直方图。
- ****稀疏性:数据可能反映了伽马射线爆发等罕见事件的发生,从而使数据变得稀疏。
- ****发生率:为了建立模型,可以假设有某个事件发生率 λ 驱动这种数据的产生。事件率可能随时间漂移。
真实世界的计数数据集
下表包含了骑自行车的人在纽约市各种桥梁上行驶的次数。从 2017 年 4 月 1 日到 2017 年 10 月 31 日每天测量计数。
Source: Bicycle Counts for East River Bridges (Data source: NYC OpenData) (Image by Author)
这是布鲁克林大桥上骑自行车的人数的时间顺序图:
Background image: The Brooklyn bridge as seen from Manhattan island
计数的回归模型
泊松回归模型和负二项式回归模型是开发计数回归模型的两种流行技术。其他可能性有有序 Logit 、有序 Probit 和非线性最小二乘模型。****
回归策略
从泊松回归模型开始,并将其用作更复杂或约束更少的模型的“控制”是一个很好的实践。在他们的《计数数据的回归分析》一书中,卡梅隆和特里维迪说:
“合理的做法是估计泊松和负二项模型.”
在本文中,我们将使用泊松回归模型来回归布鲁克林大桥上观察到的骑自行车的人数。
介绍泊松模型
泊松分布具有如下的概率函数。
Probability of seeing k events in time t, given λ events occurring per unit time (Image by Author)
泊松分布的期望值(平均值)为 λ。 因此,在没有其他信息的情况下,人们应该期望在任何单位时间间隔内看到 λ 事件,例如 1 小时、1 天等。对于任何区间 t ,人们都会期望看到 λt 事件 。
一个泊松回归模式 l 为 常数λ
如果事件速率【λ】是恒定的,则可以简单地使用修改的均值模型来预测事件的未来计数。在这种情况下,可以将计数的所有预测值设置为该常量值 λ 。
下图说明了常量 λ 的场景:
Actual and predicted counts for a constant rate model (Image by Author)
以下 Python 代码用于使用泊松过程生成蓝点(过去时间步的实际计数),其中 λ=5 。橙色点(预测)都被设置为相同的值 5。
A Python program to generate event counts using a Poisson process
非常数λ 的泊松回归模型
现在我们到了有趣的部分。让我们检查一个更常见的情况,其中 λ 可以从一个观察值变化到下一个观察值。在这种情况下,我们假设 λ 的值受解释变量、的向量影响,这些变量也被称为预测变量、回归变量或回归变量*。我们称这个回归变量矩阵为 X 。*****
回归模型的工作是将观察到的计数 y 拟合到回归值矩阵 X 。
在纽约市自行车统计数据集中,回归变量是日期、星期几、高温、低温和降水量。我们还可以引入额外的回归变量,如从日期派生的月日和月日,并且我们可以自由删除现有的回归变量,如日期。
(Image by Author)
y 到 X 的拟合通过固定回归系数 β的向量值来实现。
在泊松回归模型中,事件计数 y 被假设为泊松分布,这意味着观察到 y 的概率是事件速率向量 λ的函数。
泊松回归模型的工作是通过一个链接函数将观察到的计数 y 拟合到回归矩阵 X ,该链接函数将速率向量 λ 表示为 1)回归系数 β 和 2)回归矩阵X的函数****
下图说明了泊松回归模型的结构。
Scan from left to right: The structure of the Poisson regression model (Image by Author)
有什么好的链接功能 f (。)连接 λ 和 X ?事实证明,以下指数链接函数非常有效:
The exponential link function of the Poisson regression model (Image by Author)
即使当回归变量 X 或回归系数 β 为负值时,该链接函数也会保持 λ 为非负值。这是基于计数的数据的要求。
一般来说,我们有:
The exponential link function of the Poisson regression model (Image by Author)
泊松回归模型的形式规范
基于计数的数据的泊松回归模型的完整规格如下所示:
对于回归变量 x_i 行对应的 y_i 表示的数据集中第个个观察值,观察计数 y_i 的概率为泊松分布,其分布如下:
Probability of observing count y_i given x_i (as per the Poisson PMF formula) (Image by Author)
其中第 I 个样本的平均速率 λ_i 由前面所示的指数链接函数给出。我们在这里重现它:
The exponential link function of the Poisson regression model (Image by Author)
一旦模型在数据集上完全训练完毕,回归系数已知,模型就可以进行预测了。为了预测与已经观察到的回归量 x_p 的输入行相对应的事件计数 y_p ,使用以下公式:
The prediction equation for the Poisson regression model (Image by Author)
所有这些都依赖于我们成功训练模型的能力,这样回归系数向量【β】就是已知的 。
让我们看看这种培训是如何进行的。
定型泊松回归模型
训练泊松回归模型包括寻找回归系数 β 的值,这将使观察计数的向量 y 最有可能。
识别系数 β 的技术称为 M 最大值 L 似然比 E 估计(MLE)。
让我们来熟悉一下 MLE 的技巧。
理解最大似然估计
我将使用自行车计数数据集来说明 MLE 技术。看看这个数据集的前几行:
Daily counts of bicyclists on the Brooklyn bridge (Image by Author)
我们的假设是,红框中显示的骑自行车的人数来自泊松过程。因此我们可以说它们的发生概率是由泊松 PMF 给出的。以下是前 4 次发生的概率:
Probabilities of observing the bicyclist counts for the first few occurrences given corresponding regression vectors (Image by Author)
我们可以类似地计算在训练集中观察到的所有 n 计数的概率。
注意,在上述公式中,λ_1、λ_2、λ_3、…、λ_n 是使用如下链接函数计算的:**
The event rates corresponding to the counts for the first few days (Image by Author)
其中x1,x2,x3,x4为回归矩阵的前 4 行。******
训练集中整组 n 个计数 y_1,y_2,…,y_n 出现的概率就是单个计数出现的联合概率。
计数 y 为泊松分布, y_1,y_2,…,y_n 为独立随机变量,对应给出 x_1,x_2,…,x_n 。因此, y_1,y_2,…,y_n 出现的联合概率可以表示为单个概率的简单乘积。下面是整个训练集的联合概率:
The likelihood function L(β) expressed as a joint probability mass function (Image by Author)
让我们回忆一下, λ_1,λ_2,λ_3,…,λ_n 通过回归系数 β链接到回归向量 x_1,x_2,x_3,…,x_n 。
***β 的什么值会使给定的一组观察计数 y 最有可能?上式所示的联合概率达到最大值的是 β 的值。换句话说,就是联合概率函数 w.r.t. β 的变化率为 *0 的 β 的值。换一种说法,就是对联合概率方程 w.r.t. β 进行微分并将这个微分方程设为 0 所得到的方程的解。
联合概率方程的对数*比原方程更容易微分。对数方程的解产生相同的最优值*。****
这个对数方程被称为对数似然函数。对于泊松回归,对数似然函数由以下等式给出:
log-likelihood function for the Poisson regression model (Image by Author)
将 λ_i 替换为exp(x _ Iβ))后,取前面所示的联合概率函数两边的自然对数,即可得到上述等式。***
如前所述,我们对这个对数似然方程 w.r.t. β 进行微分,并将其设置为零。这个操作给出了下面的等式:
The Poisson MLE for β is the solution to this equation (Image by Author)
解回归系数的这个方程将产生 β的最大似然估计 (MLE) 。******
为了求解上述方程,可以使用迭代方法,例如迭代加权最小二乘法(IRLS) 。实际上,人们不能手工解这个方程。相反,您可以使用统计软件,如 Python statsmodels 包,它会在对数据集训练泊松回归模型时为您完成所有计算。
执行泊松回归的步骤摘要
总之,下面是对基于计数的数据集执行泊松回归的步骤:
- 首先,确保您的数据集包含计数。一种方法是,它只包含非负的整数值,这些值表示某个时间间隔内某个事件发生的次数。在骑自行车的人数数据集中,它是每天骑自行车穿过布鲁克林大桥的人数。
- 找出(或猜测)会影响观察计数的回归变量。在自行车计数数据集中,回归变量为星期几、最低温度、最高温度、降水量等。**
- 创建一个你的回归模型将要训练的训练数据集,和一个应该放在一边的测试数据集。不根据测试数据训练模型。
- 使用合适的统计软件,如 Python statsmodels 包,对训练数据集配置和拟合泊松回归模型。
- 通过在测试数据集上运行模型来测试模型的性能,以便生成预测的计数。将它们与测试数据集中的实际计数进行比较。
- 使用拟合优度来确定您的模型在定型数据集上的定型程度。
如何在 Python 中进行泊松回归
让我们把所学的东西付诸实践。Python statmodels 包对泊松回归有很好的支持。
让我们使用布鲁克林大桥自行车计数数据集。您可以从 这里的 中提取数据集。
我们的目标是为观察到的骑自行车的人数建立一个泊松回归模型 y. 我们将使用训练好的模型来预测布鲁克林大桥上的骑自行车的人的每日人数,这是模型在训练期间没有看到的。
Daily count of bicyclists on the Brooklyn bridge (Image by Author)
我们将从导入所有需要的包开始。
**import pandas as pd
from patsy import dmatrices
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt**
为计数数据集创建一个熊猫数据框架。
**df = pd.read_csv('nyc_bb_bicyclist_counts.csv', header=0, infer_datetime_format=True, parse_dates=[0], index_col=[0])**
我们将向矩阵 X 添加一些派生的回归变量。
**ds = df.index.to_series()df['MONTH'] = ds.dt.monthdf['DAY_OF_WEEK'] = ds.dt.dayofweekdf['DAY'] = ds.dt.day**
我们将不使用日期变量作为回归变量,因为它包含一个绝对日期值,但是我们不需要做任何特殊的事情来删除日期,因为它已经作为熊猫数据帧的索引被使用。因此它在 X 矩阵中对我们不可用。****
让我们创建训练和测试数据集。
**mask = np.random.rand(len(df)) < 0.8df_train = df[mask]df_test = df[~mask]print('Training data set length='+str(len(df_train)))print('Testing data set length='+str(len(df_test)))**
用 patsy 符号设置回归表达式。我们告诉 patsy,BB_COUNT 是我们的因变量,它取决于回归变量:DAY、DAY_OF_WEEK、MONTH、HIGH_T、LOW_T 和 PRECIP。
**expr = """BB_COUNT ~ DAY + DAY_OF_WEEK + MONTH + HIGH_T + LOW_T + PRECIP"""**
为训练和测试数据集设置 X 和 y 矩阵。patsy 让这变得非常简单。
**y_train, X_train = dmatrices(expr, df_train, return_type='dataframe')y_test, X_test = dmatrices(expr, df_test, return_type='dataframe')**
使用 statsmodels GLM 类,对定型数据集定型泊松回归模型。
**poisson_training_results = sm.GLM(y_train, X_train, family=sm.families.Poisson()).fit()**
打印培训总结。
**print(poisson_training_results.summary())**
这会打印出以下内容:
Training summary for the Poisson regression model (Image by Author)
那么我们的模型表现如何呢?让我们对测试数据集做一些预测。
**poisson_predictions = poisson_training_results.get_prediction(X_test)#.summary_frame() returns a pandas DataFrame
predictions_summary_frame = poisson_predictions.summary_frame()print(predictions_summary_frame)**
以下是输出的前几行:
First few rows of output from poisson_predictions.summary_frame() (Image by Author)
让我们绘制测试数据的预测计数与实际计数的对比图。
**predicted_counts=predictions_summary_frame['mean']actual_counts = y_test['BB_COUNT']fig = plt.figure()fig.suptitle('Predicted versus actual bicyclist counts on the Brooklyn bridge')predicted, = plt.plot(X_test.index, predicted_counts, 'go-', label='Predicted counts')actual, = plt.plot(X_test.index, actual_counts, 'ro-', label='Actual counts')plt.legend(handles=[predicted, actual])plt.show()**
以下是输出结果:
Predicted versus actual bicyclist counts on the Brooklyn bridge (Image by Author)
该模型似乎或多或少地跟踪实际计数的趋势,尽管在许多情况下,其预测值与实际值相差甚远。
让我们绘制实际计数与预测计数的对比图。
**plt.clf()fig = plt.figure()fig.suptitle('Scatter plot of Actual versus Predicted counts')plt.scatter(x=predicted_counts, y=actual_counts, marker='.')plt.xlabel('Predicted counts')plt.ylabel('Actual counts')plt.show()**
剧情是这样的:
Scatter plot of Actual versus Predicted counts (Image by Author)
这里是使用 Python 进行泊松回归的完整源代码:
泊松回归模型的拟合优度
记住泊松分布的期望值(即均值)和方差都是 λ。大多数真实世界的数据都违反了这个相当严格的条件。
泊松回归模型失败的一个常见原因是数据不满足泊松分布强加的均值=方差标准。**
stats modelsglm results类上的 summary() 方法显示了一些有用的拟合优度统计数据,可帮助您评估泊松回归模型是否能够成功拟合训练数据。让我们看看他们的价值观:
Training summary for the Poisson regression model (Image by Author)
偏差和皮尔逊卡方的报告值非常大。给定这些值,很好的拟合实际上是不可能的。为了在某个置信水平(比如 95% (p=0.05))下定量确定拟合优度,我们在 χ2 表中查找 p=0.05 和残差自由度=163 的值。(测向残差=无观测值减去测向模型】。我们将该卡方值与观察到的统计数据进行比较,在这种情况下,是 GLMResults 中报告的偏差或皮尔逊卡方值。我们发现,在 p=0.05 且 DF 残差= 163 时,来自标准卡方表的卡方值为 193.791,远小于报告的统计值 23030 和 23300。因此,根据该测试,尽管泊松回归模型显示出对测试数据集的‘好的’视觉拟合,但它对训练数据的拟合相当差。**
结论和下一步措施
对于基于计数的数据,泊松回归模型是一个有用的起点。然后可以将其性能与其他基于计数的流行模型进行比较,例如:
快乐造型!
感谢阅读!我写关于数据科学的主题,重点是回归和时间序列分析。
如果你喜欢这篇文章,请关注我的Sachin Date获取关于回归和时间序列分析主题的提示、操作方法和编程建议。
费希尔线性判别式的说明性介绍
为了处理两个或更多类别的分类问题,大多数机器学习(ML)算法以相同的方式工作。
通常,他们对输入数据应用某种转换,结果是将原始输入维度减少到一个较小的数字。目标是将数据投射到一个新的空间。然后,一旦投影,该算法试图通过找到一个线性分离来分类这些点。
对于输入维数较小的问题,任务稍微容易一些。以下面的数据集为例。
假设我们要对红蓝圈进行正确的分类。
很明显,用简单的线性模型我们不会得到好的结果。没有将输入映射到其正确类别的输入和权重的线性组合。但是,如果我们可以转换数据,这样我们就可以画一条线来区分这两个类,会怎么样呢?
如果我们对两个输入特征向量求平方,就会发生这种情况。现在,一个线性模型将很容易对蓝点和红点进行分类。
然而,有时我们不知道我们应该使用哪种转换。实际上,找到最佳表示法并不是一个简单的问题。我们可以对数据进行多种转换。同样,它们中的每一个都可能产生不同的分类器(就性能而言)。
这个问题的一个解决方案是学习正确的转换。这被称为表示学习,这正是深度学习算法所做的。
神奇的是,我们不需要“猜测”哪种转换会产生数据的最佳表示。算法会解决的。
但是,请记住,无论是表示学习还是手工转换,模式都是相同的。我们需要以某种方式改变数据,以便它可以很容易地分离。
让我们退一步考虑一个更简单的问题。
我们将探索费希尔的线性判别式 (FLD)如何设法将多维数据分类到多个类别。但是在我们开始之前,请随意打开这个 Colab 笔记本并跟随。
费希尔线性判别式
看待分类问题的一种方式是通过降维的镜头。
首先,考虑两类分类问题的情况( K=2 )。蓝色和红色点在 R 。一般来说,我们可以取任意一个 D 维输入向量,并将其向下投影到 D '维。这里, D 表示原始输入尺寸,而**D’是投影空间尺寸。在整篇文章中,认为D’**小于 D 。
在投影到一维(数轴)的情况下,即D’= 1,我们可以选取一个阈值 t 在新的空间中进行分类。给定一个输入向量 x :
- 如果预测值 y > = t 则 x 属于 C1 类(类 1)。
- 否则,它被归类为 C2(2 类)。
注意向量 y (预测)等于输入 x 和权重w→y=wᵀx的线性组合
以下面的数据集为例。我们想把原来的数据维数从 D=2 减少到 D’=1 。换句话说,我们需要一个将二维向量映射到一维向量的变换 t—t(v)=ℝ→ℝ。
首先,让我们计算两个类的平均向量 m1 和 m2 。
注意, N1 和 N2 分别表示 C1 和 C2 班级的分数。现在,考虑使用类均值作为分离的度量。换句话说,我们希望将数据投影到加入 2 类平均值的向量 W 上。
值得注意的是,任何一种向更小维度的投影都可能会丢失一些信息。在这个场景中,请注意,这两个类在它们的原始空间中是明显可分的(通过一条线)。
但是,在重新投影后,数据会出现某种类别重叠,如图上的黄色椭圆和下面的直方图所示。
这就是费雪线性判别式发挥作用的地方。
Fisher 提出的想法是最大化一个函数,该函数将在投影的类均值之间给出一个大的分离,同时在每个类内给出一个小的方差,从而最小化类重叠。
换句话说,FLD 选择了最大化类别分离的投影。为此,它最大化类间方差与类内方差之比。
简而言之,为了将数据投影到一个更小的维度并避免类重叠,FLD 维护了两个属性。
- 数据集类之间的巨大差异。
- 每个数据集类中的微小差异。
请注意,较大的类间方差意味着预计的类平均值应尽可能远离。相反,小的类内方差具有保持投影数据点彼此更接近的效果。
为了找到具有以下属性的投影,FLD 用以下标准学习权重向量 W 。
如果我们替换等式(1)和(2)给出的平均向量 m1 和 m2 以及方差 s ,我们得到等式(3)。如果我们对(3)关于 W 求导(经过一些简化),我们得到 W 的学习方程(方程 4)。
即 W (我们期望的变换)正比于类内协方差矩阵的逆乘以类均值的差。
正如预期的那样,结果允许用简单的阈值进行完美的分类分离。
多类 Fisher 线性判别式
我们可以将 FLD 推广到超过 K 个类别的情况。这里,我们需要类别内和类别间协方差矩阵和的推广形式。****
对于类内协方差矩阵 SW ,对于每个类,取集中输入值与其转置值之间的矩阵乘法之和。等式 5 和 6。
为了估计类间协方差 SB ,对于每个类 k=1,2,3,…,K ,取局部类均值 mk 和全局类均值m的外积,然后乘以类 k 中记录的数量**—等式 7。**
FLD 准则的最大化通过矩阵的特征分解来解决,即 SW 的逆和 SB 之间的乘法。因此,为了找到权重向量 W ,我们取对应于其最大特征值的D’特征向量(等式 8)。
**换句话说,如果我们想要将我们的数据维数从 D=784 减少到 D’=2 ,那么变换向量 W 由对应于 D’=2 最大特征值的 2 个特征向量组成。这给出了 **W = (N,D’)的最终形状,其中 N 是输入记录的数量,而D’是减少的特征空间维度。
构建线性判别式
到目前为止,我们仅使用 Fisher 线性判别式作为降维方法。为了真正创建判别式,我们可以在 D 维输入向量 x 上为每个类别 K 建模一个多元高斯分布**,如下所示:**
这里 μ (平均值)是一个 D 维向量。σ(sigma)是一个 DxD 矩阵——协方差矩阵。并且|∑|是协方差的行列式。行列式是协方差矩阵σ拉伸或收缩空间的程度的度量。
在 Python 中,看起来是这样的。
高斯分布的参数: μ 和σ,****使用投影输入数据为每个类别 k=1,2,3,…,K 计算。我们可以使用每个类别中训练集数据点的分数来推断先验 P(Ck) 类别概率(第 11 行)。
一旦我们有了高斯参数和先验,我们就可以单独地为每个类 k=1,2,3,…,K 计算类条件密度P()x**| Ck】。为此,我们首先将 D 维输入向量 x 投影到一个新的D’空间。请记住D’<D。然后,我们对每个投影点评估等式 9。最后,我们可以利用等式 10 得到每类 k=1,2,3,…,K 的后验类概率P(Ck |x)。**
等式 10 在下面的得分函数的第 8 行进行评估。
然后,我们可以将输入向量 x 分配给具有最大后验概率的类别 k 。
对 MNIST 进行测试
使用 MNIST 作为玩具测试数据集。如果我们选择将原始输入尺寸 D=784 减少到 D’=2 ,我们可以获得大约 56% 的测试数据精度。然而,如果我们将投影空间尺寸增加到D’= 3*,我们将达到接近 74% 的精确度。这两个投影也使结果特征空间更容易可视化。***
这篇文章的一些要点。
- Fisher 的线性判别式,本质上是一种降维的技术,而不是判别式。
- 对于二元分类,我们可以找到一个最优阈值 t 并据此对数据进行分类。
- 对于多类数据,我们可以(1)使用高斯分布对类条件分布建模。(2)求先验类概率P(Ck),( 3)用贝叶斯求后验类概率 p(Ck|x) 。**
- 为了找到投影输入数据的最佳方向,Fisher 需要监督数据。
- 给定一个维度为 D 的数据集,我们最多可以将它向下投影到*D’等于 D-1 维度。***
本文基于模式识别与机器学习的第 4.1 章。克里斯托弗·毕晓普的书。****
感谢阅读。
用 CNN 分类图像
深度学习和机器学习模型与图像分类器的比较
Photo credit: Aaron Huber
让年幼的孩子整理他们的房间通常是具有挑战性的。我坚持的是脏乱,他们会坚持的是足够干净。毕竟,所有的形容词都是主观的,我希望我的孩子在我们包容的社会中尊重他人的意见。你如何定义不同的观点?实现这种区分的客观方法是使用图像分类来区分干净的房间和脏乱的房间。
这个应用程序还可以扩展到清洁服务机构或 Airbnb,尤其是超过 10%的用户投诉与肮脏和混乱的条件有关。(参见来源)
流程
构建我的应用程序的过程包括 5 个阶段:1)网络搜集 2)数据集准备 3)模型构建 4)模型测试和 5)前端烧瓶应用程序。
1。抓取网页
没有我想要的大小的数据集,所以我不得不转向网络抓取(这就是生活!)用 google_images_download 上的关键词从 google 获取图片。
对于“干净”类别,使用了“干净的卧室”、“整洁的房间”、“酒店房间”、“干净整洁”和“整理”等词。
对于“凌乱”类别,所用的词包括“杂乱”、“混乱”和“杂乱无章的房间”。
我创建了第三个有趣的类别,以迎合我的孩子为了逃避家务而离开我的借口便条的快照。(是的,惯性实际上是从很小的时候开始的。)对于这个类别/类,我使用了像“孩子的手写笔记”、“情书”、“手写笔记”等词来抓取谷歌图片。
2。数据集准备
获得超过 3,000 张图像后,确保图像的正确性非常重要。在进入每一个类别时,我仔细查看了图片,删除了 I)冲突的图片,ii)前后对比的图片,iii)对培训没有帮助的重复图片,iv)清洁剂图片,v)卡通图片,vi)文字图片,vii)公司徽标。
这个数据集的彻底清理是必不可少的。记住这个原则:垃圾进,垃圾出。
一天下来,给我留下了 600 多张“乱”和“借口”,900 多张“干净”。
3。模型构建
从机器学习开始,我使用了 8 种不同的算法。
- k-最近邻
- 高斯朴素贝叶斯
- 逻辑回归
- 支持向量分类器
- 决策图表
- 多层感知器
- 随机森林
- XGBoost
使用 F1 分数作为所有模型的评估指标,XGBoost 以 0.76 的分数表现最佳。对于那些对技术感兴趣的人来说,我将在本文中用斜体来阐述它们。如果你只对结果感兴趣,你可以跳过它们。F1 是精确度和召回率之间的和谐平衡。I)精度是所有预测阳性(包括真阳性和假阳性)中的真阳性的比率,而 ii)召回是真阳性和假阴性中的真阳性的比率。
What is the F1 score? Widget Credit: Pavan Mirla
很想知道这是否可以以一种实质性的方式得到改善,让我们使用卷积神经网络(CNN)来探索深度学习,该网络以处理图像而闻名。
CNN Architecture. Credit: Public Library of Science Data Repository
CNN 架构由许多层组成。每一层将从每一类的训练图片中提取某些特征(例如,对比度、形状、边缘、纹理)。然后,将训练好的模型应用于看不见的图片,然后使用训练好的特征元素对这些图片进行分类。
Comparison of Models with F1 score
事实上,具有 Adam 优化器和早期停止的 CNN 模型是最好的模型,以与训练好的网络相关联的新的 0.84 F1 分数击败了 XGBoost。Adam 优化器的优越性在于其自适应的学习速率,并因其相对较少的参数调整而受到青睐。以下是我的模型代码和相关 F1 分数的分类报告。
# compile & train model
# initialize # of epochs to train for, and batch size
EPOCHS = 30
BS = 128# initialize the model and optimizer
model.compile(loss=”categorical_crossentropy”, optimizer=’adam’,metrics=[“accuracy”])# train the network
import keras
H = model.fit_generator(aug.flow(trainX, trainY, batch_size=BS),
validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS, epochs=EPOCHS,
# inject callbacks with best weights restoration
callbacks=[
keras.callbacks.EarlyStopping(patience=8, verbose=1, restore_best_weights=True),
keras.callbacks.ReduceLROnPlateau(factor=.5, patience=3, verbose=1),
])
Training and Validation accuracy with early stopping
Training and Validation loss with early stopping
Classification Report with F1 score of 0.84
“恢复最佳重量”确保模型将检索通过历元运行获得的最佳重量。
4。模型测试
用三张看不见的图片(每个班级一张)测试模型,结果如下:
Test result on an unseen excuse note image
Test result on an unseen clean room image
Test result on an unseen messy room image
更进一步说,即使我那些有创造力的孩子有一天在一张装饰过的纸上给我写了一张纸条,或者在他们的纸条上附上了一份“礼物”,这个模型仍然可以自信地把这些归类为借口。
5。前端应用
Flask App of the classifier
结论
图像分类是图像识别的一个子集,它广泛用于安全行业(面部识别)、虚拟搜索引擎(商店中的对象查找器)、医疗保健(患者的情绪检测)以及游戏和增强现实。在某种程度上,智能手机相机使所有这些进步成为可能,因为它可以轻松地创建大量图片。这个项目演示了图像分类在我们家中的应用:)
一种使用深度学习从卫星图像生成地面实况数据的图像处理工具
卫星图像的地面实况意味着在特定位置收集信息。它使卫星图像数据与地面的真实特征和材料相关联。这一信息经常用于遥感数据的校准,并将结果与地面实况进行比较。地面实况数据通常通过访问一个地点并进行一些实验来收集,如对该特定地点进行勘测,通过在不同方面进行表面观察来测量该地点的不同属性和特征,如森林、农业、水、建筑物和其他土地类别所覆盖的区域。地面真实在图像的初始监督分类中是重要的。这些数据通常用于评估卫星图像分类的性能,将图像的每个像素与相应的地面实况数据进行比较,以找到匹配。目标是最小化分割的卫星图像和地面实况信息之间的误差。目前,有许多软件和图像处理工具可以用来对卫星图像进行分类和分割,取得了很好的效果。然而,当特定地理位置的地面实况信息不可用时,问题就出现了。
不可能收集地球上所有位置的地面实况数据。因为有些地方如丘陵地带、密林等,不容易到达。人工收集地面实况信息需要大量的人力和时间。因此,卫星图像的应用,如聚类/分割/分类,仅限于地面实况信息。因此,有必要开发一些能够从卫星图像生成地面实况数据应用程序。
在本文中,我们的目标是开发一个使用深度学习技术的自动化系统,该系统可以从卫星图像本身生成地面真实数据。它不仅减少了收集这些信息所需的时间和精力,而且还生成了手动数据收集不可能得到的地理位置数据。
**数据库:**由于没有与卫星图像相对应的地面实况图像,在本研究中,我们使用卫星图像和相应的谷歌地图图像来训练一个模型。这个数据集包含纽约州的卫星图像和相应的谷歌地图图像,分为训练集和测试集,分别包含 1096 和 1098 个图像样本。因此,在本实验中,我们从给定的卫星图像中生成 google map 图像作为地面真实数据。图 1 显示了一个样本卫星,它的 google map 图像用于训练模型。
Figure 1: A sample satellite and it’s ground truth (google map) image.
生成对抗网络
按照这篇文章中提出的 PixtoPix GAN 架构,我们用 1096 幅卫星图像训练我们的模型。每个图像样本都带有卫星数据和相应的谷歌地图,它们被分组到源和目标列表中。GAN 的结构由两个模块组成:鉴别器和发生器。鉴别器是执行分类的卷积神经网络模型。生成器是一个使用 U-Net 架构的编码器-解码器模型。它将源图像(卫星图像)作为输入,并生成目标图像(谷歌地图图像)作为输出。生成器模型通过将图像向下采样到某个级别来编码图像,并通过使用 U-Net 架构向上采样到图像的原始大小来解码图像。点击此处了解更多关于 GAN 的详细信息。
Figure 2: Block diagram of training of GAN
由发生器模型产生的目标图像被作为鉴别器模型的输入。鉴别器模型还获取原始地面真实图像(谷歌地图图像),并预测目标图像是真实图像还是源图像的虚假翻译的可能性。发生器和鉴别器模型的框图如图 2 所示。使用 GAN 架构,我们用 30 个历元训练模型,得到训练好的模型需要大约 24 小时。
结果
结果,我们得到了卫星图像到谷歌地图图像的过渡。该系统产生给定卫星图像、相应的谷歌地图图像和预期/生成的谷歌地图图像的输出,这些图像可以被视觉分析相似性。在测试集上评估模型时的输出示例如图 3 和图 4 所示。
Figure 3: Generated ground truth image by model
Figure 4: Generated ground truth image by model
结论和未来工作
所提出的系统将卫星图像映射到其谷歌地图上,这可以被认为是地面事实。因此,它大大减少了手动收集地面实况信息所需的时间和精力。此外,开发的模型可以很容易地生成难以收集这些信息的地理位置。
所提出的模型可以扩展到从地面真实数据生成卫星图像,这可以帮助科学家更容易地研究环境变化。模型的性能可以通过用更多的历元数进一步训练来提高。
挑战挑战
1。GAN 需要大量时间和资源来训练模型。
运行“trainModel.py”从草图训练模型。若要测试生成的模型,请运行“testDBimage.py”。它将从数据库中读取测试图像,并生成预期的地面真相。你也可以从谷歌下载随机卫星图像,并使用“test_random_image.py”进行测试
感谢杰森·布朗利的精彩教程和文章,帮助我学到了很多。大部分代码都是为了他的教程。这个项目的完整代码在我的 GitHub 库中。可以随意下载修改。谢谢你的时间。祝你愉快。😃
参考文献