变量类型和示例
通过具体的例子学习定量连续变量、定量离散变量、定性序数变量和定性名义变量之间的区别
特种宽银幕电影
在统计学中,变量分为 4 种不同的类型:
Types of variables
数量的
一个数量变量是一个反映大小概念的变量,也就是说,如果它可以取的值是数字。因此,数量变量代表一种度量,并且是数字的。
定量变量分为两种:离散和连续。这种差异将在以下两节中解释。
分离的
定量离散变量是其取值为可数且有有限个可能性的变量。这些值通常(但不总是)是整数。以下是一些离散变量的例子:
- 每个家庭的孩子数量
- 一个班的学生人数
- 一个国家的公民人数
即使统计一个大国的公民人数需要很长时间,但在技术上还是可行的。而且,对于所有的例子,可能性的数量都是有限的。无论一个家庭有多少个孩子,都不会是 3.58 或 7.912,所以可能性的数量是有限的,因此是可数的。
连续的
另一方面,定量连续变量是其值不可数并具有无限种可能性的变量。例如:
- 年龄
- 重量
- 高度
为了简单起见,我们通常用年、千克(或磅)和厘米(或英尺和英寸)分别代表年龄、体重和身高。然而,一个 28 岁的男人实际上可能是 28 岁 7 个月 16 天 3 小时 4 分 5 秒 31 毫秒 9 纳秒。
对于所有的测量,我们通常在一个标准的粒度级别停止,但是没有什么(除了我们的测量工具)阻止我们更深入,导致无限数量的潜在值。事实上,值可以采取无限多的可能性,使它不可数。
定性的
与定量变量相反,定性变量(也称为分类变量或 R 中的因子)是而非数值的变量,其值属于类别。
换句话说,一个定性变量是一个以模态、类别甚至水平为其取值的变量,与测量每个个体的数量的定量变量相反。
定性变量分为两种:标称和序数。
名义上的
定性标称变量是一个定性变量,其中不可能排序或在等级中没有暗示。例如,变量性别是名义上的,因为在女性/男性级别中没有顺序。眼睛颜色是名义变量的另一个例子,因为蓝色、棕色或绿色眼睛之间没有顺序。
一个名义变量可以有两个级别(例如,你吸烟吗?是/否或者你的性别是什么?女/男)和一大批水平(你大学专业是什么?每个专业在那种情况下都是一个级别)。
序数
另一方面,定性序数变量是具有隐含在等级中的顺序的定性变量。例如,如果道路交通事故的严重程度是按轻度、中度和致命事故的等级来衡量的,那么这个变量就是一个定性的顺序变量,因为在等级中有一个明确的顺序。
另一个很好的例子是健康,它可以取值为差、合理、好或优秀。同样,这些级别有明确的顺序,所以在这种情况下,健康是一个定性的序数变量。
变量转换
有两种主要的变量转换:
- 从连续变量到离散变量
- 从量变到质变
从连续到离散
假设我们对婴儿的年龄感兴趣。收集的数据是婴儿的年龄,因此是一个定量的连续变量。然而,我们可能只处理出生后的周数,从而将年龄转换为离散变量。年龄变量仍然是一个定量的连续变量,但我们正在研究的变量(即出生后的周数)是一个定量的离散变量。
从量变到质变
假设我们对身体质量指数(身体质量指数)感兴趣。为此,研究人员收集了个人身高和体重的数据,并计算出身体质量指数。身体质量指数是一个定量的连续变量,但研究人员可能希望将其转化为定性变量,方法是将低于某个阈值的人归类为体重不足,高于某个阈值的人归类为超重,其余的人归类为正常体重。原始身体质量指数是一个定量的连续变量,但身体质量指数的分类使转换变量成为一个定性(顺序)变量,在这种情况下,其水平为体重不足
当年龄被转换成一个定性的顺序变量时,年龄也是如此,包括未成年人、成年人和老年人。通常情况下(尤其是在调查中),可变工资(定量连续)被转换为具有不同工资范围的定性有序变量(例如,< 1000€, 1000–2000€, > 2000€)。
附加注释
不同类型的变量用于不同类型的统计分析
我们经常将变量分为不同类型的原因是因为不是所有的统计分析都可以在所有的变量类型上进行。例如,不可能计算变量“头发颜色”的平均值,因为你不能将棕色和金色头发相加。
另一方面,寻找连续变量的模式实际上没有任何意义,因为大多数时候不会有两个完全相同的值,所以没有模式。即使在有一个模式的情况下,这个值的观测值也很少。举个例子,试着找出你们班学生身高的模式。如果你幸运的话,几个学生会有同样的尺寸。然而,大多数时候,每个学生都有不同的尺寸(特别是如果身高是以毫米为单位的话),因此没有模式。要查看每种类型变量的可能分析,请参阅文章“手工描述性统计”和“R中的描述性统计”中的更多详细信息。
类似地,一些统计测试只能在特定类型的变量上进行。例如,相关性只能对定量变量进行计算,而独立性卡方检验是对定性变量进行的,而学生 t 检验或方差分析需要混合定量和定性变量。
误导性数据编码
最后但并非最不重要的是,在数据集中,数字经常用于定性变量。例如,研究人员可能会将数字“1”分配给女性,将数字“2”分配给男性(或者将答案“否”分配为“0”,将答案“是”分配为“1”)。尽管进行了数字分类,性别变量仍然是一个定性变量,而不是看上去的离散变量。数字分类仅用于方便数据收集和数据管理。写数字“1”或“2”确实比写“女性”或“男性”更容易,因此不容易出现编码错误。
如果您面临这种设置,不要忘记在执行任何统计分析之前将变量转换成正确的类型。通常,在主要统计分析之前,一个基本的描述性分析(以及关于已测量变量的知识)足以检查所有变量类型是否正确。
感谢阅读。我希望这篇文章能帮助你理解不同类型的变量。如果您想了解 R 中不同数据类型的更多信息,请阅读文章“R中的数据类型”。
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章
- 我的数据符合正态分布吗?关于最广泛使用的分布以及如何检验 R 中的正态性的注释
- 手工卡方独立性检验
- R 中的描述性统计
- 手工描述性统计
- 总体和样本有什么区别?
原载于 2019 年 12 月 30 日【https://statsandr.com】。
金融中的变分自动编码器
金融时间序列的降维与指数构建
本文通过 Keras 和 Python 探讨了使用可变自动编码器来降低金融时间序列的维数。我们将进一步检测不同市场中金融工具之间的相似性,并将使用获得的结果来构建自定义指数。
**免责声明:**本文介绍的研究来自我们在多伦多大学继续教育学院的深度学习课程的 2019 年冬季学期项目。这是与温贝托·里贝罗·德·索萨合作完成的。概念和想法是我们自己的。我们绝不代表我们现在或以前的雇主。
第 1 部分:使用变分自动编码器降维
在本节中,我们将讨论:
- 创建几何移动平均数据集
- 用随机模拟扩充数据
- 建立变分自动编码器模型
- 获得预测。
创建几何移动平均数据集
为了比较不同价格范围的时间序列,我们选择计算收益的几何移动平均时间序列,定义如下:
我们选择了 d=5 ,因为它代表了 5 个工作日的典型交易周。
本文使用的数据集包含 2016 年 1 月 4 日至 2019 年 3 月 1 日期间的 423 个几何移动平均时间序列。
读者可以按照数据处理笔记本中描述的步骤构建自己的数据集。应该和这个差不多:
可以通过绘制一些样本股票价格时间序列及其几何移动平均线来验证结果:
然后,可以将刚刚构建的数据帧分成两个长度相等的时间段,只将第一个时间段的数据帧进行置换。周期 1 从 2016 年 1 月 12 日到 2017 年 8 月 4 日。周期 2,从 2017 年 8 月 7 日至 2019 年 3 月 1 日。
我们将仅使用周期 1 的数据来获得预测。
# Divide in two
geoMA_5d_stocks_p1 = geoMA_5d_stocks.head(int(len(geoMA_5d_stocks)/2))
geoMA_5d_stocks_p2 = geoMA_5d_stocks.tail(int(len(geoMA_5d_stocks)/2))# Transpose the dataframe for period 1
geoMA_5d_stocks_p1_T = geoMA_5d_stocks_p1.T
我们转置数据帧,以便每行代表给定股票的时间序列:
用随机模拟增加数据
我们将使用随机模拟来生成合成的几何移动平均线。目标不是精确地模拟回报,而是获得与真实数据行为相似的曲线。通过仅用模拟曲线训练模型,我们可以保留真实数据来获得预测。
使用几何布朗运动生成合成曲线。我们遵循以下步骤:
- 使用第一期数据框架,随机选择 100 个分笔成交点
- 对于每个选定的报价器,计算一个对数回报向量,如下所示:
- 然后,对于选择的每个股票,我们将生成 100 条路径,这样:
以下是模拟曲线和真实曲线的示例:
我们将 423 个时间序列的数据集扩展为 100*100 = 10,000 个与股票数据集相似(但不相等)的新时间序列。
这将允许我们保留实际的股票数据集用于预测,甚至不必使用它进行验证。
在建立 VAE 模型之前,创建训练集和测试集(使用 80%-20%的比率):
# Shuffle the generated curves
shuffled_array = np.random.permutation(sim_paths_matrix)# Split the simulated time series into a training and test set
x_train = shuffled_array[0:8000]
x_test = shuffled_array[8000:]
读者还应该注意,在训练模型之前,不需要删除时间序列的季节性和趋势。
建立变分自动编码器(VAE)模型
我们将使用变分自动编码器将具有 388 个项目的时间序列向量的维度降低到二维点。
自动编码器是用于压缩数据的无监督算法。它们由一个编码器、一个解码器和一个损失函数构成,以测量压缩和解压缩数据表示之间的信息损失。
我们的目标不是再写一篇关于 autoencoder 的文章。不熟悉自动编码器的读者可以在 Keras 博客和 自动编码变分贝叶斯论文上阅读更多,作者是 Diederik Kingma 和 Max Welling。
我们将使用一个简单的 VAE 架构,类似于 Keras 博客中描述的架构。
编码器型号具有:
- 一个长度为 388 的输入向量
- 一个长度为 300 的中间层,具有整流线性单元(ReLu)激活功能
- 一个二维编码器。
Encoder Model Summary
解码后的模型具有:
- 一个二维输入向量(从潜在变量中取样)
- 一个长度为 300 的中间层,具有整流线性单元(ReLu)激活功能
- 具有 sigmoid 激活函数的长度为 388 的解码向量。
Decoder Model Summary
以下代码改编自 Keras team Github 上的variable _ auto encoder . py。它用于构建和训练 VAE 模型。
训练后,我们绘制训练和验证损失曲线:
获得预测
我们将只使用编码器来获得预测。我们将使用一个实值矩阵,包括股票数据集和一个或多个感兴趣的时间序列。
在我们的项目中,我们针对在另一个国家以不同货币上市的近月期货合约测试了一个股票数据集。
# Obtaining the predictions:
encoded_p1 = encoder.predict(matrix_to_test_p1, batch_size=batch_size)# Convert the predictions into a dataframe
encoded_p1_df = pd.DataFrame(data = encoded_p1, columns = ['x','y'], index = dataframe_to_test_p1.T.index)
我们获得了以下结果:
在绘制结果之前,我们必须:
- 计算期货合约点和数据框架中所有其他股票之间的距离
- 选择最接近期货合约的 50 品脱
# Calculate the distances between the futures contract point and all other points in the stocks datasetref_point = encoded_p1_df.loc['Futures'].values
encoded_p1_df['Distance'] = scipy.spatial.distance.cdist([ref_point], encoded_p1_df, metric='euclidean')[0]# Get the 50 closest points:
closest_points = encoded_p1_df.sort_values('Distance', ascending = True)
closest_points_top50 = closest_points.head(51)[1:] #We take head(51), because the Futures reference point is the first entry
closest_points_top50['Ticker'] = closest_points_top50.index
现在,我们可以绘制所获得的结果,以直观显示最接近的 50 只股票:
我们已经对另一个国家上市的期货合约进行了分析。然而,对于来自同一交易所的股票,可以遵循第 1 部分中的相同步骤。
第 2 部分:索引构建
让我们使用第 1 部分中获得的结果来创建一个索引。
由于 VAE 模型的随机性,我们不会在每次运行中获得相同的前 50 名股票的精确列表。为了获得最接近的 50 个点的公平表示,我们将运行 VAE 模型 10 次(每次运行时重新初始化和重新训练它)。然后,我们将采用每次运行中找到的 50 个最近点来创建长度为 500 的数据帧closest _ points _ df。
一旦建立了 最近点 _df 数据帧:
- 按距离对点进行排序
- 丢弃重复的代码,只保留第一个出现的代码
sorted_by_dist = results_df.sort_values('Distance', ascending = True)sorted_by_dist.drop_duplicates(subset='Ticker', keep='first', inplace = True)
删除重复的点后,我们将只保留 50 个最接近的点。
计算每只股票的权重
在指数构建中,股票权重是通过使用不同的方法计算的,如市场资本总额或股票价格。
相反,我们将计算每只股票的权重,这样最接近期货合约点的点将比远离期货合约点的点获得更高的权重。
对于非匿名的股票数据,在计算股票权重之前过滤 **获得的结果非常重要。**离群值应剔除,市值范围应细化。
# Calculate the weights
top50 = sorted_by_dist.head(50).copy() # Keep the closest 50 points
top50['Weight'] = (1/top50['Distance'])/np.sum(1/top50['Distance'])
Sample of weights calculated
计算每只股票的股数
计算完权重后,我们计算每只股票在我们的自定义指数中的股份数。我们需要:
- 获取每只股票在 2016 年 1 月 4 日(周期 1 的第一天)的价格
- 定义净资产金额
- 计算股份的数量
#Get the stock prices on January 4th 2016jan4_2016_stockPrice = np.zeros(len(stock_data_top50.columns))
for i in range(len(jan4_2016_stockPrice)):
if stock_data_top50.columns[i] == top50['Ticker'].iloc[i]:
jan4_2016_stockPrice[i] = stock_data_top50[stock_data_top50.columns[i]].iloc[0]top50['Price Jan4_2016'] = jan4_2016_stockPrice
We add a column for the stock prices on January 4th, 2016
# We compute the number of sharesnet_assets = 10000000 # We chose net assets = 10 million (in the currency of the stock market)numShares = np.zeros(len(stock_data_top50.columns))
for i in range(len(jan4_2016_stockPrice)):
if stock_data_top50.columns[i] == top50['Ticker'].iloc[i]:
numShares[i] = int(net_assets*top50['Weight'].iloc[i]/top50['Price Jan4_2016'].iloc[i])
top50['numShares'] = numShares
We add a column for the number of shares
构建索引
为了构建该指数,我们将使用拉斯派尔斯指数计算如下:
stock_index = np.zeros(len(stock_data_top50))for i in range(len(stock_data_top50)):
sum_num = 0
sum_denom = 0
for j in range(len(stock_data_top50.columns)):
sum_num = sum_num + stock_data_top50[stock_data_top50.columns[j]].iloc[i]*top50['numShares'].iloc[j]
sum_denom = sum_denom + stock_data_top50[stock_data_top50.columns[j]].iloc[0]*top50['numShares'].iloc[j]
stock_index[i] = sum_num /sum_denom# We arbitrarily start the index at 100
stock_index_df = pd.DataFrame(stock_index*100, columns = ['stock_index'], index = stock_data_top50.index)
我们绘制了自定义索引:
比较我们的定制指数和期货时间序列
我们必须缩放期货价格数据,以便将其绘制在与自定义指数相同的图表中。为此,我们必须:
- 计算期货价格数据的每日百分比变化
- 设置 S_0 = 100
# Calculate the percentage change
futures_data_stock_data_pct_change = futures_data_stock_data.pct_change()
futures_data_stock_data_pct_change.dropna(inplace = True)# Scale the time series
futures_theoretical = np.zeros(len(stock_index_df))
futures_theoretical[0] = stock_index_df.iloc[0]
for i in range(len(futures_theoretical)-1):
futures_theoretical[i+1] = (1+futures_data_stock_data_pct_change.iloc[i])*futures_theoretical[i]
我们现在在同一张图中绘制两条曲线:
我们的指数除了 2018 年下半年之外,大部分趋势与参考期货时间序列相同。因为我们使用匿名数据,我们没有过滤股票的异常值和市值限制。此外,在观察到的两个时间段内没有重新平衡,我们忽略了分布。
如果识别出报价器并剔除异常值,自定义指数完全有可能跑赢期货指数。
我们鼓励我们的读者利用在线免费的 GPU 实例来创建他们自己的索引。这对我们来说是一个有趣的实验,我们发现了一些有趣的股票模式。
请随意下载 GitHub 上的两款笔记本:
结论
使用可变自动编码器可以加快外国股票市场新指数的开发,即使分析师对它们并不熟悉。此外,可以创建利基指数或投资组合来满足客户的兴趣。
虽然这种方法可以用来创建 ETF,但我们相信它也可以为全球的直接指数和 Robo Advisors 公司创造新的投资机会。
具有生成重放的变分连续学习
利用生成重放记忆进行持续学习的贝叶斯方法
介绍
这篇博客文章解释了由 Cuong V. Nguyen,Yingzhen Li,Thang D. Bui,Richard E. Turner 在 2018 年 ICLR 会议上发表的论文“不断变化的学习”中提出的方法。本文使用变分推理的贝叶斯方法来解决连续学习问题。在第二部分中,我们提出了 Y. Gal 和 S. Farquhar 提出的“变分生成重放”方法,扩展了第一篇文章。
1.持续学习模型旨在从输入的数据流中学习。数据不断到达,并且数据分布随时间而变化(非平稳性)。成功的持续学习可以处理两件事:
- 应该从根据先前数据训练的先前模型执行迁移学习,以训练最新的模型
- 避免灾难性的遗忘。即最终的模型在旧的任务上应该仍然表现良好。
2.贝叶斯方法是一种机器学习的概率方法,它将关于模型参数的先验知识形式化,并对模型权重的分布进行建模。
变分连续学习理论
一般来说,在机器学习中,根据概率将判别模型定义为:
其中 f 属于由θ参数化的一类函数。例如,前馈神经网络执行分类(softmax 作为最后一层,θ作为权重和偏差)。
经典的贝叶斯方法通过权重值的分布来对权重建模。它还使用贝叶斯规则来利用θ分布的先验信念。
在持续学习的框架中,一个自然的想法是将最后的后验概率视为新任务的θ的最佳先验分布(来自新分布的新一批数据)。事实上,我们注意到:
这是随时间推移的后验分布的递归公式。在前面的公式中,我们不关心通常难以处理的归一化因子的计算,因为我们要执行后验分布的近似。(因此有了比例符号)
在大多数情况下,后验分布是难以处理的。为了克服这个问题,我们可以用更简单的变分分布来近似后验分布
为了进行这种近似,我们考虑:
我们将通过一个更简单的分布来递归地近似后验概率:给定时间步长 t-1 的近似值,我们可以按照前面的公式计算时间步长 t 的近似值。这种方法叫做变分推理。我们正在寻找由一组参数(μVI,σVI)定义的近似分布(此处为高斯平均场),该分布与目标分布相匹配。通过拟合,我们意味着最小化两个分布之间的差异。通常,Kullback-Leibler 散度用于定义两个分布之间的差异。
Gaussian mean-field approximation
因此,为了找到近似的变分后验概率,我们最小化下面的 Kullback-Leibler 散度。
因此,我们将损失定义为:
KL 项可以解析地计算为两个高斯函数之间的 Kullback-Leibler 散度。利用蒙特卡罗方法和重新参数化技巧,我们可以很容易地估计出期望的对数似然性:
- 假设很难评估期望值 E =Ex∾p**【f(x)】**人们可以通过采样 x1,x2,…xN∞p 并得到 E 的近似值:
This estimator is unbiased but to reduce variance, it is better to use high N
- 从高斯分布中提取的θ的重新参数化技巧是独立于分布参数(μVI,σVI)重写θ的简单方法
因此,可以为可学习参数(μVI,σVI)计算损失函数的梯度,并且可以执行随机梯度下降。
为了在连续设置中改进学习,我们可以考虑多头架构。事实上,单头架构非常适合 i.i.d 实例或只有输入分布随时间变化的实例。多头架构能够利用任务之间的共享参数和为每个任务训练的特定头。
变分分布的递归近似可能影响模型性能,并触发灾难性遗忘。为了避免这种灾难性的遗忘,引入了核心集:训练数据的样本存储在核心集中(并从训练数据中移除),并用于在预测之前改进后验近似。可以选择不同的技术来选择训练批次的子集。随机抽样是最简单的选择。可以执行 k-均值聚类来保持训练数据的有意义的子集:质心被选择放入核心集中。理论上,我们注意到:
我们现在关注这个新的变分分布,它只在非核心集数据上训练。我们可以用类似的方式计算这些变分分布的递归公式:
事实上,在实现中,他们从不从核心集中删除任何点。因此,公式变得更简单:
有趣的是,与本文提出的理论相反,与本文相关的原始实现并不是在进行预测之前对整个核心集进行训练,而是只对与测试任务相对应的核心集子集进行训练。因此,这是一种最后一分钟的培训,在持续学习的框架内并不真正令人满意。
我们总结了变分连续学习算法:
变分生成重放
在之前的一篇论文《深度生成重放(DGR)》(Shin et al .,2017)中,作者以一种完全不同的方式解决了持续学习的问题。他们在每项任务上训练生成对抗网络(GAN ),以便能够使用生成的 GAN 输出来确保后一项符合前一项任务的对数似然性。这种思想,在接下来的段落中称为似然聚焦连续学习,可以集成到称为先验聚焦连续学习的变分连续学习中(因为它聚焦于先验变分近似)。这种混合方法在 S. Farquhar 和 Y. Gal 最近撰写的论文《连续学习的统一贝叶斯观点》[2019]中被称为变分生成重放。让我们回顾一下这些方法背后的理论:
以前为重点的持续学习:
这是在《不断变化的学习》一文中提出的方法。这种方法侧重于任务间的迁移学习,这要归功于先前对从先前任务中学习到的权重的信念。
它可以被解释为用概率分布加权的模型集合,该概率分布是从关于它的先验信念正则化的。时间步长 t 的先验置信是在时间步长 t-1 计算的后验置信。
注重可能性的持续学习:
这是深度生成重放(DGR)一文中提出的方法。这种方法试图确保后验概率符合所有以前看到的数据的可能性,使用以前任务中训练的 GANs 生成的数据。实际上,这个想法是要符合以下棘手的损失函数(因为我们不能直接访问以前看到的数据):
因此,进行了以下近似,为先前的任务引入了生成模型 pt′(x,y)
变化生成重放的连续学习;
这种方法是在《持续学习的统一贝叶斯观点》一文中发展起来的。它混合了以先验为重点的持续学习方法和以可能性为重点的持续学习方法:
基本上,变分生成重放在实现中取代了核心集,是一种新的记忆形式。
结论
总之,具有生成重放的变分连续学习是一种使用来自贝叶斯深度学习和生成对抗网络的工具来实现连续学习的新途径。它可以被看作是一种人类启发的方法,我们在以前的任务基础上建立的先验知识被用来执行新的任务。此外,深度生殖重播有时被比作梦,当人类提醒自己过去的行为以进一步学习时。然而,使用这种新方法,所需的内存随着任务的数量而线性增长,这对于一般的连续学习模型来说可能是不令人满意的。
代码可在https://github.com/pihey1995/VariationalContinualLearning获得
C.阮,李,裴东光,特纳。不断变化的学习。ICLR (2018 年)。
南法夸尔和 y .高尔。持续学习的统一贝叶斯观点(2019)。
韩 ul Shin、Jung Kwon Lee、Jaehong Kim、Jiwon Kim 深度生殖重播(DGR) (2017 年)
各种类型的卷积神经网络
该帖子将出现在 CNN 的各种类型上,在图像处理和物体识别的各个领域中成功设计并实现。如果你对卷积神经网络有所了解会更好。
你可能听说过 ImageNet 。这是一个大型的有组织的视觉图像数据库,供研究人员和开发人员用来训练他们的模型。现在,他们主办了一年一度的竞赛,名为 ImageNet 大规模视觉识别挑战赛(ILSVRC)——一场与大规模物体检测和图像分类相关的竞赛。一般来说,这场比赛中表现最好的选手能够在物体分类领域设定一个基准。这份各种建筑的列表,在他们的设计中是独一无二的,在这场竞赛中获得了最高的位置,并且正在成功地应用于各种任务中。
注意:除非另有说明,这些网络都实现了同填充,实质上保留了图像卷积后的原始大小。
让我们看看它们:
LeNet:
LeNet Architecture.
没有这一点,就不能开始讨论有线电视新闻网的架构。就对象分类而言,这是一个开创性的算法,是同类算法中的第一个,也是有能力的。最初接受 MNIST 数据集 0-9 手写数字分类的训练。它由 7 层组成,均由可训练参数组成。它采用 32 X 32 像素的图像,相对于训练网络的数据集内的图像,其尺寸相对较大。应用的激活功能为 RELU 功能。这些层按以下方式排列:
LeNet Architecture, but with more details.
- 第一卷积层由 6 个尺寸为5 X 5的滤波器和 1 个的步长组成。
- 第二层为尺寸 2×2的亚取样或平均汇集层,2 的步距。
- 第三层也是卷积层,由 16 个 5×5尺寸的滤波器和1 步长的滤波器组成。
- 第四层同样是平均汇集层的尺寸为 2×2和跨距为 2。
- 第五层将第四层 ( 400 参数)的输出连接到 120 节点的全连接层**。**
- 第六层是一个类似的全连接层,由 84 个节点组成,从第五层的 120 个节点的输出中导出。
- 第七层(,或最后一层)包括将最后一层的输出分类成 10 类,与它最初被训练分类的 10 位数字相关。
它是当时实现的对手写数字进行分类的成功的数字识别算法之一。今天,在数据集上实现这种架构,使用各种库,可以获得大约 98.9 %的准确率。然而,当涉及到处理大尺寸图像和在大量类别的对象中进行分类时,该网络在计算成本或准确性方面不能有效地工作。
AlexNet:
AlexNet Architecture
ImageNet ILSVRC-2012 竞赛的获胜者 AlexNet 由 Alex Krizhevsky、Ilya Sutskever 和 Geoffery E. Hinton 设计。它能够将前五名的错误率降低到 15.3 %** ,而该比赛亚军的错误率为 26.2%。该网络类似于 LeNet 架构,但与原始 LeNet 相比具有大量过滤器,因此能够在一大类对象中进行分类。此外,它使用“退出”而不是正则化来处理过度拟合。(退出实质上减少了在训练/学习过程中要考虑的参数数量的大小)。简而言之,让我们来定义这些层。**
它输入一个尺寸为 224 X 224 的颜色 (RGB) 图像。
- 首先,尺寸为 11×11 且步距为 4 的 96 个滤波器的卷积层(CL)** 。**
- 接下来,一个 Max-Pooling Layer (M-PL) 的过滤器大小为 3 X 3,跨距= 2。
- 同样,256 的一个 CL 过滤大小为 5×5 且跨距= 4 的**。**
- 然后,一个 M-PL 的滤镜大小为 3×3,步幅= 2。
- 同样,384 个尺寸为 3×3 且跨距= 4 的滤波器的 CL。
- 同样,384 个尺寸为 3×3 且跨距= 4 的滤波器的 CL。
- 同样,256 个大小为 3×3 且跨距= 4 的滤波器的 CL。
- 然后,滤波器大小为 3×3 并且跨距= 2 的一个 M-Pl。
- 当最后一层的输出被转换成输入层时,像对于由 9261 个节点组成的全连接块一样, 全连接到具有 4096 个节点的隐藏层。
- 第一隐藏层再次 完全连接到由 4096 个节点组成的另一隐藏层。
- 最后一个隐藏层 完全连接到输出层,实现 1000 个节点的“softmax 回归”。
现在,我所写的可能看起来与第一张图片(原始图片)中所示的架构大相径庭。仔细查看,对于两个管道(或两个部分),在每个块输出中添加它们的通道号,并查看它是否与描述相匹配。造成这种差异的原因是 AlexNet 同时在两个 Nvidia GeForce GTX 580 GPU上进行训练,导致了架构的这两条流水线。
这个网络有6230 万个参数,需要十亿个计算单元。这种巨大的计算成本导致在多个 GPU 上同时训练该架构以加速该过程。最初的网络只在两个 GPU 上训练。
他们从网络中获得的一个有趣的结果是在分析了来自两个 GPU 的第一个卷积块的滤波器之后。他们发现,一个生成高频灰度特征,另一个生成低频颜色特征。
Visualization of few layers at the beginning of the AlexNet model.
VGGNet 16:
这个特殊的网络架构是由 Simonyan 和 Zisserman 设计的 ILSVRC-2014 竞赛的亚军。很容易达到 5.1% 的前五名错误率。虽然这看起来很复杂,需要考虑一大堆参数,但实际上非常简单。当谈到特征提取时,开发人员非常喜欢它,因为它遵循简单的模式。关于卷积层和汇集层的过滤器尺寸和步距的基本超参数是恒定的:卷积层具有尺寸为 3×3的过滤器和步距= 1** ,而最大汇集层具有尺寸为 2×2的过滤器和步距= 2 。这些层以特定的顺序应用于整个网络。只有为每个卷积块定义的滤波器数量不同。让我们来看看:**
The VGG16 Network Architecture.
它接收 224 X 224 尺寸的彩色(RGB)图像。
- 64 个滤波器的卷积层(CL)。
- CL 64 的再次过滤。
- 最大池层(M-PL)
- 128 个过滤器的 CL。
- CL 128 的再次过滤。
- M-PL。
- 256 个过滤器的 CL。
- CL 256 的再次过滤。
- CL 256 的再次过滤。
- M-PL。
- CL 512 过滤器。
- CL 512 的再次过滤。
- CL 512 的再次过滤。
- M-PL。
- CL 512 过滤器。
- CL 512 的再次过滤。
- CL 512 的再次过滤。
- M-PL。
- 最后一个池层的输出被送入由 4096 个节点组成的 全连接隐藏层。
- 这是再次完全连接到另一个同样由 4096 个节点组成的隐藏层。
- 这是 f 完全连接到实现“softmax 回归”的输出层,在 1000 类对象中分类。
那有很多层。因此,它有将近 1 . 4 亿个参数需要处理,这使得实现这个网络的任务充满挑战。然而,预先训练的 VGGNet 的权重很容易获得,并且可以由开发人员在他们的项目中使用。
GoogleNet / Inception:
Inception Network Architecture
GoogleNet 或盗梦空间网络是 ILSVRC 2014 竞赛的冠军,取得了 6.67% 的前五名错误率,几乎等同于人类水平的表现,太棒了!该模型由谷歌开发,包括原始 LeNet 架构的一个更智能的实现。这是基于先启模块的思想。
这些模块背后的基本思想是,我们不是在不同的层中实现各种超参数的卷积层,而是一起进行所有的卷积,以输出包含来自所有滤波器操作的矩阵的结果。这是一个简单 inception 模块的图像,其中各种卷积层一起实现:
The Inception module.
级联输出由所有卷积运算的结果组成。请注意,实现了一个包含大小为 1 X 1 的滤波器的卷积层。这减小了图像的大小,在该图像上应用了包含大小为 5×5 的滤波器的另一个卷积层。这背后的原因是,计算单元的总数在很大程度上减少了。
比如,当一只 Conv。32 层大小为 5×5 的滤波器被应用于某层的输出矩阵,其尺寸为 28×28×192。因此,总计算次数为28×28×32(输出矩阵大小)* 5×5×192(权重矩阵大小)****= 1.2 亿(接近)。
而若一个 Conv。在实施 Conv 之前,首先应用大小为 1 X 1 的 16 个过滤器层。大小为 5×5 的 32 个滤波器的层,矩阵的大小减小到28×28×16**,然后进行第二次卷积。
因此总计算次数= {28×28×16(第一 conv 层的输出) 1×1×192(第一 conv 层的权重矩阵的大小)}+{28×28×32(第二 conv 层的输出) 5×5×16(第二 conv 层的权重矩阵的大小)}
=240 万+1000 万(接近)因此,总成本降低了。
上面显示的 inception 模块(图片很难查看,但是相信我,我没有发现更好的图片可以有更清晰的细节),是这个网络的构建模块。仔细看看盗梦空间网络图像。这是一个由许多块开始块组成的堆栈,在一些块之间有一些 Max-Pooling 层来改变图像的尺寸。最后一层是全连接网络层,后面是**“soft max 回归”,用于输出层中的分类。
ResNets:
A 34-layer deep ResNet Architecture
大概是在 AlexNet 之后,CNN 架构开发领域最具开创性的发展发生在 ResNet 或者残余网络身上。这是基于“跳过连接”的思想,并实现了重批量标准化**,这有助于它有效地训练数千层,而不会降低长期性能。随着对更深层次网络的训练,问题出现了。**“消失梯度”的问题,当梯度被反向传播时,重复的乘法操作使得梯度无限小。这导致性能下降。(看一看反向传播和梯度下降,以便清楚地了解在训练阶段实际发生了什么。)
这个架构中注入的思想是“身份快捷连接”,这意味着将一些层的结果转移到一些更深的层,跳过中间的一些其他层。这张图片可能有助于你理解这个想法:
The skip-connection in ResNet models.
其背后的直觉是,较深的层不应该比其较浅的对应层产生更高的训练错误。跳过连接就是为了实现这个想法。该网络的开发人员实现了残差块的预激活变体,其中梯度可以通过快捷方式连接到早期层,从而减少“消失梯度”问题。希望这个图像能够解释它自己。这个 1001 层深度 ResNet 实现了3.57%的前 5 名错误率,在数据集上实际上击败了人类水平的性能。尽管它有很深的网络,但它提供了比大多数 VGGNet 架构更好的性能。它囊括了 2015 年 ILSVRC 在分类、检测和定位领域的所有奖项**。**
希望你喜欢读它。请评论,如果有任何错误或错误的信息从我这边提供。欢迎任何形式的建议。
长命百岁,编码。
基于 VAR & VECM 的时间序列分析:统计方法
股票市场数据的案例研究
时间序列随机数据建模
Image by author
https://sarit-maitra.medium.com/membership
V ECTOR 自回归(VAR)集成模型包含多个时间序列,是一种非常有用的预测工具。它可以被认为是自回归(ARIMA 的 AR 部分)模型的延伸。VAR 模型涉及多个独立变量,因此有多个方程。每个方程使用所有变量的滞后和可能的确定性趋势作为解释变量。VAR 的时间序列模型通常是基于将 VAR 应用于平稳序列,并对原始序列进行一阶差分,因此,总有可能丢失关于积分序列之间关系的信息。
因此,对序列进行差分以使其稳定是一种解决方案,但代价是忽略了级别之间可能重要的(“长期”)关系。一个更好的解决方案是检验回归水平是否可信。)通常的做法是用 Johansen 的方法来检验是否存在协整。如果答案为“是”,则可以估计结合了级别和差异的***【VECM】***向量误差校正模型,而不是级别中的 VAR。因此,我们将检查 VECM 是否能够超越我们现有系列的 VAR。
这是我以前发表的 文章 的延伸。
加载所有数据集(黄金、白银和原油)
经过必要的清理和预处理(用以前的值填充丢失的值),我们最终有了三个时间序列用于必要的分析。
快速测试是检查数据是否是随机的。随机数据在滞后图上不会显示出结构。
时间序列图清楚地表明了序列之间的某种关系。滞后曲线的线性形状表明 ar 模型是更好的选择。我们也没有在数据中看到任何异常值。这里的数据显示线性模式,表明正自相关的存在。
经济数据的时间序列通常是随机的,或者具有不稳定的趋势,这意味着数据有一个根单位
# plots the autocorrelation plots at 75 lags
for i in dataset:
plot_acf(dataset[i], lags = 50)
plt.title(‘ACF for %s’ % i)
plt.show()
平稳性检查
def augmented_dickey_fuller_statistics(time_series):
result = adfuller(time_series.values)
print('ADF Statistic: %f' % result[0])
print('p-value: %f' % result[1])
print('Critical Values:')
for key, value in result[4].items():
print('\t%s: %.3f' % (key, value))
通过上面的函数,我们可以对所有列进行增广的 Dickey Fuller (ADF)检验,这清楚地表明原始序列是非平稳的并且包含单位根。
print('Augmented Dickey-Fuller Test: Gold Price Time Series')
augmented_dickey_fuller_statistics(X_train['Gold'])
print('Augmented Dickey-Fuller Test: Silver Price Time Series')
augmented_dickey_fuller_statistics(X_train['Silver'])print('Augmente
d Dickey-Fuller Test: Oil Price Time Series')
augmented_dickey_fuller_statistics(X_train['Oil'])
向量自回归模型
VAR 模型还可以用来分析使用格兰杰因果关系检验所涉及的变量之间的关系。格兰杰因果关系表明,如果 y1t 中的信息有助于改善 y2t 的预测,则变量 y1t 是变量 y2t 的因果关系。
格兰杰因果检验试图确定一个变量(x1)是否可以作为另一个变量(x2)的预测值,而另一个变量的过去值可能有帮助,也可能没有帮助。这意味着 x1 的解释超越了 x2 过去的值。这里有两个重要的假设-
- x1 和 x2 都是静止的
- 它们的当前值和过去值之间存在线性关系。
这意味着,如果 x1 和 x2 是非平稳的,我们必须在检验格兰杰因果关系之前使它们平稳。
将序列拆分为训练和测试数据
我们将在 X_train 上拟合 VAR 模型,以预测接下来的 10 个观测值。这些预测将与测试数据(X_test)中的实际值进行比较。我们将使用多种预测准确性指标。
级数变换
差分变换是从时间序列中去除系统结构的一种简单方法。我们将通过从序列中的每个值减去前一个值来移除趋势,这是一阶差分。为了简单起见,我们将做一阶差分或季节差分。
如果我们对 n 个时间序列进行积分排序,并且如果我们对差值和时间进行一次排序,我们将得到 0 个序列积分排序。
X_train_log = np.log(X_train)
X_train_log_diff =(X_train_log).diff().dropna()
X_train_log_diff.describe()
查看该图,我们可以发现数据集看起来是标准化的
变换序列的自相关函数分析
下面的函数绘制了每只股票的价格与前一个交易日的价格相差 75°的自相关图。
fig, ax = plt.subplots(1,2, figsize=(10,5))
ax[0] = plot_acf(X_train_log_diff['Gold'], ax=ax[0])
ax[1] = plot_pacf(X_train_log_diff['Gold'], ax=ax[1])
我们已经展示了 ACF & PACF 的变形金系列;同样,也可以绘制其他系列。
ADF 测试转换系列
print('Augmented Dickey-Fuller Test: Gold Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Gold'])
print('Augmented Dickey-Fuller Test: Silver Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Silver'])
print('Augmented Dickey-Fuller Test: Oil Price Time Series')
augmented_dickey_fuller_statistics(X_train_log_diff['Oil'])
Augmented Dickey-Fuller Test on "Oil"
格兰杰因果检验
格兰杰因果检验用于确定一个时间序列是否有助于预测另一个时间序列。如果通常通过对 X 的滞后值(也包括 Y 的滞后值)的一系列 t-检验和 f 检验可以表明,那些 X 值提供了关于 Y 的未来值的统计上有意义的信息,则称时间序列 X 为格兰杰原因 Y 。
多变量分析
这里,对于多变量格兰杰因果关系分析,通过对时间序列拟合一个 VAR 来进行。考虑下面是一个 d 维多元时间序列—
格兰杰因果关系是通过拟合具有 L 个时滞的风险值模型来实现的,如下所示:
其中ε ( t)是白高斯随机向量,τ是每个τ的矩阵。一个时间序列 X i 称为另一个时间序列 Xi 的格兰杰原因,如果τ = 1,…,L 中至少有一个元素 A τ ( j,I)显著大于零。
print(grangercausalitytests(X_train_log_diff[['Gold','Silver']], maxlag=15, addconst=True, verbose=True))
print(grangercausalitytests(X_train_log_diff[['Gold','Oil']], maxlag=15, addconst=True, verbose=True))
print(grangercausalitytests(X_train_log_diff[['Oil','Silver']], maxlag=15, addconst=True, verbose=True))
下面显示了黄金和石油的产量,这与滞后 4 之前的测试假设不同。
VAR§过程的基本形式是:
这里 yt 表示一个向量中收集的一组变量,c 表示一个常数向量,a 是自回归系数矩阵, e t 是白噪声。由于 a 的参数是未知的,我们必须估计这些参数。模型中的每个变量都有一个方程。每个变量的当前(时间 t )观察值取决于其自身的滞后值以及 VAR 中每个其他变量的滞后值。
滞后订单选择
我已经通过 VAR §实现了 Akaike 的信息标准(AIC ),以确定滞后订单值。在 fit 函数中,我已经传递了最大数量的滞后和用于订单选择的订单标准。
#Initiate VAR model
model = VAR(endog=X_train_log_diff)
res = model.select_order(15)
res.summary()
#Fit to a VAR model
model_fit = model.fit(maxlags=3)
#Print a summary of the model results
model_fit.summary()
预测 VAR 模型
预测是根据模型使用的训练数据生成的。
# Get the lag order
lag_order = model_fit.k_ar
print(lag_order)# Input data for forecasting
input_data = X_train_log_diff.values[-lag_order:]
print(input_data)# forecasting
pred = model_fit.forecast(y=input_data, steps=nobs)
pred = (pd.DataFrame(pred, index=X_test.index, columns=X_test.columns + '_pred'))
print(pred)
逆变换
因此,要将其恢复到原始比例,我们需要对原始输入数据进行去差分。我们的数据是第一次对数转换,然后差分。因此,为了求逆,我们必须首先使用累积和去微分,然后使用指数。自然对数是 exp()的倒数。
# inverting transformation
def invert_transformation(X_train, pred_df):
forecast = pred.copy()
columns = X_train.columns
for col in columns:
forecast[str(col)+'_pred'] = X_train[col].iloc[-1] + forecast[str(col) +'_pred'].cumsum()
return forecastoutput = invert_transformation(X_train, pred)
print(output)output_original = np.exp(output)
print(output_original)
VAR 预测评估
#Calculate forecast bias
forecast_errors = [X_test['Oil'][i]- output_original['Oil_pred'][i] for i in range(len(X_test['Oil']))]
bias = sum(forecast_errors) * 1.0/len(X_test['Oil'])
print('Bias: %f' % bias)#Calculate mean absolute error
mae = mean_absolute_error(X_test['Oil'],output_original['Oil_pred'])
print('MAE: %f' % mae)#Calculate mean squared error and root mean squared error
mse = mean_squared_error(X_test['Oil'], output_original['Oil_pred'])
print('MSE: %f' % mse)
rmse = sqrt(mse)
print('RMSE: %f' % rmse)
“众所周知,当数据相当持久时,动态回归模型的最小二乘参数估计在小样本中会表现出相当大的偏差”
VECM 估计和分析
由于存在非平稳但协整的数据形式,VECM 施加了额外的限制。它将协整限制信息应用到其规范中。在协整已知后,下一步的检验过程是通过使用误差修正方法来完成的。通过向量误差修正模型,我们可以解释长期和短期方程。我们需要确定协整关系的数量。VECM 相对于 VAR 的优势在于,从 VECM 表示得到的 VAR 具有更有效的系数估计。
Johansen 协整
为了拟合向量误差修正模型,我们需要使用 VEC 秩检验来确定协整关系的数量。
vec_rank1 = vecm.select_coint_rank(X_train, det_order = 1, k_ar_diff = 1, method = 'trace', signif=0.01)
print(vec_rank.summary())
我们在第三列中找到λtrace 统计数据,以及相应的临界值。测试统计值 38.25 低于临界值(41.08),因此至多一个协整合向量的零不能被拒绝。
让我们采用另一种统计,最大特征值统计(λmax)。
vec_rank2 = vecm.select_coint_rank(X_train, det_order = 1, k_ar_diff = 1, method = 'maxeig', signif=0.01)
print(vec_rank2.summary())
测试输出报告了λmax 统计信息的结果,该统计信息与 trace 统计信息相差不大;临界值(29.28)仍然高于测试统计值。
我们仍将继续估计 VECM,因为在缺乏协整的情况下,它对短期动态仍有价值。让我们用 9 个滞后、1 个协整关系和协整关系中的一个常数来估计价格的向量误差修正模型。我使用了*【慈利】**【ci】——协整关系中的常数和【李】——协整关系*中的线性趋势的组合
vecm = VECM(endog = X_train, k_ar_diff = 9, coint_rank = 3, deterministic = ‘ci’)
vecm_fit = vecm.fit()
vecm_fit.predict(steps=10)
forecast, lower, upper = vecm_fit.predict(10, 0.05)
print(“lower bounds of confidence intervals:”)
print(lower.round(3))
print(“\npoint forecasts:”)
print(forecast.round(3))
print(“\nupper bounds of confidence intervals:”)
print(upper.round(3))
VECM 预测评估
虽然我们有迹象表明,VAR 将是我们的价格预测数据集的最佳选择;然而,我们出于实验和说明目的展示了 VECM。这是一个解释 VAR 的简单程序。然而,如果我们能够看到一个变量的冲击如何在随后的时期影响其他变量,也可以将脉冲响应分析和方差分解等其他程序引入实验。
关键要点
经济数据的时间序列通常是随机的,或者具有不稳定的趋势,这意味着数据有一个根单位。能够用数据来估计一个模型-
VAR-的步骤
- 测试数据的平稳性和整合程度
- 滞后长度的确定
- 检验格兰杰因果关系
- 风险值估计
- 方差分解
VECM 的预测步骤-
- 滞后长度的确定
- 检验格兰杰因果关系
- 协整度检验
- 向量误差修正模型估计
- 方差分解
注意:此处描述的程序是实验性的,应谨慎使用。所有此类使用风险自负。
参考文献:
(1)饶,B. (2007)。协整:应用经济学家斯普林格。
(2) Ashley,r . a .&Verbrugge,R. J. (2009)。差异还是不差异:向量自回归模型中推断的蒙特卡罗研究。国际数据分析技术和策略杂志,1(3),242–274。
(3)吕特克波尔,H. (2011 年)。向量自回归模型。《国际统计科学百科全书》(第 1645-1647 页)。施普林格柏林海德堡。
(4)郭春英(2016)。向量误差修正模型在预测股价上比其他模型表现更好吗?剩余收益评估理论的一个应用。经济模型,52,772–789。
矢量化:如何用 x78 加速你的机器学习算法
给定一个等式,我们将看到 step by step 如何不仅在速度方面实现 x78 倍的更高效代码,而且仅使用 3 行代码!让我们深入了解一下…
介绍
作为一种解释语言, Python for
loops 天生就比 C 语言慢。这对臭名昭著的编程语言来说是一个很大的瓶颈,因为深度学习和机器学习算法严重依赖于矩阵运算,它们通过for
循环来执行。
这就是开发人员开发包的原因,比如numpy
,他们在numpy
数组上提供矢量化动作。这意味着它将通常在 Python 中完成的for
循环推到了更快的 C 层。
Python + C 级速度=天堂
问题是
(如果你能理解 EM 算法,你可以跳过解释部分)
我们希望将期望最大化 (EM)算法用于无监督学习任务(例如,识别 MNIST 数据集中的手写数字),并且我们的数据是二进制的(例如二进制图像)。一个自然的方法是将我们的数据建模为一个伯努利混合模型。伯努利分布的加权和,其中每个分布具有其自己的标量权重**π**
和其自己的均值向量**μ**
,并且表示数据的聚类(例如,如果我们的数据是数字 2、3 & 4 的图像,并且我们使用 3 个伯努利来对它们建模,一个伯努利将是数字 2,另一个是数字 4,等等)。总的来说,前者是一个向量,后者是一个矩阵。
Bernoulli mixture model (1)
Distribution of one observation x given the cluster k (2)
设 N =观察值的数量,D =一个观察值的维数,K =聚类的数量。因为这对我们的问题很重要,所以我们的随机变量类型有:
**X**
;我们的数据 a NxD 矩阵
(N 是图像的数量,D 是图像的维数→ 5 张 2828 的图像会组成一个 5x784 的矩阵 X)
π
;一个向量 K,一个代表权重的标量。
(例如三个伯努利可以有π=[0.2,0.75,0.05]加权向量)
**μ**
;每个聚类的平均 KxD 矩阵。
(一幅图像的维数为 D=2828=784,其中每一幅图像代表一个像素值。对属于同一聚类的图像的每个像素取平均值,比如数字 2,我们得到 784 的平均向量。因此,**μ**
将是 KxD 的矩阵)
在 E 步骤中,我们特别感兴趣的是潜在变量后验的期望值,或者所谓的责任
E-step of EM algorithm (3)
γ
实际返回期望值的观测值(图像)n
属于聚类k
。
γ
是一个 NxK 矩阵;对于每个观察值,我们分配一个属于每个聚类的概率。具有最大值的是我们分配给。
我为什么要说这些?
“矢量化中最重要的事情是理解变量的维数.”
责任的计算是我们要向量化的内容
总结一下:
**X**
:NxD 矩阵
**π**
:1xK 向量
**μ**
:KxD 矩阵
**γ**
**:NxK 矩阵**
管道
我们将创建一个函数E_step
来运行计算上面的表达式,并用下面的代码测试它
**observations = [5, 10, 20, 50, 100, 200, 500, 1000]
for n in observations:
X_test = bin_train_data[:n]
D_test, K_test = X_test.shape[1], 10 mu_test = np.random.uniform(low=.25, high=.75,
size=(K_test,D_test))
pi_test = np.ones(K_test) / K_test t0 = time.time()
gamma_test = E_step_1(X_test, mu_test, pi_test)
runtime = time.time() - t0
**assert** gamma_test.shape == (n, K_test)**
放心先自己试一试吧!
尝试№1
在我们的第一次尝试中,我们将使用 for 循环编写所有内容;在向量/矩阵运算中,只有标量。
通过看方程,我们可以看到有 3 个循环;每个例子一个N
,每个集群一个K
,每个物体的每个维度一个D
,我们将按这个顺序循环。所以我们要一次用一个元素填充矩阵γ
。
**def E_step(X, mu, pi):
N, D = X.shape
K = pi.shape[0]
gamma = np.zeros((N, K))
for n in range(N):
for k in range(K):
m = 1
for i in range(D):
m *= mu[k][i]**X[n][i] * (1-mu[k][i])**(1-X[n][i])
gamma[n][k] = m * pi[k]
gamma[n] /= gamma[n].sum()
return gamma**
我们的结果可以在下图中看到。
我们肯定能做得更好!
尝试 2
最好从内部循环开始,然后向外部循环推进。这正是我们要做的!
我们想摆脱 for 循环D
。因此,依赖于D
的每一项现在都应该变成一个向量。在这个 for 循环中,我们有两个变量;μ
和x
(见等式。(2)
)。因此x
和μ
→矢量。问题;这是μ**x
,向量到另一个向量的幂,很难计算。如果我们能绕过这个…
有一个函数可以将乘幂运算转化为乘法运算。没错,就是对数!让我们对表达式取对数,然后取结果的指数!
对数概率上的运算是优选的,因为它们提供了数值稳定性
尽管在我们的例子中它没有任何影响,但是每次使用 log 时,在表达式中使用一个常量epsilon
以保持稳定性(为了不归零,使用 is -inf
)。
因此,我们将不得不进行逐元素的向量乘法。容易;)
**def E_step(X, mu, pi):
N, D = X.shape
K = pi.shape[0]
gamma = np.zeros((N, K))
for n in range(N):
for k in range(K):
log_gamma = np.log(pi[k]) + (X[n] * np.log(mu[k]) \
+ (1 - X[n])*np.log(1 - mu[k])).sum()
gamma[n][k] = np.exp(log_gamma)
gamma[n] /= gamma[n].sum()
return gamma**
我们的结果是…
这是一个巨大的胜利!似乎 x 轴比得上Algor. 1
!但是,我们可以做得更好;)
尝试№3
一次一圈:轮到K
了!
在矢量化过程中,我们的移动如下:
标量→矢量→矩阵
随着我们用numpy
数组替换越来越多的循环,越来越多的代码将在 C 上运行→更快的&更干净的代码。
我们采用之前的实现,希望移除循环的K
。因此,每一个依赖于K
的标量都会变成一个vector
,而每一个vector
都会变成一个matrix
。这意味着X
将保持不变,而μ
将变成矩阵,而π
和γ
将变成向量。注意最后一条;随着γ
字段的一行一行,我们表达式的结果现在必须是一个向量!所以μ
和X
的操作必须产生一个1xK
向量,快速指示器是(I)它们必须与向量π
相加,向量也是1xK
(ii)结果是矩阵γ
的一行,向量也是1xK
。
将我们的结果编码成:
**def E_step(X, mu, pi):
N, D = X.shape
K = pi.shape[0]
gamma = np.zeros((N, K))
for n in range(N):
log_gamma = np.log(pi) + np.log(mu) @ X[n] \
+ np.log(1 - mu) @ (1 - X[n])
gamma[n] = np.exp(log_gamma)
gamma[n] /= gamma[n].sum()
return gamma**
结果是:
********
太神奇了!我们已经为n=1000
争取到了一半的时间!跟Algor. 1
真的没法比。但是,我们能做得更好吗?
尝试№4
我们还有一个循环。我们能有一个计算循环-python-free 吗?N
,你的时间到了!**
由于我们要将一个matrix * vector
运算转化为一个matrix @ matrix
运算,我们需要取前者的传输矩阵(@
是正则矩阵乘法)。请记住,现在我们的输出必须是整个γ矩阵。我想现在你已经知道它是怎么回事了;).
所以我们的代码应该是
**def E_step(X, mu, pi):
gamma = np.exp(np.log(pi) + X @ np.log(mu.T) \
+ (1 - X) @ np.log(1 - mu.T))
gamma /= gamma.sum(axis=1)[:, np.newaxis]
return gamma**
没有一个循环!代码看起来很优雅,而且只有三行长!现在是结果,鼓声…
********
就是这样,不能再好了!对于n=1000
,我们只用了三行代码就从运行时的11.688
→ 0.012
!
摘要
那么,当你想对一个表达式进行矢量化时,你需要做什么呢?
了解矩阵的尺寸。
纸笔:记下公式,从求和到求和,化为等价矩阵运算
数学是你的朋友;总是考虑任何表达式必须返回的维数;观察邻居求和运算,因为它们具有相同的维数
逐循环、逐步进行:标量→向量→矩阵 取对数并确保引入归一化常数ε
代码您的方法的矢量化版本并闪耀:D****
供应商—定义您对#AI 的使用
Photo by Lukas on Unsplash. Used with permission.
作为一名行业分析师,我听取了许多供应商的简报。在这些简报中越来越常见的是,厂商频繁而随意地使用缩写***【AI】***来描述他们产品或服务的各种功能。
在最近的一次简报中,这种做法在一家大型供应商那里尤为明显。他们的短语是:*AI+BI;用 AI…的力量去探索他们的数据;有了 AI……变得更聪明;AI 让数据可访问;人工智能…从根本上改变了分析的使用方式;由 AI 驱动;注入了人工智能。*所有这些都在前 13 张幻灯片中!
注:这是我的一面大红旗!我完全避免在我的文章中使用 AI 这个缩写词,因为它经常含糊不清,并且分散了我想要传达的信息。
我问了这个问题,“你们公司是怎么定义 AI 的?”
这个首字母缩略词是指…描述性分析之外的任何分析吗?预测未来事件的分析?因果关系的发现?模仿人类的思维过程?超过人类专家水平的分析?深度神经网络的使用?业务流程自动化?或者,仅仅是又一个分析技术时代?
更新 2019–03–13:文章 AI 已经变得毫无意义 作者 Ian Bogost 在《大西洋月刊》中有许多明确的例子和一些有用的替代方法。
厂商的回答很简单……AI 的意思是增强智能,不是人工智能。这个回答让我很惊讶。
但是 AI =人工智能
对大多数专业人士来说,AI 这个缩写意味着人工智能。如果供应商暗示了一个替代概念,比如增强智能,他们就不应该使用这个缩写。
此外,我想知道为什么这个短语没有明确地出现在他们的幻灯片中,所以我继续问定义他们的 AI 用法的问题。
外卖:厂商应该把 AI 这个缩写词限制在描述一般的技术趋势,避免把 AI 这个缩写词和产品/服务特性联系起来。
强调增加
我说这是一个好的回答,因为它强调了**自动化(取代人类)与增强(增强人类)**的关键问题。增强智能意味着人类的智能正在增强,而不是被更好、更便宜或更快的东西取代。这是一个微妙但关键的转变,它承认人类的价值,特别是他们的直觉、创造力、经验和判断力。
然后,我建议他们应该在营销信息中强调这一点,因为对其增强的准确陈述将是一个实质性的营销点。换句话说,他们已经错过了与现有观众交流的大好机会。
外卖:供应商应该总是强调增加,而不是取代人类的智慧。此外,清楚地展示如何利用和增强个人的独特能力。
强调学习
人工智能系统的一个关键方面是它能够让 T2 学习 T3。不幸的是,这个主题不是这个供应商的简报的一部分,这意味着他们的“人工智能”能力是创造性的静态算法。这应该被认为是“人工智能”吗?
重要的一点不是人工智能系统学习,而是系统通过展示良好的行为范例被教授令人满意的行为。这是从静态逻辑到学习逻辑的范式转变,随着更多例子的使用,这种转变会得到改善。参见这篇关于新价值观的文章 [1]
因此,重要的是要知道…谁在教学?又是怎么做到的?
在传统的机器学习中,这种教学是由人类对示例数据集的管理来驱动的,这些示例数据集是从原始数据中精心制作的显著特征。如今人工智能系统的核心——神经网络——正在通过投掷原始数据,通过从其他模型转移训练,或者通过与其他神经网络竞争来学习。可以更有效地进行学习逻辑的教学。因此,教授这个学习人工智能系统的机制是一个关键的方面,需要一个清楚的解释。
外卖:厂商应该定义他们的人工智能产品如何学习。AI 模型的教学(训练)是如何进行的?
定义价值
供应商关于增强智能的回答暗示了一个明显的下一个问题:通过学习型人工智能系统增强人类智能如何给组织带来价值?
几十年来,IT 行业一直在追求增强智能,当我在 20 世纪 60 年代末参与进来时,它被贴上了“决策支持系统”的标签。我立刻想到了约翰·图基在 20 世纪 70 年代早期在一辆瓦里安 620 上演示 PRIM-9。这里有一篇关于这一历史瑰宝的简短博客(和视频)!2
面临的挑战是如何通过提高个人的效率和/或效力来确定具体的增强对组织的价值。
彼得·德鲁克(Peter Drucker)那句臭名昭著的名言与此相关:“效率就是把事情做对;有效性就是做正确的事情。【③】
增强人类的智力,让人们能够更快、更便宜、更可靠地完成特定的任务(做正确的事情)是件好事。然而,如果这个人能够定制任务以满足特定情况的需要 ( 做正确的事情),那就更好了。这一点在这篇关于新价值观的文章中解释为 智能效能 。[4]
要点:供应商应该精确地了解人类的智能是如何增强的。并且,展示这种增强如何为组织增加价值,尤其是智能效率。
术语 AI 的随意使用是欺骗性的
首字母缩写词 AI 的随意使用充其量是含糊不清的,而且经常具有欺骗性,尤其是在营销信息中!
对于一些观众来说,不幸的是,它的使用传达了产品/服务的一种神奇的品质,暗示着“来买这个吧,你所有的商业问题都会很快消失。”这就是首字母缩写 AI 背后微妙但误导人的魅力!
任何了解深度神经网络当前研究和实践的人都意识到,企业中的实际人工智能应用范围有限,难以开发,部署麻烦,难以实现价值……尽管大型技术供应商进行了迷人的演示!没有魔法,只有一个关于一百万个简单数字的群集如何能够模拟现实的复杂性的秘密。
许多专家得出结论,人工智能技术仍然处于“炼金术”阶段,作为一门原始科学,就像中世纪的化学一样……关于“什么-如何-为什么”的问题比理论更多。详见本文。[1]
我同意,从长远来看,这项技术有巨大的潜力。与此同时,早期采用者(和他们的供应商)应该预料到背后会有很多箭!
外卖:厂商应抵制利用人工智能的空洞营销炒作。那些日子已经过去了。相反,深入思考并清楚地解释你的产品为增强某人的能力和学习提高其能力所带来的价值。
用人工智能处理伦理问题
这是随意使用 AI 首字母缩写词的积极一面。准备好面对黑暗面了吗?
越来越多的人认为,人工智能意味着业务流程的自动化,导致人类的替代,以及失业、技能灭绝、管理集中化、财富集中和政治控制等令人讨厌的影响。
将未来押在人工智能上的厂商应该非常谨慎,并对道德含义有政治头脑。在汤姆·达文波特(Tom Davenport)和比尔·弗兰克斯(Bill Franks)的 2019 年 IIA 预测和分析优先事项中,他们的第一个预测是: 将越来越强烈地关注分析的道德 ,并敦促他们的客户 今天就开始正式解决分析道德问题 ![5]
你的公司是否明确批准并热情鼓励公开和诚实的讨论,以及政策的形成,关于你的产品/服务在人工智能旗帜下营销的道德含义?
几十年来,我经历了许多技术浪潮。对我来说,现在的深度神经网络浪潮,特别刺激,特别有挑战性。然而,我必须承认,我越来越觉得自己像一个 1940 年代开发核能的科学家。这是一个巨大的好的潜力…也是一个悲剧!
忘记人工智能机器人奴役人类的威胁吧。真正的威胁是人工智能系统正在被武器化以对抗其他系统,这是有意的,尤其是天真的。像核能一样,这个大国必须得到明智的管理。[6, 7, 8]
要点:供应商应该公开诚实地面对道德问题。帮助他们的客户理解和管理这些道德问题。
如果你有类似的动机,请与我合作。作为 Bolder 技术的一部分,请查看我目前在 BizSmartAnalytics 的工作。[9]一些掌声将不胜感激;)
© Bolder Technology — CC BY 3.0 US
更新 2019–06–29:发了这个 JPEG 来强调以上几点。请在与同事讨论时使用。
参考
- Hackathorn,管理者应该如何准备深度学习:新范式,
https://towards data science . com/How-Managers-Should-Prepare-for-Deep-Learning-New-Paradigms-28de 63054 ea 6 - 黑客马拉松,交互式三维数据可视化的开端,
https://www . immersiveanalytics . com/2015/11/Beginning-of-Interactive-3D-Data-Visualization/ - 彼得·德鲁克, 经营效益管理。第 53-60 页。
- 黑客马拉松,管理者应该如何准备深度学习:新价值观,
https://towardsdatascience . com/How-Managers-Should-Prepare-for-Deep-Learning-New-Values-f 29 a 98 b 70 BD 8 - 达文波特和弗兰克斯,关于 2019 年分析预测&优先事项的网络研讨会,由国际分析研究所于 2018 年 12 月 6 日举办,https://www . ii Analytics . com/2019-Analytics-Predictions-Priorities-Webinar/
- Chollet,我担心什么 AI,
https://medium . com/@ Francois . chollet/What-Worries-Me-About-AI-ed 9df 072 b 704 - 入伙上艾,
【https://www.partnershiponai.org/】T21 - 骑士,AI 的父亲之一担心它的未来,
https://medium . com/MIT-technology-review/One-of-the-Fathers-of-AI-is-Future-a 7996 cddce 72 - 黑客马拉松,深度学习系统的管理挑战,
https://BizSmartAnalytics.com/
Python 中的维恩图和单词云
所有你不需要知道的西雅图宠物名称和品种
Photo by Jakob Owens on Unsplash
在我对西雅图宠物的调查中,我发现自己很想知道宠物的名字——最流行的宠物名字是什么?猫的名字和狗的名字是不同的吗,就像猫和狗是不同的一样(平均来说,我们都有这样一个朋友,当你来到门口的时候,他会跑过来迎接你,当你叫他的时候,他会过来,玩捡东西的游戏。或者当它的家人举行聚会时,那只藏在椽子里的狗…)?还有宠物品种——西雅图的每只狗都是狮子狗混种吗?这些经常出现在我家后院的奇特的猫有多常见(还没有被我的小狗贝克汉姆注意到,它以前从来没有在一楼住过)?
还有其他心怀不满的纽约巨人队球迷,他们用小奥德尔·贝克汉姆的名字给他们的狗命名,但当他搬到克利夫兰·布朗(NFL 历史上统计数据最差的球队之一)时,他们感到非常失望,在那里他迅速开始了他最糟糕的一年。我本人是一个骄傲的西雅图和海鹰队的球迷,但我嫁给了一个新泽西巨人队的球迷(他慷慨地编辑了这篇文章,并利用他的编辑控制权表达了他对巨人队的失望——迄今为止只有 3 胜 11 负——和小奥黛尔·贝克汉姆)。
不管怎样…在这个过程中,我意识到了一个维恩图的绝佳机会,甚至维恩图单词云可以帮助回答这些问题。
顶级猫狗名
我从横条图开始,查看西雅图最常见的 50 个猫狗名。
fig, axes = plt.subplots(ncols=2, figsize=(12,12))
plt.subplots_adjust(wspace=.3)axes[0].barh(cat_t50['name'], cat_t50['count'], .5, color='#294AB9',
alpha=0.8)
axes[0].invert_yaxis()
axes[0].set_title("Frequency of Seattle's Top 50 Cat Names",
fontsize=12)
axes[0].set_xlabel("Number of Cats")axes[1].barh(dog_t50['name'], dog_t50['count'], .5, color='#1896ac',
alpha=0.8)
axes[1].invert_yaxis()
axes[1].set_title("Frequency of Seattle's Top 50 Dog Names",
fontsize=12)
axes[1].set_xlabel("Number of Dogs");
注意这里使用的一些matplotlib
工具:
- 使用
plt.subplots_adjust(hspace=.3)
水平分隔支线剧情,这样名字就不会出现在其他剧情中。在文档中找到更多关于调整支线剧情的信息。 ax.invert_yaxis()
将翻转 y 轴,使数据集中的第一项出现在顶部。
我马上注意到的一件事是,前 50 名狗名单和前 50 名猫名单上的名字有很多重叠:我称之为“物种中性名字”。为了形象化这一点,我做了一个文氏图。
注意:根据 PyPI 文档,您需要pip install
或easy-install
matplotlib-venn
,并确保您拥有依赖关系:numpy
、scipy
和matplotlib
。
from matplotlib_venn import venn2, venn2_circles
from matplotlib import pyplot as plt# setup the figure
fig, ax = plt.subplots(figsize = (12,10)
ax.set_title(‘Top 50 Cat and Dog names in Seattle’, fontsize=20)# make the venn diagram
v = venn2([set(cat_t50[“name”]), set(dog_t50[“name”])],
set_labels=[‘Cat Names’, ‘Dog Names’])# adjust labels from counts to names
v.get_label_by_id(‘10’).set_text(‘\n’.join(cat_only_names))
v.get_label_by_id(‘01’).set_text(‘\n’.join(dog_only_names))
v.get_label_by_id(‘11’).set_text(‘\n’.join(overlap_names))# add circle outlines
c = venn2_circles([set(cat_t50[“name”]), set(dog_t50[“name”])],
linestyle=’solid’)
使用matplotlib-venn
的一些注意事项:
venn2
(两个圆圈)的参数编号如下:“10”=仅左侧项目,“01”=仅右侧项目,“11”=左侧和右侧项目。相同的框架适用于venn3
(三个圆圈):‘100’=仅第一组项目,‘010’=仅第二组项目,‘110’=第一和第二组的交集,但不在第三组中,等等。Get_label_by_id()
允许您.set_text()
get_patch_by_id()
允许您.set_alpha()
和.set_color()
venn2_circles
添加轮廓,并允许您为不同的圆设置不同的轮廓,使用索引指示哪个圆,set_lw(*width*)
指示线宽,.set_ls(*linestyle*)
指示线型。c[0].set_ls(‘dotted’)
例。记住matplotlib
有多种内置的线条样式,包括‘实线’、‘虚线’、‘虚线’,以及定制功能。
注意猫专用名(Shadow、Loki、Smokey)和狗专用名(Cooper、Sadie、Bailey)的区别。狗更有可能被赋予“人类”的名字吗?改天的问题…
作为调整颜色的一个例子,我决定看看猫和狗的名字通常是如何重叠的。
from matplotlib_venn import venn2, venn2_circles
from matplotlib import pyplot as pltfig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Species-neutral names in Seattle’, fontsize=20)v = venn2([set(cat_names[“name”]), set(dog_names[“name”])],
set_labels=[‘Cat Names’, ‘Dog Names’])
v.get_patch_by_id(‘10’).set_color(‘red’)
v.get_patch_by_id(‘10’).set_alpha(0.4)
v.get_patch_by_id(‘01’).set_color(‘blue’)
v.get_patch_by_id(‘01’).set_alpha(0.4)
v.get_patch_by_id(‘11’).set_color(‘purple’)
v.get_patch_by_id(‘11’).set_alpha(0.4)c = venn2_circles([set(cat_names[“name”]),set(dog_names[“name”])],
linestyle=’solid’)
请注意,圆圈内的标签和大小是基于猫/狗名称的数量,而不是数量,尽管注册的狗数量比西雅图注册的猫数量多。
在我寻找显示维恩图中名字的方法时,我看到了 Paul Broaderson 的这个可爱的包,它在你的维恩图中创建了一个单词云。你所需要做的就是安装matplotlib-venn-wordcloud
,然后你就可以使用与上面相同的语法开始比赛了。默认的配色方案是黑色和白色,但是您可以按照matplotlib-venn
中使用的相同策略添加背景色。注意,单词的大小并不自动反映单词的频率。查看文档添加该功能。
from matplotlib_venn_wordcloud import venn2_wordcloud
fig, ax = plt.subplots(figsize=(10,10))
ax.set_title(‘Top 50 Cat and Dog Names in Seattle’, fontsize=20)v = venn2_wordcloud([set(cat_t50[‘name’]), set(dog_t50[‘name’])],
ax=ax, set_labels=[‘Cats’, ‘Dogs’])# add color
v.get_patch_by_id(‘10’).set_color(‘red’)
v.get_patch_by_id(‘10’).set_alpha(0.4)
v.get_patch_by_id(‘01’).set_color(‘blue’)
v.get_patch_by_id(‘01’).set_alpha(0.4)
v.get_patch_by_id(‘11’).set_color(‘purple’)
v.get_patch_by_id(‘11’).set_alpha(0.4)
Ragamuffin Kitten from Togle1 [CC BY-SA 4.0 ] on wikimedia commons
猫和狗的品种
接下来看看品种,猫似乎在完全不科学的最佳品种名称( Ragamuffin )和最可爱品种名称( Munchkin )奖项中拔得头筹。与此同时,令人惊讶的是,这些狗并不都是涂鸦狗。不管走在街上看起来如何,他们实际上只占 9%左右。
Munchkin Cat (inspired by the Wizard of Oz) from Tasy Hong [CC0] on Wikimedia Commons
仔细看看最常见的涂鸦:拉布拉多涂鸦和金毛涂鸦,我们看到在 34,882 只注册狗中,大约有 10,000 只或 28%的西雅图注册狗将其中一只(拉布拉多或金毛)作为它们的主要或次要品种。大约四分之一具有金毛血统的狗是金杜,而接近 15%具有拉布拉多血统的狗是拉布拉多。然后还有 135 个金达多。我们的数据集中没有双涂鸦(拉布拉多金毛狗混种),尽管这可能受到宠物注册数据收集过程的限制,该过程只允许主人识别主要和次要品种。这指出了维恩图中不精确的地方,但总的来说,这是一个非常棒的工具。
from matplotlib_venn import venn3, venn3_circles
fig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Poodle-Lab-Golden Mixes in Seattle’, fontsize=20)v = venn3([set(poodle_dogs), set(labs), set(goldens)],
set_labels=[‘Poodle’, ‘Labrador Retriever’,
‘Golden Retriever’],
ax=ax)
c = venn3_circles([set(poodle_dogs), set(labs), set(goldens)],
linestyle=’solid’, ax=ax)
A certain Labradoodle puppy
最后,我想知道,在西雅图的贵宾犬中,有多少是涂鸦?
答案是:很多。而matplotlib-venn
像 champ 一样处理这种情况,为了美观,只要求最右边补丁的标签设置为" "。
from matplotlib_venn import venn2, venn2_circles
fig, ax = plt.subplots(figsize = (10,10))
ax.set_title(‘Poodles vs. Poodle Mixes in Seattle’, fontsize=20)v = venn2([set(poodle_dogs), set(doodle_dogs)], set_labels=[“”,””],
ax=ax)
v.get_label_by_id(‘10’).set_text(‘Poodle’)
v.get_label_by_id(‘11’).set_text(‘Doodle’)
v.get_label_by_id(‘01’).set_text(‘’)c = venn2_circles([set(poodle_dogs), set(doodle_dogs)],
linestyle=’solid’, ax=ax)
和往常一样,查看 GitHub repo 了解更多细节。
**临别赠言:**作为一个养狗名为小奥戴尔·贝克汉姆(O’dell Beckham Jr. Honold)(注册名为‘Beckham’)的人,我对西雅图只有一只注册名为‘Ichiro’的宠物感到震惊和错愕。但振奋地发现有 39 个威尔逊 39 个格里菲斯 29 个埃德加 22 个谢尔曼,21 个拉塞尔,以及 6 个马肖恩,佩顿,邓普西。其中 22%是猫,78%是狗,相比之下,32%是猫,67%是狗。这句话是在说猫和狗的本性,猫和狗的主人,还是两者都是?
对凯文来说,原来还有另外两只小贝夫妇*,一只金毛寻回犬,另一只短毛吉娃娃。*
Goldendoodle puppy by William Warby [CC BY 2.0] on Wikimedia Commons
在 Python 和 R 中验证线性回归的假设
深入探究高斯-马尔可夫定理和线性回归的其他假设!
线性回归是最基本的机器学习算法之一,经常被用作更高级模型的基准。我假设读者知道线性回归是如何工作的,以及一般来说回归问题是什么。这就是为什么在这篇短文中,我想重点介绍算法的假设——它们是什么,以及我们如何使用 Python 和 r 来验证它们。我并不试图在这里应用解决方案,而是指出它们可能是什么。
在本文中,我主要使用 Python(在 Jupyter Notebook 中),但我也展示了如何使用rpy2
——一种“两种语言之间的接口,以便在使用另一种语言时受益于一种语言的库”。它使我们能够在同一个笔记本中运行 R 和 Python,甚至在两者之间传输对象。直觉上,我们也需要在我们的计算机上安装 R。
声明:一些使用rpy2
的单元格不工作,我不得不“欺骗”在 R 中运行它们来显示结果。使用ggplot2
的细胞大多如此。尽管如此,我还是把代码留在了这个单元里。如果这对你有用,请在评论中告诉我:)
开始吧!
1.数据
在本文中,我使用了一个经典的回归数据集——波士顿房价。为了简单起见,我只取数值变量。这就是为什么我放弃了唯一的布尔特征——CHAS。我不打算深究这些特性的含义,但这总是可以通过运行print(boston.DESCR)
来检查。
2.运行线性回归
大多数读者可能会估计这样的线性回归模型:
Coefficients: [-1.13139078e-01 4.70524578e-02 4.03114536e-02 -1.73669994e+01
3.85049169e+00 2.78375651e-03 -1.48537390e+00 3.28311011e-01
-1.37558288e-02 -9.90958031e-01 9.74145094e-03 -5.34157620e-01]
Intercept: 36.89195979693238
R^2 score: 0.7355165089722999
这当然不是错误的方法。然而,从 R 到 Python,我对默认接收的信息量有更高的期望。要在我们的笔记本中运行 R,我们首先需要运行这个神奇的命令:
%load_ext rpy2.ipython
随后,使用另一个神奇的命令表明该单元包含 R 代码。在这一步,我还使用了输入命令-i
来指示我正在将一个对象从 Python 传递到 R。要将 R 的输出检索到 Python,我们可以使用-o
。运行这两行会产生更多的信息,包括统计显著性和一些指标,如 R。
当然,Python 不会落后,我们可以使用另一个流行的库— statsmodels
获得类似级别的细节。需要记住的一点是,当在statsmodels
中使用线性回归时,我们需要添加一列 1 作为截距。为此我使用了add_constant
。结果比来自sklearn
的默认结果信息丰富得多。
所以现在我们来看看如何在 R 和 Python 中运行线性回归。让我们继续假设。我把这些分成两部分:
- 高斯-马尔可夫定理的假设
- 其余的假设
3.高斯-马尔可夫定理
在您的统计学或计量经济学课程中,您可能听说过线性回归中的缩写词 BLUE。这是什么意思?根据高斯-马尔可夫定理,在线性回归模型中,普通最小二乘(OLS)估计器给出系数的最佳线性无偏估计器(蓝色),前提是:
- 误差(残差)的期望值是 0
- 误差是不相关的
- 误差具有相等的方差——误差的同方差
此外,蓝色的“最佳”表示与其他无偏线性估计相比,导致估计的最低方差。
对于蓝色的估计器,残差不需要遵循正态(高斯)分布,也不需要独立且同分布。
模型的线性
因变量(y)被假定为模型中指定的自变量(X,特征)的线性函数。规格参数必须是线性的。将线性模型拟合到具有非线性模式的数据会导致严重的预测错误,尤其是样本外(未用于训练模型的数据)。
为了检测非线性,可以检查观察值与预测值或残差与预测值的关系图。期望的结果是,在前一个图中,点对称地分布在对角线周围,或者在后一个图中,点对称地分布在水平线周围。在两种情况下都有大致恒定的方差。
观察到“弓形”模式表明,每当该模型做出异常大或小的预测时,它都会犯系统性错误。当模型包含许多特征时,非线性也可以通过残差与单个特征的关系图中的系统模式来揭示。
对图的检查表明,线性假设不满足。
潜在解决方案:
- 因变量/自变量的非线性变换
- 添加额外的功能,这些功能是已经使用的功能的转换(例如方形版本)
- 添加以前没有考虑到的功能
残差的期望值(均值)为零
这个很容易检查。在 Python 中:
lin_reg.resid.mean()
# -1.0012544153465325e-13
而在 R:
%%R
mean(lin_reg$resid)
# 2.018759e-17
结果有点不同,据我所知,这是一个数值近似值问题。但是,我们可以假设残差的期望值确实是 0。
无(完全)多重共线性
换句话说,这些特征应该是线性独立的。这在实践中意味着什么?我们不应该能够使用一个线性模型来准确地预测一个特征使用另一个特征。让我们以 X1 和 X2 作为特征的例子。有可能发生 X1 = 2 + 3 * X2,这违背了假设。
需要注意的一个场景是“虚拟变量陷阱”——当我们使用虚拟变量对分类特征进行编码时,不要忽略模型中的基线水平。这导致虚拟变量和常数项之间的完美关联。
多重共线性可以存在于模型中,只要它不是“完美”的。在前一种情况下,估计效率较低,但仍然是无偏的。估计会不太精确,对特定的数据集高度敏感。
我们可以使用方差膨胀因子 (VIF)来检测多重共线性。在不涉及太多细节的情况下,VIF 的解释如下:给定变量的 VIF 的平方根显示了与该预测因子与模型中的其他要素不相关的情况相比,标准误差要大多少。如果没有相关的要素,则 VIF 的所有值都将为 1。
%%R
library(car)
vif(lin_reg)
为了处理多重共线性,我们应该反复移除具有高 VIF 值的要素。移除的经验法则可能是 VIF 大于 10 (5 也是常见的)。另一种可能的解决方案是使用 PCA 将特征减少到一个更小的不相关组件集。
提示:我们还可以查看特性的相关性矩阵,以确定它们之间的依赖关系。
残差的同方差(等方差)
当残差不具有恒定方差时(它们表现出异方差),很难确定预测误差的真实标准差,通常会导致置信区间过宽/过窄。例如,如果残差的方差随着时间的推移而增加,样本外预测的置信区间将变得非常窄。异方差的另一个影响也可能是在估计系数时对数据子集(误差方差最大的子集)赋予过多的权重。
为了研究残差是否是同方差的,我们可以查看残差(或标准化残差)与预测值(拟合值)的关系图。我们应该警惕残差作为预测值或时间的函数增长的情况(在时间序列的情况下)。
我们也可以使用两种统计检验:Breusch-Pagan 和 Goldfeld-Quandt。在这两种情况下,零假设假设假设同异方差,而低于某一水平(如 0.05)的 p 值表明我们应该拒绝零假设而支持异方差。
在下面的片段中,我绘制了残差(和标准化值)与拟合值的关系,并进行两个提到的测试。为了确定图中的同方差,点的放置应该是随机的,并且不应该有可见的模式(残差值的增加/减少)- R 图中的红线应该是平的。我们可以看到,对于我们的数据集,情况并非如此。
结果表明,假设不成立,我们应该拒绝同异方差假设。
潜在解决方案:
- 因变量的对数变换
- 在时间序列的情况下,如果它涉及货币价值,则对序列进行缩减
- 使用 ARCH(自回归条件异方差)模型来模拟误差方差。一个例子可能是股票市场,其中的数据可以显示随着时间的推移波动性增加或减少的周期(波动性聚类,参见本文了解更多信息)
无残差自相关
这种假设在时间序列模型中尤其危险,因为残差中的序列相关性意味着模型还有改进的空间。极端的序列相关性通常是模型严重错误的标志。残差中序列相关的另一个原因可能是违反了线性假设,或者是由于可以用省略变量(可识别条件的交互项或虚拟变量)解释的偏差。前一种情况的一个例子可能是对数据拟合一条(直线),该数据随时间呈指数增长。
这个假设在非时间序列模型的情况下也有意义。如果残差在特定条件下总是具有相同的符号,这意味着当预测者具有特定配置时,模型系统地低估/高估了发生的情况。
为了研究自相关是否存在,我使用了 ACF(自相关函数)图和 Durbin-Watson 检验。
在前一种情况下,我们希望了解 ACF 的值对于任何滞后是否显著(如果没有时间序列数据,则使用行号)。在调用该函数时,我们指出我们感兴趣的显著性水平(更多细节见本文),并在图上标出关键区域。显著的相关性不在这个范围之内。
注意:当处理没有时间维度的数据时,我们可以选择绘制残差与行号的关系。在这种情况下,应以(仅)取决于要素值的方式对行进行排序。
第二种方法是使用德宾-沃森测试。我不会详细介绍它是如何构造的,但会提供一个高层次的概述。检验统计提供了对滞后 1 处的显著残差自相关的检验。DW 统计大约等于2(1-a)
,其中a
是滞后 1 残差自相关。DW 测试统计位于statsmodels
回归的默认汇总输出中。
关于德宾-沃森测试的一些注释:
- 测试统计值总是介于 0 和 4 之间
- 值为 2 表示样本中没有自相关
- 数值< 2 indicate positive autocorrelation, values > 2 负一。
潜在解决方案:
- 在轻微正自相关的情况下,可能有一些微调模型的空间,例如,添加因变量/自变量的滞后
- 模型可能无法捕捉到某些季节性因素,请使用虚拟变量或季节性调整变量来解释这些因素
- 如果 DW < 1,则可能表明模型规范中可能存在问题,考虑通过差分、记录和/或缩减(在货币值的情况下)对时间序列变量进行平稳化
- 在显著负相关的情况下,一些变量可能被过度区分
- 使用广义最小二乘法
- 包括线性(趋势)项,以防残差中出现一致的增加/减少模式
4.其他假设
下面我介绍一些其他的线性回归的普遍验证的假设。
特征和残差是不相关的
为了研究这个假设,我检查了每个特征和残差之间的皮尔逊相关系数。然后报告 p 值,以测试两个考虑系列之间缺乏相关性。
我不能拒绝任何一对的零假设(缺乏相关性)。
观察的数量必须大于特征的数量
这个很简单。我们可以通过使用 Python 中的shape
方法或 r 中的dim
函数来检查数据的形状。此外,根据经验,我们应该在数据集中有 30 个以上的观察值。这取自中心极限定理,该定理指出,当样本大小大于 30 时,即使随机变量本身不是高斯型的,添加 IID 随机变量也会导致归一化分布。
特征上肯定有一些可变性
这种假设表明特征中一定存在一些差异,因为对于所有或大多数观察值具有恒定值的特征可能不是一个好的预测器。我们可以通过简单地检查所有特征的方差来检验这个假设。
X.apply(np.var, axis=0)
在 R 的caret
包中有一个名为nearZeroVar
的函数,用于识别方差为零或接近零的特性。
%%R
library(caret)apply(X, 2, var)
nearZeroVar(X, saveMetrics= TRUE)
残差正态性
当这个假设被违反时,它会导致计算置信区间和系数的各种显著性测试的问题。当误差分布明显偏离高斯分布时,置信区间可能太宽或太窄。
导致非正态残差的一些潜在原因:
- 数据中存在一些大的异常值
- 模型假设可能存在一些其他问题(违规)
- 另一个更好的模型规范可能更适合这个问题
从技术上讲,如果我们假设模型方程是正确的,并且我们的目标是估计系数并生成预测(在最小化均方误差的意义上),我们可以忽略这个假设。
然而,通常我们感兴趣的是从模型中做出有效的推断,或者估计给定预测误差在特定方向上超过某个阈值的概率。为此,必须满足关于残差正态性的假设。
为了研究这个假设,我们可以看看:
- 残差的 QQ 图(详细描述可以在这里找到)。例如,偏离对角线的弓形模式意味着残差具有过度的偏斜度(即,分布是不对称的,在一个方向上有太多的大残差)。s 形偏差模式意味着残差的峰度过大——在两个方向上都有太多或两个大误差。
- 使用统计检验,如科尔莫戈罗夫-斯米尔诺夫检验、夏皮罗-维尔克检验、贾尔克-贝拉检验和安德森-达林检验
根据上述结果,我们可以推断残差不遵循高斯分布——根据 QQ 图的形状,以及在所有统计测试中拒绝零假设。来自ols_test_normality
的 Kolmogorov-Smirnov 显示不同结果的原因是它没有运行“双边”版本的测试。
潜在解决方案:
- 目标变量或特征非线性变换
- 移除/处理潜在的异常值
- 可能会出现两个或两个以上的数据子集具有不同的统计特性,在这种情况下,可以考虑单独的模型
5。奖金:异常值
这不是一个真正的假设,然而,在我们的数据中异常值的存在会导致违反上述一些假设。这就是为什么我们应该调查数据,并核实一些极端的观察是否有效,对我们的研究是否重要,或者仅仅是一些我们可以消除的错误。
我不会深究离群点检测方法,因为已经有很多关于它们的文章了。一些可能的方法:
- z 分数
- 箱形图
- 杠杆-衡量一个点的特征值与不同观测值之间的距离。高杠杆点是变量的极值点,在该点附近缺少观测值使得拟合的回归模型接近该特定点。
- 库克距离-衡量删除观察如何影响回归模型的一种方法。调查具有高库克距离的点是有意义的。
- 隔离森林——更多详情见这篇文章
6.结论
在本文中,我展示了线性回归的假设是什么,如何验证它们是否满足,以及我们可以采取哪些潜在的步骤来解决模型的潜在问题。本文使用的代码可以在 GitHub 上找到。
一如既往,我们欢迎任何建设性的反馈。你可以在推特上或者评论里联系我。
喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,而不需要额外的费用。提前感谢,再见!
参考
数据科学家的版本控制:实践介绍
从历史上看,许多数据科学家不使用像版本控制系统这样的“软件开发”工具。如今,随着他们的代码变得越来越复杂,数据科学家越来越多地受到他们的软件工程合作伙伴的影响,学习如何熟练地使用 Git 这样的版本控制系统变得越来越重要。
在这个简短的动手介绍中,您将学到足够的 Git,以便当您获得一份数据科学家的工作时,能够跟踪您的变化,并与您的同事分享。
什么是版本控制?
版本控制系统允许你跟踪你对你的工作所做的改变。这有点像谷歌文档中的“跟踪修改”,但不同的是,你可以保存一组文件的修改,而不仅仅是单个文件内的修改。大多数版本控制系统也支持分支的思想,允许不同的人对相同的底层文件进行不同的更改,然后在以后将他们的工作合并在一起。
数据科学家如何使用版本控制?
作为一名数据科学家,即使你只处理一个文件(比如一个 Jupyter 笔记本),你也可以使用版本控制系统来跟踪你的变更(通常会这样)。它允许您定期保存您的工作,这使得您可以轻松地将笔记本恢复到早期版本。
随着项目变得越来越复杂,版本控制变得更加有价值。用一个 Jupyter 笔记本开始一个项目是很常见的。随着时间的推移,笔记本变得充满了清理导入数据的小功能,以至于很难专注于笔记本的重要部分。
解决这个问题的一个好方法是将这些函数分解成单独的 Python 文件,您可以使用一行代码调用这些文件。通过这种方式,任何希望了解您的项目的人都可以从 Jupyter 笔记本中获得一个高层次的视图,然后如果他们想了解您的数据清理脚本的细微差别,他们可以随时深入研究您的支持 Python 文件。这种策略也使得编写自动化单元测试来确认您的数据清理脚本将您期望的转换应用于各种类型的输入变得更加容易。
一旦您的项目有多个需要保持同步的文件,像 Git 这样的版本控制系统就特别有用,因为它允许您对多个文件进行一系列更改,然后将它们一起“提交”,这样您就可以轻松地将所有文件恢复到提交后的状态。
安装 Git
如果你还没有安装 Git,请点击这里,按照你的操作系统的安装程序进行操作。
Git 101
让我们从定义几个关键概念开始,这些概念在我们讨论 Git 时会有所帮助:
- 一个库——这是 Git 对一个项目的名称。它包括项目中的所有文件,以及它们如何随时间变化的所有信息。如果您有一个存储库的完整副本(通常称为“repo”),您可以查看项目的当前状态,但也可以查看项目以前所处的任何状态。
- 提交 —在 Git 中,历史由一系列保存在变更日志中的提交组成。每当您对项目进行一组有意义的更改时,您都应该提交它们,这样您就可以在将来将项目恢复到那个状态。
- 暂存区 —这就像一个用于版本控制的购物篮。在这里,您可以加载您希望在下一次提交时使用的更改集,因此,如果您编辑了三个文件,但希望对其中两个文件进行一次提交,对第三个文件进行另一次提交,您只需使用命令“暂存”前两个文件,然后使用适当的消息提交它们,然后分别添加和提交最后一个文件。
Git 入门
让我们用 Git 做一些实践。如果你用的是 windows,打开“Git Bash”程序,如果你用的是 Mac 或 Linux,只需打开一个终端窗口。重要的是不要在 windows 机器上只打开 Powershell 或默认终端——它不会正常工作。
转到您的主目录中的某个目录(这样您就有写权限)。让我们确保您还没有在一个属于 Git 存储库的目录中(不太可能,但是会发生):
> git status
fatal: not a git repository (or any of the parent directories): .git
很好。我们向 Git 询问我们所在的存储库的状态,它让我们知道我们不在 Git repo 中。这很好——在另一个中创建一个 Git repo 会让您和 Git 都感到困惑!
现在让我们创建一个新的 Git repo 和目录:
> git init my_first_repo
Initialized empty git repository in /Users/peterbell/Dropbox/code/my_first_repo/.git/
完美。所以它在我所在的目录下创建了一个存储库。让我们使用 Unix 的“更改目录(cd)”命令去那里:
**>** cd my_first_repo
my_first_repo git:(master)
好了,我的终端通过显示git:(master)
消息来告诉我什么时候我在 Git repo 中。让我们看看这个项目的状态:
> git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
酷毙了。如果您看到稍微不同的消息,不要担心——它们因操作系统和 Git 版本而异,但底线是 Git 告诉我们还没有任何提交,我们在“主”分支(主分支)上,这里没有任何文件要保存到版本控制中。
初始配置
让我们检查一下您是否有 Git 的基本配置,这样当您保存文件时,它就知道您的姓名和电子邮件地址。
> git config --global user.name
Peter Bell
使用上面的命令,我们可以访问您计算机上 Git 的配置设置。*--global*
标志意味着我们正在查看配置设置,这些设置将应用于您在这台机器上作为这个用户登录的所有项目。不常见的*--system*
标志用于访问机器上所有用户共享的设置。最后,*--local*
标志访问特定项目的设置——所以只有当您运行命令时,它才在 Git repo 中工作。
当您向 git config 传递一个不带值的键(在本例中是键)时,它返回现有的值。如果您还传递了一个值,它将设置该值。根据您的设置,您可能会看到您的名字,什么也没看到,一条 Git 没有正确设置的消息,甚至一条找不到文件的错误消息。如果你看到除了你的名字之外的任何东西,像这样设置你的名字:
> git config --global user.name ‘Your Name’
然后运行:
> git config --global user.name
Your Name
现在你应该看到你的名字了!让我们为您的电子邮件地址做同样的事情:
> git config --global user.email
this@that.com
如果它没有您想要的值,请将其设置为某个值。不需要引号:
> git config --global user.email this@that.com
> git config --global user.email
this@that.com
还有很多其他的设置,但是至少 Git 现在知道用什么名字和电子邮件地址来保存你的提交了!
添加一些文件
创建测试文件最简单的方法是使用 Unix 命令“touch”如果文件存在,它只会更新时间戳。如果没有,它将创建一个空白文件,然后我们可以添加到版本控制中。
所以让我们创建三个文件。它们不会有任何内容,但我们会给它们起一些名字,在进行真正的数据科学项目时可能会用到。
> touch index.ipynb
> touch import.py
> touch clean.py
> git status
On branch master
No commits yet
Untracked files: (use "git add <file>..." to include in what will be committed)
clean.py
import.py
index.ipynb
nothing added to commit but untracked files present (use "git add" to track)
好的,我们还是在主分支上。我们还没有提交(保存到 Git 中的永久历史中),这三个文件是“未被跟踪的”——在我们添加它们之前,Git 并没有真正关注它们。
现在假设我们想对 Jupyter 笔记本文件(index.ipynb)进行一次初始提交,然后对导入和清理脚本进行另一次提交。
> git add index.ipynb
> git status
On branch master
No commits yet
Changes to be committed
(use "git rm --cached <file>..." to unstage)
new file: index.ipynb
Untracked files:
(use "git add <file>..." to include in what will be committed)
clean.py
import.py
这告诉我们,当我们现在提交时,index.ipynb 文件将被保存。让我们这样做:
> git commit -m 'Add Jupyter Notebook file'
[master (root-commit) 998db10] Add Jupyter Notebook file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 index.ipynb
好吧,这是怎么回事?首先,我告诉 Git 提交—将这组更改保存到历史中。我向它传递了-m
标志,以传递提交消息。我在-m
后面加上了我希望与这个提交相关联的消息,用单引号或双引号括起来。提交消息的目的是让将来的任何人都更容易理解我做了什么更改以及为什么做这些更改。
重要的是要知道,每次提交都需要两件事——一条提交消息和至少一个添加、修改、重命名或删除的文件。根据您的操作系统和 Git 的版本,如果您没有传递提交消息,它要么会为您创建一个默认消息,要么会将您扔进您与 Git 一起使用的任何文本编辑器(注意,它可能有点像 vi )来添加提交消息。
而回应是什么意思?嗯,它告诉我们,我们仍然在主项目上,我们刚刚对这个项目进行了根(非常第一次)提交。它为我们提供了十六进制 SHA-1 哈希的前 7 个字符,这是 Git 存储库中每次提交的唯一标识符,它共享了我的提交消息以及有多少文件被更改。在本例中,我们添加了 1 个文件,但是没有添加或删除任何内容行,因为文件是空的。它还显示了提交中的文件(index.ipynb ),并显示“创建模式 100644 ”,您几乎可以忽略它。
酷毙了。我们现在的 Git 状态如何?
> git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
clean.py
import.py
nothing added to commit but untracked files present (use "git add" to track)
完美。所以它看到我们还有两个未被跟踪的文件。让我们将它们添加到临时区域:
> git add .
在 Git 中,有很多方法可以将文件添加到“暂存区”。您可以一次给它们命名一个(git add clean.py import.py
)。您可以使用 fileglob 模式(git add *.py
)匹配一组文件,或者您可以只添加 repo 中的所有文件(git add .
)。
无论采用哪种方法,都会将另外两个新文件添加到临时区域。
> git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: clean.py
new file: import.py
所以我们要做的就是承诺他们:
> git commit -m ‘Add import and cleaning scripts’
[master 625e7a1] Add import and cleaning scripts
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 clean.py
create mode 100644 import.py
很好——它在 master 上进行了一次新的提交(对我来说是625e7a1
—对你来说会有所不同,因为它部分基于这次和以前提交中使用的用户名和电子邮件),并添加了两个新文件(但没有文本行,因为在这个简单的教程示例中,它们都是空白文件)。
恭喜你!您刚刚创建了一个新的 Git repo,并暂存和添加了一些文件!
集结地是怎么回事?
现在,你可能会问一个非常合理的问题*“为什么我们必须运行两个单独的命令* *git add*
然后 *git commit*
来保存我们的工作?”
首先,这不是你必须一直做的事情。作为一名数据科学家,您将大部分时间花在修改文件上——通常是您的 Jupyter 笔记本和一些支持 Python 的文件。当你修改文件时,Git 给出了一个快捷方式git commit -am “your message here*"*
,它将在一行中添加修改的文件并提交它们,所以大多数时候你只需要键入一个命令。
但是 staging area 的真正强大之处在于,每当您做出多个更改,然后想要返回并将它们分类到单独的提交中时。
您可能会问*“为什么要有一堆不同的提交呢?”*这是一个特别常见的问题,来自那些使用过 subversion 之类的旧版本控制系统的人,在 subversion 中提交是一个较慢的过程,他们通常只是写一整天的代码,然后保存他们的更改,并显示一条类似于“我在周一做的事情”的信息!
创建有意义的提交消息的原因很重要,每种类型的更改都有一个提交(“更新的可视化”、“添加了一个分类数据的热编码”等),这样当您或您的团队回到您的日志时,就很容易理解您是如何到达这里的,并找到甚至恢复(撤销)任何有问题的东西。这和你不把你的变量命名为“a”、“b”和“c”是一个道理——计算机不会介意,但是下次你拿起代码并试图弄清楚它到底是什么的时候,它不会让你的生活变得更容易!
后续步骤
关于 Git 还有很多要学的。我们还没有介绍分支、从远程服务器推和拉、撤销更改、更高级的配置设置,或者如何检查以前的提交,但是一旦您理解了 staging area 的基本原理,您将会领先于许多已经使用 Git 一段时间的人。在接下来的几周里,请关注本系列的更多文章!
版本控制 ML 模型
dvc workflow from https://dvc.org
机器学习操作(姑且称之为 mlOps 在当前的流行语格局 xxOps 下)与传统的软件开发操作( devOps )有很大的不同。原因之一是 ML 实验除了代码(小的纯文本文件)之外,还需要大的数据集和模型工件。
这篇帖子提出了一个用 git 和 dvc ( 数据版本控制)对机器学习模型进行版本控制的解决方案。
此解决方案将提供以下功能:
- ML 模型具有可伸缩性、安全性、可用性和几乎无限的存储空间
- ML 模型受版本控制,即它的任何特定版本都可以被方便地标记和访问
- ML 模型的可审计性、透明性和可再现性可以通过版本控制数据集和分析代码来保证
- 基于现有的模型设置,新的实验可以被快速和协作地初始化
吉特和 DVC
该解决方案包括两层版本控制:
- git :处理代码和元数据(数据集和模型工件的)
- dvc :处理大型数据集和模型工件
首先,我们准备好项目文件夹并安装好工具。
# Download code
git clone [https://github.com/iterative/example-versioning.git](https://github.com/iterative/example-versioning.git)
cd example-versioning# install and initialize git
# install and initialize dvc ([https://dvc.org/doc/get-started/install](https://dvc.org/doc/get-started/install))
然后将 dvc 连接到后端存储,数据集和模型工件将实际存储在这里(在本例中为 AWS S3 )。
dvc remote add -d s3remote s3://[my-test-bucket-dvc](https://console.aws.amazon.com/s3/#)/myproject
现在,在我们将进行 ML 实验的示例版本化文件夹中,应该包含两个元数据子文件夹。
.dvc/
.git/
工作流程
下一步,我们使用来自 dvc.org 的数据和脚本训练一个模型
cd example-versioning# Install dependencies
pip install -r requirements.txt# Download data
cd example-versioning
wget [https://dvc.org/s3/examples/versioning/data.zip](https://dvc.org/s3/examples/versioning/data.zip)
unzip data.zip
rm -f data.zip# Build the ML model
python train.py
获得模型(model.h5)后,使用 dvc + git 工作流将其置于版本控制之下。
步骤 1:向 dvc 添加模型元数据
dvc add model.h5
输出:
可以观察到:
- “真实”模型存储在。dvc/cache/40
- 模型元数据 model.h5.dvc 记录它在哪里
步骤 2:通过将模型推送到后端存储来持久化模型
dvc push model.h5.dvc
在 s3 中,我们可以在模型元数据的指导下检查模型是否被正确存储
步骤 3:用 git 持久化模型元数据
模型元数据可以引导我们找到存储在后端存储中的真正的模型对象。为了防止丢失元数据,应该使用 git 将它添加到版本控制中。
git add .gitignore model.h5.dvc data.dvc metrics.json
git commit -m "model first version, 1000 images"
git tag -a "v1.0" -m "model v1.0, 1000 images"
这里可以使用“git 标签”来记录模型的版本。
第四步:随时访问模型
通过搜索 git branch 上的标签,很容易获取模型的特定版本。从 git 中,我们可以检查模型元数据。
git checkout tags/<tag_name> -b <branch_name>
根据元数据,我们可以找到模型对象,并使用命令将其下载到当前工作区
dvc pull model.h5.dvc
结论
同理,也可以解决机器学习实验的大数据集版本控制问题。解决 ML 管道挑战的其他类似工具例如有ML flowdatanami和 神圣 。
很有空间感!基于人工智能的视差 3D 视频。
三维本·伯恩斯效应
T 以下是我热爱 AI 开发的几个原因。新技术途径、意想不到的可能性、令人惊喜的品质。并且:团队工作。每个模型背后都有人,他们编写、测试、增强、审查模型。
人的因素是人工智能背后最重要的因素。
在这个 3D 本·伯恩斯模型的情况下也是如此。
本·伯恩斯效应。
本·伯恩斯效应 得名于电影纪录片导演本·伯恩斯,他用变焦和相机移动曝光静态照片来模拟视频镜头。
后来,这种效果通过视差效果得到了增强,静止图像被分成几层,类似于剧院舞台装饰。来模拟深度。并且虚拟摄像机在第三维中移动。它有各种各样的用途——用于视频游戏(模仿第三维),用于网站(沉浸式体验),用于电影(重复使用照片作为动态镜头)。
Layered scene — from a computer game The Whispered World (source).
这种方法早在 20 世纪 20-30 年代就已经被德国动画师洛塔·赖尼格采用了。这里你也可以看到这样的分层背景是如何在没有任何 CGI 的情况下实现的:
对于视频,您可以手动使用 Photoshop+Adobe After effects,或者像“Photomotion”这样的特殊解决方案来制作视差视频。就像我曾经做过的多语言项目一样。
但是——人工智能提供了新的可能性!
因此,一个研究团队:西蒙·尼克劳斯(波特兰州立大学)、龙脉(Adobe Research)、杨笈每(Adobe Research)和刘峰(波特兰州立大学)致力于基于深度学习的解决方案:
3D 本·伯恩斯效应。
论文:《单幅图像的 3D 本·伯恩斯效应》https://arxiv.org/abs/1909.05483
上下文感知修复和深度估计是关键词。
Source: Paper “3D Ken Burns Effect from a Single Image”
该模型可以识别背景,模拟深度,用内容敏感的填充来填充缺失的区域,添加新的角度——简而言之:用一张图像就可以制作一个空间 3D 视频镜头。
观看由撰写的 2 分钟的论文卡罗利·佐尔奈-费希尔视频解释这一模式(一如既往地提供大量信息):
本周,西蒙·尼克劳斯可能会从 Adobe 获得公开代码的批准(= > GitHub )。
从现在开始,每个人都可以尝试这个解决方案,比如人工智能研究员兼艺术家乔纳森·弗莱:
或者博客作者兼技术专家安迪·拜奥:
或者我自己:
它可以完美地处理街道的透视图像,也可以处理室内。
Andy Baio 在他的 Waxy.org 博客中发布了一个历史照片平行排列的图库(如果你想的话,也可以是 3d 立体图)。在这篇博文中,他还发布了他的 Colab 笔记本,并配有 3D 本·伯恩斯模型以供试用。电脑工程师马努·罗梅罗对笔记本进行了一些改进,包括多张图片上传。
这就是:一个 3D 本·伯恩斯效果的 Colab 笔记本。
这里是我的一些结果。请注意深度和 3D 尺寸的显著识别。
在评论中发布你自己视差照片的结果。
更新 1(2020 年 1 月 22 日)。
通过使用 #DeOldify 和 3D 本·伯恩斯效果,我们可以让一条古老的纽约街道重现生机:
正在使用的深度学习模型
towardsdatascience.com](/re-animated-history-6b5eb1a85efa)
更新 2(2020 年 1 月 22 日)
如果对“autozoom.py”中的参数进行微调,可以得到有趣的结果。例如,这些值
objectTo = process_autozoom({'dblShift': 10.0,'dblZoom': 10000000000000000000000000000000000000000000000000000000,'objectFrom': objectFrom})numpyResult = process_kenburns({'dblSteps': numpy.linspace(0.0, 8.0, 400).tolist(),'objectFrom': objectFrom,'objectTo': objectTo,'boolInpaint': True})
产生更长的摄像机飞行时间:
因为团队合作仍在继续——现在用创造性的方法!
基于 Python 和 Keras 的血管分割
Photo by Erica Leong on Unsplash
动机:
医学图像的自动分割是提取有用信息帮助医生做出诊断的重要步骤。例如,它可以用于分割视网膜血管,以便我们可以表示它们的结构并测量它们的宽度,这反过来可以帮助诊断视网膜疾病。
在这篇文章中,我们将实现一个神经基线,对视网膜血管图像进行图像分割。
数据集:
http://www.isi.uu.nl/Research/Databases/DRIVE/browser.php
我们使用 DRIVE(用于血管提取的数字视网膜图像)数据集进行所有实验。它是 40 个视网膜图像(20 个用于训练,20 个用于测试)的数据集,其中在像素级(参见上面的例子)对血管进行注释,以在图像的每个像素(I,j)处标记血管的存在(1)或不存在(0)。
问题设置:
问题:我们想给每个像素分配一个“1”标签,如果它是图像中血管的一部分,否则为“0”。
直觉 / 假设:相邻像素值对于对每个像素(I,j)进行预测很重要,所以我们应该考虑上下文。预测不依赖于图像上的特定位置,因此分类器应该具有某种平移不变性。
解决方案:用 CNN!我们将使用 U-net 架构来进行血管分割。它是一种广泛用于语义分割任务的架构,尤其是在医学领域。
型号:
U-net
U-net 架构是一个编码器-解码器,在编码器和解码器之间有一些跳跃连接。这种架构的主要优点是在对像素进行预测时能够考虑更广泛的背景。这得益于上采样操作中使用的大量通道。
输入图像处理:
我们在把它传送给 CNN 之前应用了这一系列的处理步骤。
- 标准化:我们将像素强度除以 255,因此它们在 0-1 的范围内。
- 裁剪:由于汇集操作,网络希望输入图像的每个维度都能被 2⁴整除,因此我们从每个图像中随机裁剪 64*64。
- 数据扩充:随机翻转(水平或垂直或两者)、随机剪切、随机平移(水平或垂直或两者)、随机缩放。仅在培训期间执行。
我们训练模型的三个变体:
- 预先接受过 ImageNet VGG 编码器+数据增强的培训。
- 从零开始训练+数据扩充。
- 在没有数据扩充的情况下从头开始训练。
我们将使用 AUC ROC 指标来比较这三个模型,并且我们将在评估中仅考虑视网膜掩膜内的像素(这意味着图像圆圈周围的黑边将不计算在内)。
结果:
- 从零开始训练+数据增强 AUC ROC : 0.9820
- 从零开始训练,没有增加 AUC ROC : 0.9806
- 预训练编码器+数据增强 AUC ROC : 0.9811
这三种变体的性能很接近,但在这种情况下,预训练似乎没有帮助,而数据扩充有一点帮助。
Best model predictions
上图中的预测看起来相当酷!😄
Predictions on top of ground Truth
我们还画出了预测和实际情况之间的差异:蓝色为假阴性,红色为假阳性。我们可以看到,该模型在预测只有一两个像素宽的精细血管时存在一些困难。
结论:
在这篇文章中,我们实现了一个神经网络来进行图像分割,应用于视网膜图像中的血管检测。我们获得的 AUC ROC 值为 0.9820 ,非常接近最先进水平(https://paperswithcode.com/search?q=vessel)。关于实验结果,我发现最有趣的是,对于像这样的一些任务,我们可以在少至 20 张图像上训练一个深度神经网络,并仍然获得良好的性能和非常酷的结果。
重现结果的代码可从这里获得:https://github.com/CVxTz/medical_image_segmentation
如果你有任何建议,请不要犹豫发表意见😸
VGG 神经网络:AlexNet 之后的下一步
2012 年 AlexNet 问世,是革命性的进步;它改进了传统的卷积神经网络(CNN),成为图像分类的最佳模型之一……直到 VGG 问世。
Photo by Taylor Vick on Unsplash
**AlexNet。**当 AlexNet 发布时,它轻松赢得了 ImageNet 大规模视觉识别挑战赛(ILSVRC ),并证明了自己是最有能力的对象检测模型之一。它的主要特性包括使用 ReLU 代替 tanh 函数、针对多个 GPU 的优化以及重叠池。它通过使用数据扩充和删除来解决过拟合问题。那么 AlexNet 到底出了什么问题?嗯,没有什么,比如说,特别“错误”的。人们只是想要更精确的模型。
**数据集。**图像识别的一般基线是 ImageNet,这是一个由超过 1500 万张图像组成的数据集,标记有超过 22,000 个类别。通过网络抓取图像和众包人类贴标机,ImageNet 甚至举办了自己的竞争:前面提到的 ImageNet 大规模视觉识别挑战(ILSVRC)。来自世界各地的研究人员面临着创新方法的挑战,以产生最低的前 1 名和前 5 名错误率(前 5 名错误率将是正确标签不是模型的五个最可能标签之一的图像的百分比)。比赛给出 120 万幅图像的 1000 类训练集,5 万幅图像的验证集,15 万幅图像的测试集;数据是丰富的。AlexNet 在 2012 年赢得了这场比赛,基于其设计的模型在 2013 年赢得了比赛。
Configurations of VGG; depth increases from left to right and the added layers are bolded. The convolutional layer parameters are denoted as “conv — ”. Image credits to Simonyan and Zisserman, the original authors of the VGG paper.
VGG 神经网络。虽然 AlexNet 以前的衍生产品专注于第一卷积层的较小窗口大小和步长,但 VGG 解决了 CNN 的另一个非常重要的方面:深度。让我们来看看 VGG 的建筑:
- 输入。 VGG 接受 224x224 像素的 RGB 图像。对于 ImageNet 竞赛,作者在每个图像中裁剪出中心 224x224 的补丁,以保持输入图像大小一致。
- **卷积层。**VGG 的卷积层使用非常小的感受域(3x3,仍然可以捕捉左/右和上/下的最小可能尺寸)。还有 1x1 卷积滤波器,它充当输入的线性变换,后跟一个 ReLU 单元。卷积步距固定为 1 个像素,以便在卷积后保持空间分辨率。
- 全连接层。 VGG 有三个全连接层:前两层各有 4096 个通道,第三层有 1000 个通道,每个类别一个通道。
- **隐藏层。**VGG 的所有隐藏层都使用 ReLU(Alex net 的一项巨大创新,减少了训练时间)。VGG 通常不使用本地响应标准化(LRN),因为 LRN 增加了内存消耗和训练时间,但准确性没有特别提高。
区别。 VGG 虽然基于 AlexNet,但它与其他竞争车型有几个不同之处:
- VGG 没有使用像 AlexNet 这样的大感受野(11x11,步幅为 4),而是使用非常小的感受野(3x3,步幅为 1)。因为现在有三个 ReLU 单元,而不是只有一个,所以决策函数更具区分性。参数也更少(27 倍通道数而不是 AlexNet 的 49 倍通道数)。
- VGG 合并了 1x1 卷积层,以在不改变感受野的情况下使决策函数更加非线性。
- 小尺寸卷积滤波器允许 VGG 具有大量的权重层;当然,层数越多,性能越好。不过,这并不是一个不常见的特性。GoogLeNet 是另一个使用深度 CNN 和小型卷积滤波器的模型,也在 2014 年的 ImageNet 竞赛中亮相。
Performance of VGG at multiple test scales. Image credits to Simonyan and Zisserman, the original authors of the VGG paper.
**战果。**在单个测试量表上,VGG 取得了 25.5%的前 1 名误差和 8.0%的前 5 名误差。在多个测试量表中,VGG 得到的前 1 名误差为 24.8%,前 5 名误差为 7.5%。VGG 还在 2014 年 ImageNet 竞赛中以 7.3%的前五名误差获得了第二名,提交后该误差降至 6.8%。
现在怎么办? VGG 是一种创新的物体识别模型,支持多达 19 层。作为一个深度 CNN,VGG 在 ImageNet 之外的许多任务和数据集上也优于基线。VGG 现在仍然是最常用的图像识别架构之一。
我在下面附上了一些有趣的资源
VGGNet vs ResNet
消失梯度问题的清晰答案!
Photo by Bench Accounting on Unsplash
"你能解释一下 VGGNet 和 ResNet 的区别吗?"是人工智能和机器学习领域的一个流行的面试问题。虽然答案就在网上,但我还没能找到一个简明扼要的答案。我们将从什么是 VGGNet 开始,它遇到了什么问题,以及 ResNet 是如何解决这个问题的。
VGGNet
VGG 代表视觉几何小组(一组牛津的研究人员开发了这种架构)。VGG 架构由块组成,其中每个块由 2D 卷积和最大池层组成。VGGNet 有两种风格,VGG16 和 VGG19,其中 16 和 19 分别是它们各自的层数。
Fig. 1 VGGNet architecture
在卷积神经网络(CNN)中,随着层数的增加,模型适应更复杂函数的能力也会增加。因此,层数越多越好(不要与人工神经网络混淆,后者不一定随着隐藏层数的增加而提供明显更好的性能)。所以现在你可以争论为什么不用 VGG20,或者 VGG50 或者 VGG100 等等。
嗯,有一个问题。
使用反向传播算法更新神经网络的权重。反向传播算法以减少模型损失的方式对每个权重进行小的改变。这是怎么发生的?它更新每个权重,以便在损失减少的方向上迈出一步。这个方向不过是这个重量的梯度(相对于损失)。
使用链式法则,我们可以找到每个重量的梯度。它等于(局部梯度)x(从前方流出的梯度),如图 2 所示。
Fig. 2 Flow of Gradients through a Neuron
问题来了。由于这个梯度不断流向初始层,这个值不断乘以每个局部梯度。因此,梯度变得越来越小,使得对初始层的更新非常小,大大增加了训练时间。
如果局部梯度不知何故变成了 1,我们就能解决这个问题。
瞧啊。输入 ResNet。
雷斯内特
局部梯度怎么会是 1,也就是说,哪个函数的导数总是 1?身份功能!
Fig. 3 Mathematics behind solving the Vanishing Gradient problem
因此,当这个梯度反向传播时,它的值不会减少,因为局部梯度是 1。
ResNet 架构,如下所示,现在应该可以很好地理解它是如何不允许渐变消失问题发生的。ResNet 代表残余网络。
Fig. 4 ResNet architecture
这些跳跃连接充当坡度高速公路,让坡度畅通无阻。现在你可以理解为什么 ResNet 有 ResNet50、ResNet101 和 ResNet152 这样的风格了。
我希望这篇文章对你有所帮助。
另一篇值得一读的文章:用 Keras 增强图像数据!
参考资料:
[1] 用于视觉识别的 CS231n 卷积神经网络作者 Andrej Karpathy。
2 K. Simonyan 和 A. Zisserman。用于大规模图像识别的非常深的卷积网络。2015 年在 ICLR。
3 K. He,X. Zhang,S. Ren 和 J. Sun,“用于图像识别的深度残差学习”,2016 年 IEEE 计算机视觉和模式识别会议(CVPR),拉斯维加斯,NV,2016 年,第 770-778 页。
[4] draw.io 供图。
视频:关于自动编码器的一切
深入了解应用程序
A 自动编码器是一个非常强大的工具,可以利用未标记的数据来解决各种问题——你经常会在获奖的 Kaggle 提交文件以及先进的行业解决方案中发现它们的组件。例如,您可以使用它们来学习“特征提取器”,以帮助构建更强大的分类器,发现异常,或进行缺失值插补。
该视频介绍了自动编码器,深入探讨了它们的工作原理,并解释了如何使用它们。
想了解更多类似内容,可以在 blog.zakjost.com订阅我的邮件列表或者关注WelcomeAIOverlords YouTube 频道 。
Python 中张量分解的视频分析
人工智能。深度学习。卷积神经网络。强化学习。这些都是机器学习领域的革命性进步,让不可能变成了可能。尽管有这些优点,也有缺点和限制。例如,神经网络由于需要庞大的训练集而容易过度拟合。它们通常是特定于任务的,并且它们的能力不能很好地转化到其他环境中。
Neural Network Illustration, by Arden Dertat, https://towardsdatascience.com/applied-deep-learning-part-1-artificial-neural-networks-d7834f67a4f6
虽然正在进行的研究解决了这些问题(我个人对 OpenAI 在人工通用智能方面的努力很感兴趣),但替代方法也可以拯救这些问题。例如,计算机视觉的主要挑战之一是涉及的数据量:一幅图像通常被表示为具有数百万元素的矩阵,而一个视频包含数千幅这样的图像。此外,这种数据中经常存在噪声。因此,减少维数的无监督学习技术是改进的潜在来源。
考虑到这一点,张量分解的概念在高维数据环境中尤其强大。在 Python 中实现这些思想来分析视频产生了重要的见解,并且可以在其他方法之前充当有用的预处理阶段。
高维数据
高维数据分析的概念指的是一组问题,其中特征的数量比观察值的数量大。在许多应用程序中(回归是最常见的),这会导致速度和模型学习问题,例如过度拟合或者甚至不可能产生模型。这在计算机视觉、材料科学甚至商业中很常见,因为互联网上捕获了大量数据。
一种解决方案是找到数据的低维表示,并在我们的模型中使用它作为训练观察值,因为维度减少缓解了上面列出的问题。这个低维空间通常包含大部分信息,因此是一个合适的替代物。样条、正则化和张量分解是这种方法的例子。我们将深入研究后一种方法,并看看它的一个应用。
Projecting 3D data onto a 2D plane. Credit: May Morrison
数学插曲
本文的核心概念是张量,它只是一个多维数组:
- 数字是一个零维张量
- 向量是一维张量
- 矩阵是二维张量
- 除此之外,我们只提到张量的维数
这种数据结构对于存储图像或视频特别有用。在传统的 RGB 模型中,单幅图像由一个 3D 张量表示:
- 每个像素在矩阵中具有(x,y)坐标;因此,矩阵的大小取决于图像的分辨率
- 每个颜色通道(红色、绿色、蓝色)都有自己的矩阵,矩阵中给定像素的值编码了这种特定颜色的强度
Representation of a 3D tensor. For an image, K = 3, and I and J depend on the resolution of the image. Credits: Kolda, Tamara G., and Brett W. Bader.
更进一步说,视频就是一系列的帧,每一帧都是一幅图像。这变得有点难以想象,但这可以存储在 4D 张量中:3 维用于存储单个帧,第四维编码时间的流逝。
Each slice is a 3D tensor for one frame, and there are multiple such slices over time. Credits: Kamran Paynabar
更具体地说,让我们以 60fps(每秒帧数)和 800 x 600 分辨率的 60 秒视频为例。这个视频可以存储在一个 800 x 600 x 3 x 3600 的张量中。因此它将有 50 亿个元素!这是太多的希望建立一个可靠的模型。这就是张量分解的用武之地。
有大量关于张量分解的文献,我向感兴趣的读者推荐科尔达和巴尔德关于这个主题的伟大研究。特别地,Tucker 分解有许多应用,例如张量回归,用张量作为目标或预测变量。关键是它允许提取核心张量,即原始数据的压缩版本。如果这让你想起了 PCA,那么你是正确的:Tucker 分解的步骤之一实际上是高阶奇异值分解,是 SVD 的扩展。
现有算法允许提取核心张量以及分解矩阵(在我们的应用中没有使用)。超参数是 n 秩。不涉及太多细节,主要思想是 n 秩值越高,分解越精确。n 阶也控制核心张量的大小。对于小的 n 秩,重建的张量可能不完全匹配原始张量,但是我们在降维方面获得了很多:权衡取决于手边的应用。
A, B and C are factorizing matrices while G is the core tensor, whose dimensions are specified by the n-rank. Credits: Kolda, Tamara G., and Brett W. Bader.
提取这个核心张量产生了重要的好处,正如我们在实际数据的应用中所看到的。
应用
举个玩具的例子,我用手机拍了三个 10s 的视频:
- 我喜欢的咖啡馆的露台
- 停车场
- 在我下午通勤期间,汽车在高速公路上行驶
我把它们(和开发笔记本)上传到了 GitHub 上。我的主要目标是确定我们是否可以根据相似性对潜在的配对进行严格的排序,假设停车场和通勤视频最相似。
我利用流行的 OpenCV Python 库在分析之前加载和操作这些数据。步骤如下:
- 创建 VideoCapture 对象并提取每个对象的帧数——我使用较短的视频来截断其他两个对象,以便有一个共同的比较基础
# Import libraries
import cv2
import numpy as np
import random
import tensorly as tl
from tensorly.decomposition import tucker# Create VideoCapture objects
parking_lot = cv2.VideoCapture('parking_lot.MOV')
patio = cv2.VideoCapture('patio.MOV')
commute = cv2.VideoCapture('commute.MOV')# Get number of frames in each video
parking_lot_frames = int(parking_lot.get(cv2.CAP_PROP_FRAME_COUNT))
patio_frames = int(patio.get(cv2.CAP_PROP_FRAME_COUNT))
commute_frames = int(commute.get(cv2.CAP_PROP_FRAME_COUNT))
- 在适当维度的张量中阅读它们。我选择 TensorLy 和 tensors 一起工作
# Create function to read all frames of a video in an array
def read_frames(video_capture, max_frames):
"""
INPUTS:
video_capture: an OpenCV VideoCapture object whose frames we want to read
max_frames: the maximum number of frames we want to read
OUTPUT:
array of all the frames until max_frames
"""
# Initialize empty array
frames_array = []
# Keep track of the frame number
frame_nb = 0
# iterate through the frames and append them to the array
while video_capture.isOpened() and frame_nb < max_frames:
ret, frame = video_capture.read()
if not ret:
break
frames_array.append(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_nb += 1
# release the video capture
video_capture.release()
cv2.destroyAllWindows()
# return the array
return(frames_array)# Read in all the videos
parking_lot_array = read_frames(video_capture=parking_lot, max_frames=commute_frames)patio_array = read_frames(video_capture=patio, max_frames=commute_frames)commute_array = read_frames(video_capture=commute, max_frames=commute_frames)# Create tensors from matrices
parking_lot_tensor = tl.tensor(parking_lot_array)
patio_tensor = tl.tensor(patio_array)
commute_tensor = tl.tensor(commute_array)
- 从这些张量中随机抽取 50 帧,以加速未来的运算
# Set the seed for reproducibility
random.seed(42)
random_frames = random.sample(range(0, commute_frames), 50)# Use these random frames to subset the tensors
subset_parking_lot = parking_lot_tensor[random_frames,:,:,:]
subset_patio = patio_tensor[random_frames,:,:,:]
subset_commute = commute_tensor[random_frames, :, :, :]# Convert three tensors to double
subset_parking_lot = subset_parking_lot.astype('d')
subset_patio = subset_patio.astype('d')
subset_commute = subset_commute.astype('d')
经过这些步骤,就有了三个 50 x 1080 x 1920 x 3 的张量。我们可以继续分析。
结果
为了确定这些视频彼此之间的相似程度,我们需要一种方法来对它们进行排序。两个张量之差的 L2 范数是相似性的常用度量。较小的值与较大的相似性相关联。数学上,张量的范数是
Each I represents a given dimension, and x is a given element, identified by position
因此,差的范数类似于欧几里德距离。
用全张量实现这一点产生了不令人满意的结果。
# Parking and patio
parking_patio_naive_diff = tl.norm(subset_parking_lot - subset_patio)# Parking and commute
parking_commute_naive_diff = tl.norm(subset_parking_lot - subset_commute)# Patio and commute
patio_commute_naive_diff = tl.norm(subset_patio - subset_commute)
将相似性显示为表格:
不仅配对之间没有明确的排名,而且停车场和天井视频也似乎最相似,这与最初的假设形成了鲜明对比。这就是塔克分解发挥作用的地方。
TensorLy 库使得分解张量变得相对容易(尽管很慢):我们需要的只是张量和它的 n 阶。尽管 AIC 准则是寻找该参数最优值的常用方法,但在这种特定情况下,达到最优实际上是不必要的,因为目的是进行比较。我们需要一个跨越所有三个变量的公共 n 秩。因此,我们选择 n-rank = [2,2,2,2],这是精度和速度之间的一个很好的折衷。作为旁注,n-rank = [5,5,5,5]超过了 LAPACK(引擎盖下的线性代数例程)的能力,这表明这些方法在计算上是多么昂贵。
一旦我们提取了核心张量,我们可以做同样的比较。
# Get core tensor for the parking lot video
core_parking_lot, factors_parking_lot = tucker(subset_parking_lot, ranks = [2,2,2,2])# Get core tensor for the patio video
core_patio, factors_patio = tucker(subset_patio, ranks = [2,2,2,2])# Get core tensor for the commute video
core_commute, factors_commute = tucker(subset_commute, ranks = [2,2,2,2])# Compare core parking lot and patio
parking_patio_diff = tl.norm(core_parking_lot - core_patio)
int(parking_patio_diff)# Compare core parking lot and commute
parking_commute_diff= tl.norm(core_parking_lot - core_commute)
int(parking_commute_diff)# Compare core patio and commute
patio_commute_diff = tl.norm(core_patio - core_commute)
int(patio_commute_diff)
再次在表格中显示结果:
这些结果是有意义的:虽然天井视频与停车场和通勤视频不一样,但后两者在数量级上是最接近的。
结论
在本文中,我展示了无监督学习方法如何为我们的数据提供洞察力。只有在通过 Tucker 分解降低维度以从视频中提取核心张量之后,它们的比较才有意义。我们确认停车场和通勤视频最相似。
随着视频成为越来越常见的数据源,这项技术有许多潜在的应用。我想到的第一件事(由于我对电视的热情以及视频流媒体服务如何使用数据)是通过检查电影/电视节目的预告片或一些关键场景如何彼此相似来改进现有的推荐系统。第二个是在材料科学领域,加热金属的红外视频可以根据其与基准的相似性进行分类。为了使这些方法完全可扩展,计算成本应该得到解决:Tucker 分解在我的计算机上对三个 10 秒的视频很慢。并行化是一种潜在的加速方法。
除了这些直接的应用之外,这种技术与介绍中提出的一些方法结合起来也是有前途的。使用核心张量而不是完整的图像或视频作为神经网络中的训练点,可以帮助解决过度拟合问题并加快训练速度,通过解决两个主要问题来推动该方法。
[1]:科尔达,塔玛拉 g,和布雷特 w .巴德。"张量分解和应用."暹罗评论 51.3(2009):455–500。