学习谷歌云助理工程师认证
如何学习(并通过)谷歌的云认证考试?
介绍
随着云的使用越来越多,谷歌的云助理工程师(ACE)认证提供了一个展示你在云工程和云开发方面的才能的好方法。
这篇文章提供了一些资源和建议来帮助你准备 ACE 考试。
一.评价
你应该参加这个考试吗?
1.云工程适合你吗?
如果云计算听起来与你正在做或想要做的工作相关,那么云工程是你想要拥有的技能。
- 如果你是谷歌云平台(GCP)的新手: 谷歌在 Coursera 上的在线课程是一个很好的学习工具,会给你在云中构建的技能。
- 如果你已经与谷歌云平台(GCP)互动过:
学习并参加考试是完善你的技能组合并向你介绍 GCP 提供的你可能不知道的元素的一种可靠方式。(例如。谷歌的私有 ip 网络,以减少延迟和成本。)
2.认证有益吗?
- 验证你的技能组合
认证是对你技能组合的一个很好的验证,无论是内在的(你会对你的技能组合更有信心)还是外在的(你可以证明你知道你在说什么)。 - 增加就业能力 这个挺明显的。
- 进入谷歌认证目录
通过这次考试,你将获得谷歌认证目录的排名。你还将获得许多 GCP 产品的提前发布。 - 截止日期作为动力 认证考试可以作为你学习目标的动力&截止日期。
3.你能承受现在准备考试的压力吗?
为考试学习是有压力的。问问你自己,你现在是否能承受那么大的压力。
提示:在你准备考试的时候,制定一个计划来管理额外的压力。(例如。如果你生病了,你的日程/工作量会有什么变化。)
4.被你的目标所激励。
保持动力很重要。保持专注于你的目标——无论是学习新技能、创造新项目、获得新工作还是证明你的能力——并在你的学习计划中加入这个目标。
二。关于考试:
考试很难。许多问题将挑战你的知识和应试技巧。
1。谷歌 考试指南
考试内容的布局。
2。谷歌的 样本考试
这个示例与考试结构和问题风格非常相似。我建议在开始学习之前参加这个模拟考试*——这样你就知道如何获取信息。*
注:这是网上唯一可用的实践考试(截至 2020 年 8 月 20 日)。
三。准备考试
为例题学习为你提供了基于考试材料的知识。准备考试为你提供了通过考试所需的技能和领域知识。
在 Unsplash 上由 NESA 拍摄的制造商
第一步:注册参加考试
给自己一个期限。你随时可以重新安排。
报名费用: $125 美元
**改期费用:**考试前 72 小时免费。那么,50 美元注意:我在截止日期前工作得很好——注册是我激励自己的方式。
步骤 2:查看考试指南
复习考试指南,这样你就知道学什么了。
步骤 3:参加模拟考试
这样你就能了解考试风格,知道该期待什么。
**提示:**在开始学习之前参加模拟考试。这会让你对提问方式有所准备。另外,一旦你完成了学习,你几乎肯定会忘记问题的答案…
第四步:在 Coursera 上参加谷歌的云工程课程(谷歌提供)。
这门深入的课程将带你了解考试所需的一切(以及更多)。它提供讲座和实验室实践经验。参加完这个课程后,我能够轻松地部署和扩展应用程序。
**注意:**这是一个庞大的课程,将花费你 2-3 周的时间,每周 10 个小时。
第五步:重考样题。
看你对内容的了解程度。你应该花更多的时间学习什么。
**注意:**最好是全面的,因为标准化考试中的大多数问题都是低水平的,涵盖了广泛的知识。确保你的后期学习集中在你的弱点上。
第六步:再次复习课程内容。
- 快速浏览 Coursera 上的课程。
- 创建学习笔记。
- 经常复习这些学习笔记。
小贴士:考虑在吃早餐的时候复习你的学习笔记。(很棒的大脑热身。)
第七步:考试前一天停止学习。
事实证明,临时抱佛脚对结果有负面影响。在考试的前一天,帮自己一个忙,放松一下。
照片由 Shutterstock 拍摄
四。关键概念
我在参加考试时签署了保密协议,不会泄露任何考试问题。也就是说,这里有一些你需要很好了解的领域。
InternationalAssociationofMachinists 国际机械师协会
- 规则层次结构
- 不同类型的角色*(原始/预定义/定制)*
- 特定权限之间的差异*(例如云存储创建者与查看者。)*
虚拟机(虚拟机)
- 虚拟机类型(托管与非托管实例)
- 可抢占虚拟机的用途
- 使用定制机器类型+如何重复使用它们*(图像和快照)*
- 管理虚拟机。(如何开关等等。)
VPC ( 虚拟私有云)联网
- 如何配置防火墙规则
- 子网的角色和功能
- 如何设置负载平衡器
- 如何连接 VPN(虚拟专用网络)
- 每种不同类型的对等
云存储
- 不同的储物选项以及每种储物选项的使用时间
- 存储类别以及如何在它们之间转换
- 何时使用 BigQuery
云函数
- 云功能的用例是什么?
- 它们的局限性是什么?
库伯内特发动机
- Kubernetes 的用例是什么?
- 与 Kubernetes 合作
- 自动缩放是如何执行的?
- 如何启用互联网连接
堆栈驱动
- stackdriver 有哪些用例?
- 它的局限性是什么?
- 创建和使用警报
云 SDK
- 如何在命令行界面执行基本命令?(不需要了解它的冷,只是松松地熟悉它。)
照片由 Keegan Houser 在 Unsplash 上拍摄
动词 (verb 的缩写)考试技巧
以下是一些有助于你参加考试的应试技巧:
1.跳过困难的问题:
如果一个问题难倒了你,跳过它!考试软件给你选择*【标记】*一个问题供以后复习。不要把时间花在那些旨在迷惑你的问题上。
2.永远不要留下空白答案
阅读问题前选择一个选项。*(回答错误没有处罚。)*如果你跳过一个硬 Q,在继续之前随机选择一个选项。
3.识别问题中的问题:
有时候问题包含很多信息*(意在迷惑你)*。学会识别被询问的内容,而不是被告知的内容。
举个例子: 一个管理员不小心删除了他们的数据库。在混乱中,他们恢复了错误的数据库,现在网络崩溃了。您如何确保新数据库的安全配置?
- 这个问题实际上是在问“如何为恢复的数据库设置安全配置。”
- 关于意外恢复版本+网络崩溃的信息是无关紧要的。
4.识别错误答案
不管是什么问题,有些答案都是错误的(并且可以被删除)。这些错误答案有几种形式:
- 永远错误的——这些都是旨在迷惑你的错误陈述。(例如。更改无法重新定位的服务器的位置。)
- 有时是假的——这些是规则的例外。仅当“例外”是问题的一部分时,才选择此答案。(例如。打破永不删除此服务器的规则,以便您可以将此服务器的位置重置为高速连接。)
- 永远正确 —这些答案是正确的陈述,但并不总能解决你的问题。如果你发现了几个“永远正确”的答案,重新评估这个问题,看看它真正想要的是什么。(例如。更改网络设置以允许此用户 ip 地址的流量。)
5。留意时钟
不要在一个问题上花太多时间。如果某件事花费的时间比你想要的多,把它标记出来,以后再继续做。
6.休息一下你的眼睛
每隔几分钟就移开视线,放松眼部肌肉。这会帮助你保持专注。
7.沉思
不时花 15-30 秒闭上眼睛,慢慢呼吸。这种努力的时间成本会让你获得平静和放松。
8.审查标记的问题(迭代)
通过复习标记的问题来重复你的考试。如果你能解决它,取消标记 q。如果不能,留下标记,继续前进。这样做一次——然后检查你的答案(# 9)——然后做第二次。
9.检查您的答案
对于每个问题,首先阅读你选择的答案,然后是问题,最后是答案。*(这允许您验证您的答案,并根据问题进行确认。)*如果你发现自己第二次怀疑自己,标记问题,继续前进。重复所有标记的 Q,直到完成或时间用完。
不及物动词更多资源
以下是您可能会用到的一些附加资源:
结论:
祝你考试顺利!
第 2 部分:STUMPY 基础知识
用 STUMPY 分析图案和异常
(图片由阿诺·梅瑟尔拍摄)
整体大于部分之和
(图片由作者提供)
STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!
注:这些教程最初出现在 STUMPY 文档 中。
第 1 部分:矩阵轮廓图
第 2 部分: STUMPY 基础知识
第 3 部分:时间序列链
第 4 部分:语义分割
第 5 部分:用 STUMPY 快速近似矩阵轮廓图
第 6 部分:用于流式时间序列数据的矩阵轮廓图
第 7 部分:用 STUMPY 快速模式搜索 10: 发现多维时间序列模体
第 11 部分:用户引导的模体搜索
第 12 部分:机器学习的矩阵轮廓
用残肢分析图案和异常
在这篇博客中,我们将使用 STUMPY 包来看看研究论文中的一些主要内容:矩阵概要 I & 矩阵概要 II 。
为了探索基本概念,我们将使用 workhorse stumpy.stump()
函数来寻找有趣的主题(模式)或不一致(异常/新奇),并用两个不同的时间序列数据集来演示这些概念:
- Steamgen 数据集
- 纽约市出租车乘客数据集
stumpy.stump()
是流行的 STOMP 算法的 Numba JIT 编译版本,在最初的 Matrix Profile II 论文中有详细描述。stumpy.stump()
能够进行并行计算,它对特定时间序列内的模式和异常值进行有序搜索,并利用一些计算的局部性来最小化运行时间。
入门指南
让我们导入加载、分析和绘制数据所需的包。
%matplotlib inline
import pandas as pd
import stumpy
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as dates
from matplotlib.patches import Rectangle
import datetime as dt
plt.rcParams["figure.figsize"] = [20, 6] # width, height
plt.rcParams['xtick.direction'] = 'out'
什么是主题?
时间序列基序是在一个较长的时间序列中发现的近似重复的子序列。能够说一个子序列是“近似重复的”需要你能够将子序列相互比较。在 STUMPY 的情况下,时间序列中的所有子序列可以通过计算成对的 z 归一化欧几里得距离进行比较,然后只存储其最近邻的索引。这个最近邻距离向量被称为matrix profile
,时间序列内每个最近邻的索引被称为matrix profile index
(参见第 1 部分:矩阵轮廓进行全面回顾)。幸运的是,stumpy.stump()
函数接受任何时间序列(具有浮点值),并计算矩阵轮廓和矩阵轮廓索引,反过来,人们可以立即找到时间序列主题。让我们看一个例子:
加载 Steamgen 数据集
该数据是使用模糊模型生成的,该模型用于模拟位于伊利诺伊州香槟市的 Abbott 电厂的蒸汽发生器。我们感兴趣的数据特性是输出蒸汽流量遥测,单位为 kg/s,数据每三秒“采样”一次,共有 9600 个数据点。
steam_df = pd.read_csv("https://zenodo.org/record/4273921/files/STUMPY_Basics_steamgen.csv?download=1")
steam_df.head()drum pressure excess oxygen water level steam flow
320.08239 2.506774 0.032701 9.302970
1321.71099 2.545908 0.284799 9.662621
2320.91331 2.360562 0.203652 10.990955
3325.00252 0.027054 0.326187 12.430107
4326.65276 0.285649 0.753776 13.681666
可视化 Steamgen 数据集
plt.suptitle('Steamgen Dataset', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Steam Flow', fontsize='20')
plt.plot(steam_df['steam flow'].values)
(图片由作者提供)
花一点时间,用肉眼仔细检查上面的情节。如果你被告知有一个模式是近似重复的,你能发现它吗?即使对于计算机来说,这也是非常具有挑战性的。以下是您应该寻找的内容:
手动寻找主题
m = 640
fig, axs = plt.subplots(2)
plt.suptitle('Steamgen Dataset', fontsize='30')
axs[0].set_ylabel("Steam Flow", fontsize='20')
axs[0].plot(steam_df['steam flow'], alpha=0.5, linewidth=1)
axs[0].plot(steam_df['steam flow'].iloc[643:643+m])
axs[0].plot(steam_df['steam flow'].iloc[8724:8724+m])
rect = Rectangle((643, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
rect = Rectangle((8724, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[1].set_xlabel("Time", fontsize='20')
axs[1].set_ylabel("Steam Flow", fontsize='20')
axs[1].plot(steam_df['steam flow'].values[643:643+m], color='C1')
axs[1].plot(steam_df['steam flow'].values[8724:8724+m], color='C2')
(图片由作者提供)
上面突出显示了我们正在寻找的基序(图案),但仍然很难确定橙色和绿色的子序列是否匹配(上图),也就是说,直到我们放大它们并将子序列彼此重叠(下图)。现在,我们可以清楚地看到,母题非常相似!计算矩阵轮廓的基本价值在于,它不仅能让你快速找到基序,还能识别时间序列中所有子序列的最近邻。请注意,我们实际上没有做任何特别的事情来定位主题,除了我们从原始文件中抓取位置并绘制它们。现在,让我们获取 steamgen 数据,并对其应用stumpy.stump()
函数:
使用 STUMP 找到主题
m = 640
mp = stumpy.stump(steam_df['steam flow'], m)
stump
需要两个参数:
- 时间序列
- 一个窗口大小,
m
在这种情况下,基于一些领域的专业知识,我们选择了m = 640
,这大约相当于半小时的窗口。同样,stump
的输出是一个数组,它包含所有的矩阵轮廓值(即,到最近邻居的 z 归一化欧几里德距离)和矩阵轮廓索引,分别在第一和第二列(我们现在忽略第三和第四列)。为了确定基元的索引位置,我们需要找到矩阵轮廓mp[:, 0]
具有最小值的索引位置:
motif_idx = np.argsort(mp[:, 0])[0]
print(f"The motif is located at index {motif_idx}")The motif is located at index 643
有了这个motif_idx
信息,我们还可以通过交叉引用矩阵轮廓索引来识别其最近邻居的位置,mp[:, 1]
:
nearest_neighbor_idx = mp[motif_idx, 1]
print(f"The nearest neighbor is located at index {nearest_neighbor_idx}")The nearest neighbor is located at index 8724
现在,让我们将所有这些放在一起,并在原始数据旁边绘制矩阵图:
fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})
plt.suptitle('Motif (Pattern) Discovery', fontsize='30')axs[0].plot(steam_df['steam flow'].values)
axs[0].set_ylabel('Steam Flow', fontsize='20')
rect = Rectangle((643, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
rect = Rectangle((8724, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[1].set_xlabel('Time', fontsize ='20')
axs[1].set_ylabel('Matrix Profile', fontsize='20')
axs[1].axvline(x=643, linestyle="dashed")
axs[1].axvline(x=8724, linestyle="dashed")
axs[1].plot(mp[:, 0])
(图片由作者提供)
我们了解到的是,来自矩阵轮廓的全局最小值(垂直虚线)对应于构成基序对的两个子序列的位置!并且这两个子序列之间的精确 z 归一化欧几里德距离是:
mp[:, 0].min()5.49161982776594
因此,这个距离不是零,因为我们之前看到两个子序列不是完全相同的匹配,但是,相对于矩阵分布图的其余部分(即,与矩阵分布图的平均值或中值相比),我们可以理解这个基序是非常好的匹配。
使用 STUMP 查找异常
相反,矩阵轮廓中的最大值(根据上述stumpy.stump()
计算)为:
print(f"The discord is located at index {discord_idx}")The discord is located at index 3864
与这种不和谐最近的邻居有一段相当远的距离:
nearest_neighbor_distance = mp[discord_idx, 0]
print(f"The nearest neighbor subsequence to this discord is {nearest_neighbor_distance} units away")The nearest neighbor subsequence to this discord is 23.476168367301987 units away
位于这个全局最大值的子序列也被称为不一致、新奇或“潜在异常”:
fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})
plt.suptitle('Discord (Anomaly/Novelty) Discovery', fontsize='30')axs[0].plot(steam_df['steam flow'].values)
axs[0].set_ylabel('Steam Flow', fontsize='20')
rect = Rectangle((3864, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[1].set_xlabel('Time', fontsize ='20')
axs[1].set_ylabel('Matrix Profile', fontsize='20')
axs[1].axvline(x=3864, linestyle="dashed")
axs[1].plot(mp[:, 0])
(图片由作者提供)
为了进一步发展/加强我们不断增长的直觉,让我们继续探索另一个数据集!
加载纽约市出租车乘客数据集
首先,我们将下载代表 2014 年秋季 75 天内纽约市出租车乘客半小时平均人数的历史数据。
我们提取该数据并将其插入到一个 Pandas dataframe 中,确保时间戳存储为 datetime 对象,并且值的类型为 float64 。请注意,我们将进行比上面多一点的数据清理,以便您可以看到一个包含时间戳的示例。但是请注意,在计算矩阵概要文件时,stumpy.stump()
实际上根本不使用或者不需要时间戳列。
taxi_df = pd.read_csv("https://zenodo.org/record/4276428/files/STUMPY_Basics_Taxi.csv?download=1")
taxi_df['value'] = taxi_df['value'].astype(np.float64)
taxi_df['timestamp'] = pd.to_datetime(taxi_df['timestamp'])
taxi_df.head() timestamp value
2014-10-01 00:00:00 12751.0
2014-10-01 00:30:00 8767.0
2014-10-01 01:00:00 7005.0
2014-10-01 01:30:00 5257.0
2014-10-01 02:00:00 4189.0
可视化出租车数据集
# This code is going to be utilized to control the axis labeling of the plots
DAY_MULTIPLIER = 7 # Specify for the amount of days you want between each labeled x-axis tickx_axis_labels = taxi_df[(taxi_df.timestamp.dt.hour==0)]['timestamp'].dt.strftime('%b %d').values[::DAY_MULTIPLIER]
x_axis_labels[1::2] = " "
x_axis_labels, DAY_MULTIPLIERplt.suptitle('Taxi Passenger Raw Data', fontsize='30')
plt.xlabel('Window Start Date', fontsize ='20')
plt.ylabel('Half-Hourly Average\nNumber of Taxi Passengers', fontsize='20')
plt.plot(taxi_df['value'])plt.xticks(np.arange(0, taxi_df['value'].shape[0], (48*DAY_MULTIPLIER)/2), x_axis_labels)
plt.xticks(rotation=75)
plt.minorticks_on()
plt.margins(x=0)
plt.show()
(图片由作者提供)
似乎在一天和七天之间有一个普遍的周期性,这可能是因为更多的人在白天而不是晚上使用出租车,并且有理由说大多数周都有类似的出租车乘客模式。此外,也许在接近 10 月底的窗口右侧有一个异常值,但除此之外,仅从原始数据无法得出任何结论。
生成矩阵配置文件
同样,定义窗口大小,m
,通常需要一定程度的领域知识,但是我们稍后将展示stumpy.stump()
对于该参数的变化是健壮的。因为这个数据是半小时采集一次的,所以我们选择了一个值m = 48
来表示正好一天的跨度:
m = 48
mp = stumpy.stump(taxi_df['value'], m=m)
可视化矩阵轮廓
plt.suptitle('1-Day STUMP', fontsize='30')
plt.xlabel('Window Start', fontsize ='20')
plt.ylabel('Matrix Profile', fontsize='20')
plt.plot(mp[:, 0])plt.plot(575, 1.7, marker="v", markersize=15, color='b')
plt.text(620, 1.6, 'Columbus Day', color="black", fontsize=20)
plt.plot(1535, 3.7, marker="v", markersize=15, color='b')
plt.text(1580, 3.6, 'Daylight Savings', color="black", fontsize=20)
plt.plot(2700, 3.1, marker="v", markersize=15, color='b')
plt.text(2745, 3.0, 'Thanksgiving', color="black", fontsize=20)
plt.plot(30, .2, marker="^", markersize=15, color='b', fillstyle='none')
plt.plot(363, .2, marker="^", markersize=15, color='b', fillstyle='none')
plt.xticks(np.arange(0, 3553, (m*DAY_MULTIPLIER)/2), x_axis_labels)
plt.xticks(rotation=75)
plt.minorticks_on()
plt.show()
(图片由作者提供)
了解矩阵配置文件
让我们明白我们在看什么。
最低值
最低值(空心三角形)被认为是基元,因为它们代表具有最小 z 归一化欧几里得距离的一对最近邻子序列。有趣的是,两个最低的数据点正好相隔 7 天,这表明,在这个数据集中,除了更明显的一天的周期性之外,可能还有七天的周期性。
最高值
那么最高的矩阵轮廓值(实心三角形)呢?具有最高(局部)值的子序列实际上强调了它们的唯一性。我们发现前三个峰值恰好分别与哥伦布日、夏令时和感恩节的时间相对应。
不同的窗口大小
如上所述,stumpy.stump()
对于窗口大小参数m
的选择应该是稳健的。下面,我们通过运行不同窗口大小的stumpy.stump()
来演示操作窗口大小如何对你生成的矩阵轮廓产生小的影响。
days_dict ={
"Half-Day": 24,
"1-Day": 48,
"2-Days": 96,
"5-Days": 240,
"7-Days": 336,
}
days_df = pd.DataFrame.from_dict(days_dict, orient='index', columns=['m'])
days_df.head() m
Half-Day 24
1-Day 48
2-Days 96
5-Days 240
7-Days 336
我们特意选择了与人类可以选择的相当直观的白天长度相对应的时间跨度。
fig, axs = plt.subplots(5, sharex=True, gridspec_kw={'hspace': 0})
fig.text(0.5, -0.1, 'Subsequence Start Date', ha='center', fontsize='20')
fig.text(0.08, 0.5, 'Matrix Profile', va='center', rotation='vertical', fontsize='20')
for i, varying_m in enumerate(days_df['m'].values):
mp = stumpy.stump(taxi_df['value'], varying_m)
axs[i].plot(mp[:, 0])
axs[i].set_ylim(0,9.5)
axs[i].set_xlim(0,3600)
title = f"m = {varying_m}"
axs[i].set_title(title, fontsize=20, y=.5)
plt.xticks(np.arange(0, taxi_df.shape[0], (48*DAY_MULTIPLIER)/2), x_axis_labels)
plt.xticks(rotation=75)
plt.suptitle('STUMP with Varying Window Sizes', fontsize='30')
plt.show()
(图片由作者提供)
我们可以看到,即使窗口大小不同,我们的峰值仍然突出。但是看起来好像所有的非峰值都在向彼此靠拢。这就是为什么在运行stumpy.stump()
之前了解数据环境非常重要的原因,因为它有助于获得一个可以捕捉数据集中重复模式或异常的窗口大小。
GPU-STUMP —使用 GPU 加快 STUMP 速度
当时间序列中的数据远远超过几千个数据点时,您可能需要提高速度来帮助分析数据。幸运的是,你可以试试stumpy.gpu_stump()
,一种超快速的 GPU 驱动的stumpy.stump()
的替代品,它提供几百个 CPU 的速度,并提供与stumpy.stump()
相同的输出:
**import** **stumpy**mp = stumpy.gpu_stump(df['value'], m=m) *# Note that you'll need a properly configured NVIDIA GPU for this*
事实上,如果你不处理 PII/SII 的数据,那么你可以在 Google Colab 上用这个笔记本来试试stumpy.gpu_stump()
。
树桩—分布式树桩
或者,如果您只能访问一个 CPU 集群,并且您的数据需要留在防火墙后面,那么stumpy.stump()
和stumpy.gpu_stump()
可能不足以满足您的需求。相反,您可以尝试stumpy.stumped()
函数,它是stumpy.stump()
的分布式并行实现,依赖于 Dask distributed:
**import** **stumpy**
**from** **dask.distributed** **import** Clientdask_client = Client()mp = stumpy.stumped(dask_client, df['value'], m=m) *# Note that a dask client is needed*
摘要
就是这样!现在,您已经加载了一个数据集,使用 STUMPY 包在stumpy.stump()
中运行它,并且能够提取两个不同时间序列中现有模式和异常的多个结论。您现在可以导入这个包并在您自己的项目中使用它。编码快乐!
资源
Matrix Profile I
Matrix Profile II
STUMPY Matrix Profile 文档
STUMPY Matrix Profile Github 代码库
← 第一部分:矩阵简介 | 第三部分:时间序列链 →
线条画的风格转换
用 ML 从线条画生成图像
在这里,我将以类似教程的方式介绍我最近做的一个机器学习项目。这是一种从线条画中以艺术风格生成完整图像的方法。
资料组
我在 Imagenet 数据集的 10%上进行训练。这是计算机视觉任务中常用的基准数据集。Imagenet 数据集不是公开可用的;它仅限于那些需要使用它来计算性能基准以便与其他方法进行比较的研究人员。因此,通常要求您提交一份申请表。但是如果你只是随便用的话,这里有。除了个人项目之外,我不会用这个做任何事情。请注意,数据集非常大,这就是为什么我只用了 1/10 来训练我的模型。它由 1000 个类组成,所以我用了其中的 100 个图像类进行训练。
几周前,我在一个不同的个人项目中使用了 Imagenet,所以我已经在 Google Drive 中收集了大量文件。然而,不幸的是,将这 140,000 张图片上传到 Google Drive 需要大约 20 个小时。有必要在 Google Colab 的在线 GPU 上训练模型,但这需要你将图像上传到 Google Drive,因为你没有在本地托管你的编码环境。
数据输入管道
我有一个 Colab Pro 帐户,但即使有额外的 RAM,我也肯定无法处理 140,000 个线条画,每个都是 256x256 像素大小,以及它们的 256x256 像素彩色对应物。因此,我必须使用 TensorFlow 数据输入管道随时加载数据。
在我们开始设置管道之前,让我们导入所需的库(这些是我的代码中的所有导入语句):
import matplotlib.pyplot as plt
import numpy as np
import cv2
from tqdm.notebook import tqdm
import glob
import random
import threading, queuefrom tensorflow.keras.models import *
from tensorflow.keras.layers import *
from tensorflow.keras.optimizers import *
from tensorflow.keras.regularizers import *
from tensorflow.keras.utils import to_categorical
import tensorflow as tf
现在,让我们加载指向 Imagenet 子集中每个图像的文件路径,假设您已经将它们上传到适当目录结构下的 Drive,并将 Google Colab 实例连接到 Google Drive。
filepaths = glob.glob("drive/My Drive/1-100/**/*.JPEG")# Shuffle the filepaths
random.shuffle(filepaths)
如果你不想使用glob
模块,你可以使用os
库中的函数,这样通常效率更高。
这里有几个我需要的助手函数:
- 标准化数据
- 色调分离图像数据
def normalize(x):
return (x - x.min()) / (x.max() - x.min())
色调分离
上述色调分离过程将图像作为输入,并通过将颜色值舍入到某个最接近的值,将平滑的渐变转换为更清晰分离的颜色部分。这里有一个例子:
色调分离
正如您所看到的,生成的图像具有不太平滑的渐变,这些渐变被替换为单独的颜色部分。我实现这一点的原因是因为我可以将输出图像限制为一组颜色,允许我将学习问题格式化为图像中每个像素的分类问题。对于每一种可用的颜色,我分配一个标签。该模型通过最后一个通道num_colors
输出由 softmax 函数激活的形状(height, width, num_colors)
的图像。给定一个变量num_values
,我允许颜色值限制在np.arange(0, 255, 255 / num_values)
的所有 RGB 组合。这意味着num_colors = num_values ** 3
。这里有一个例子:
色调分离
作为我如何实现这一点的例子,这里有一个演示:
def get_nearest_color(color, colors):
"""
Args:
- color: A vector of size 3 representing an RGB color
- colors: NumPy array of shape (num_colors, 3)
Returns:
- The index of the color in the provided set of colors that is
closest in value to the provided color
""" return np.argmin([np.linalg.norm(color - c) for c in colors])def posterize_with_limited_colors(image, colors):
"""
Args:
- colors: NumPy array of shape (num_colors, 3)
Returns:
- Posterized image of shape (height, width, 1), where each value
is an integer label associated with a particular index of the
provided colors array
""" image = normalize(image)
posterized = np.array([[get_nearest_color(x, colors) for x in y] for y in image])
return posterized
边缘抽取
为了从我们的彩色图像中创建输入数据,我们需要一种从图像中提取边缘的方法,这种方法类似于描画或画线。
我们将使用 Canny 边缘检测算法。让我们编写助手函数,它输入图像的路径并输出相关的示例/(X,Y)训练对,包括彩色输入的色调分离以及黑白边缘提取:
def preprocess(path):
color = cv2.imread(path)
color = cv2.resize(color, input_image_size) # Assuming your pipelines generator function ignores None
if color.shape < input_image_size:
return None, None color = (normalize(color) * 255).astype(np.uint8) gray = cv2.cvtColor(color, cv2.COLOR_RGB2GRAY
# Removes noise while preserving edges
filtered = cv2.bilateralFilter(gray, 3, 60, 120) # Automatically determine threshold for edge detection algorithm
# based upon the median color value of the image
m = np.median(filtered)
preservation_factor = 0.33
low = max(0, int(m - 255 * preservation_factor))
high = int(min(255, m + 255 * preservation_factor))
filtered_edges = cv2.Canny(filtered, low, high)
filtered_edges = normalize(filtered_edges)
filtered_edges = np.expand_dims(filtered_edges, axis = -1) color = cv2.resize(color, output_image_size)
color /= 255.
color = posterize_with_limited_colors(color, colors) return filtered_edges, color
自动 Canny 边缘检测只是我对这篇文章中使用的小函数的修改。
管道
正如我所说的,我正在使用输入管道现场加载数据。因此,我需要定义一个生成器对象,以便在需要时加载这些数据。我的生成器函数很简单,因为我们基本上刚刚定义了它。它所添加的只是过滤掉preprocess
函数的None
输出(分辨率低于input_image_size
的图像),并过滤掉任何包含nan
或inf
值的结果。
def generate_data(paths):
for path in paths:
edges, color = preprocess(path.decode())
if not edges is None:
if not np.any(np.isnan(edges)) or np.any(np.isnan(color)):
if not np.any(np.isinf(edges)) or np.any(np.isinf(color))):
# Yield the clean data
yield edges, color
我用(128, 128)
来表示input_image_size
和output_image_size
。128x128 像素的图像并不是低分辨率的,所以对于我们的目的来说没有明显的缺点。此外,Imagenet 图像的分辨率通常要高得多,因此如果需要,我们可以使用更高的分辨率。
现在让我们建立管道。我使用多线程来提高速度。TensorFlow 的.interleave()
允许我们这样做:
thread_names = np.arange(0, 8).astype(str)
dataset = tf.data.Dataset.from_tensor_slices(thread_names)dataset = dataset.interleave(lambda x:
tf.data.Dataset.from_generator(
generate_data,
output_types = (tf.float32, tf.float32),
output_shapes = ((*input_image_size, 1),
(*output_image_size, 1)),
args = (train_paths,)),
cycle_length = 8,
block_length = 8,
num_parallel_calls = 8)dataset = dataset.batch(batch_size).repeat()
测试管道
让我们通过管道加载一个培训示例:
一个带有输入线条画/边缘(右)和输出着色(左)的训练示例
完全如你所愿。请注意,左边描绘的图像并不完全是管道输出的图像。回想一下,管道返回的是引用每个像素颜色的索引。我只是引用了每种相关的颜色来创建可视化。这里有一个简单得多的例子。
更简单的培训示例
你会看到在左边我们有输出,色调分离的彩色图像,这部分类似于一幅画。在右侧,您可以看到输入边提取,类似于草图。
当然,并不是所有的训练样本都比其他样本具有更好的边缘提取。当颜色更难分离时,产生的轮廓可能会有点嘈杂和/或分散。然而,这是我能想到的提取边缘最准确的方法。
模型架构
让我们继续讨论模型架构。
我从input_image_size = (128, 128)
开始,从而在展开最后一个轴后输入形状(128, 128, 1)
。我将图层输入形状缩小 2 倍,直到它等于 1。然后,我用stride = 1
再应用两个卷积层,因为我们不能再减少前两个轴的形状了。然后,我对转置的层执行相反的操作。每个卷积层有padding = 'valid'
,每个卷积层之间有一个批量归一化层。所有卷积层都有 ReLU 激活,除了最后一个,当然它在最后一个热编码颜色标签通道上有 softmax 激活。
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_35 (InputLayer) [(None, 128, 128, 1)] 0 _________________________________________________________________ conv2d_464 (Conv2D) (None, 64, 64, 3) 30 _________________________________________________________________ batch_normalization_388 (Bat (None, 64, 64, 3) 12 _________________________________________________________________ conv2d_465 (Conv2D) (None, 32, 32, 9) 252 _________________________________________________________________ batch_normalization_389 (Bat (None, 32, 32, 9) 36 _________________________________________________________________ conv2d_466 (Conv2D) (None, 16, 16, 27) 2214 _________________________________________________________________ batch_normalization_390 (Bat (None, 16, 16, 27) 108 _________________________________________________________________ conv2d_467 (Conv2D) (None, 8, 8, 81) 19764 _________________________________________________________________ batch_normalization_391 (Bat (None, 8, 8, 81) 324 _________________________________________________________________ conv2d_468 (Conv2D) (None, 4, 4, 243) 177390 _________________________________________________________________ batch_normalization_392 (Bat (None, 4, 4, 243) 972 _________________________________________________________________ conv2d_469 (Conv2D) (None, 2, 2, 729) 1595052 _________________________________________________________________ batch_normalization_393 (Bat (None, 2, 2, 729) 2916 _________________________________________________________________ conv2d_470 (Conv2D) (None, 1, 1, 2187) 14351094 _________________________________________________________________ batch_normalization_394 (Bat (None, 1, 1, 2187) 8748 _________________________________________________________________ conv2d_471 (Conv2D) (None, 1, 1, 2187) 43048908 _________________________________________________________________ batch_normalization_395 (Bat (None, 1, 1, 2187) 8748 _________________________________________________________________ conv2d_472 (Conv2D) (None, 1, 1, 2187) 43048908 _________________________________________________________________ batch_normalization_396 (Bat (None, 1, 1, 2187) 8748 _________________________________________________________________ conv2d_transpose_229 (Conv2D (None, 1, 1, 2187) 43048908 _________________________________________________________________ batch_normalization_397 (Bat (None, 1, 1, 2187) 8748 _________________________________________________________________ conv2d_transpose_230 (Conv2D (None, 1, 1, 2187) 43048908 _________________________________________________________________ batch_normalization_398 (Bat (None, 1, 1, 2187) 8748 _________________________________________________________________ conv2d_transpose_231 (Conv2D (None, 2, 2, 2187) 43048908 _________________________________________________________________ batch_normalization_399 (Bat (None, 2, 2, 2187) 8748 _________________________________________________________________ conv2d_transpose_232 (Conv2D (None, 4, 4, 2187) 43048908 _________________________________________________________________ batch_normalization_400 (Bat (None, 4, 4, 2187) 8748 _________________________________________________________________ conv2d_transpose_233 (Conv2D (None, 8, 8, 729) 14349636 _________________________________________________________________ batch_normalization_401 (Bat (None, 8, 8, 729) 2916 _________________________________________________________________ conv2d_transpose_234 (Conv2D (None, 16, 16, 243) 1594566 _________________________________________________________________ batch_normalization_402 (Bat (None, 16, 16, 243) 972 _________________________________________________________________ conv2d_transpose_235 (Conv2D (None, 32, 32, 81) 177228 _________________________________________________________________ batch_normalization_403 (Bat (None, 32, 32, 81) 324 _________________________________________________________________ conv2d_transpose_236 (Conv2D (None, 64, 64, 27) 19710 _________________________________________________________________ up_sampling2d_1 (UpSampling2 (None, 128, 128, 27) 0 _________________________________________________________________ batch_normalization_404 (Bat (None, 128, 128, 27) 108 ================================================================= Total params: 290,650,308 Trainable params: 290,615,346 Non-trainable params: 34,962 _________________________________________________________________
培养
让我们创建一些列表来存储整个培训过程中的指标。
train_losses, train_accs = [], []
此外,训练时期数量的变量
epochs = 100
这是我们的训练脚本
for epoch in range(epochs):
random.shuffle(filepaths)
history = model.fit(dataset,
steps_per_epoch = steps_per_epoch,
use_multiprocessing = True,
workers = 8,
max_queue_size = 10) train_loss = np.mean(history.history["loss"])
train_acc = np.mean(history.history["accuracy"]) train_losses = train_losses + history.history["loss"]
train_accs = train_accs + history.history["accuracy"] print ("Epoch: {}/{}, Train Loss: {:.6f}, Train Accuracy: {:.6f}, Val Loss: {:.6f}, Val Accuracy: {:.6f}".format(epoch + 1, epochs, train_loss, train_acc, val_loss, val_acc)) if epoch > 0:
fig = plt.figure(figsize = (10, 5))
plt.subplot(1, 2, 1)
plt.plot(train_losses)
plt.xlim(0, len(train_losses) - 1)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Loss")
plt.subplot(1, 2, 2)
plt.plot(train_accs)
plt.xlim(0, len(train_accs) - 1)
plt.ylim(0, 1)
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.title("Accuracy")
plt.show() model.save("model_{}.h5".format(epoch))
np.save("train_losses.npy", train_losses)
np.save("train_accs.npy", train_accs)
设计你的熊猫数据框
让我们创造出比简单数字更多的东西。
照片由亨电影公司在 Unsplash 上拍摄
数据可视化是从普通数据中推断出有意义结果的伟大工具。它们广泛用于探索性数据分析过程,以便更好地理解手头的数据。如果我们在熊猫数据框架中集成一些可视化结构会怎么样?我认为这比简单的数字更好看。此外,我们可以在数据帧的显示上增加一些信息能力。
我们可以通过使用熊猫数据帧的 Style 属性来实现这一点。Style 属性返回一个 styler 对象,该对象为格式化和显示数据帧提供了许多选项。在本帖中,我们将浏览几个例子,看看数据帧是如何以不同的风格显示的。
我们可以通过调整参数来使用内置的样式函数。我们也可以编写自己的样式函数,并将其传递给 styler 对象,然后该对象在呈现之前实现样式。
有两种方法可以使用 styler 对象。一种是基于元素的样式,可以用 applymap 方法完成。另一种是列或行样式,需要使用应用方法。
让我们首先用 numpy 和 pandas 创建一个样本 dataframe。
df = pd.DataFrame({'A':np.linspace(1,8,8),
'B':np.random.random(8),
'C':np.random.randn(8),
'D':np.random.randn(8),
'E':np.random.randint(-5,5,8)})df.iloc[[1,5],[1,3]] = np.nan
df
它看起来简单明了。我们可以编写一个函数,根据条件用不同的颜色显示一些值。例如,我们可以选择用红色显示负值。下面是完成这项任务的函数。
def color_negative_values(val):
color = 'red' if val < 0 else 'black'
return 'color: %s' % color
然后我们把它传递给 applymap 方法。
df.style.applymap(color_negative_values)
Applymap 执行基于元素的操作,而 apply 基于列或行执行操作。这是一个改变列中最大值的背景颜色的函数。
def color_max(s):
is_max = s == s.max()
return ['background-color: lightblue' if v else '' for v in is_max]
我们只需要通过它来应用方法。
df.style.apply(color_max)
我们还可以通过将 axis 参数设置为 1 来将该函数应用于行。
df.style.apply(color_max, axis=1)
每行的最大值是彩色的。在这种情况下,它们恰好在“A”栏中。
我们可以通过链式操作来组合不同风格的功能。
df.style.applymap(color_negative_values).apply(color_max)
通过使用子集参数选择特定的行或列,样式功能可部分应用于数据帧。
df.style.apply(color_max, subset=['B','C'])
Color_max 函数应用于列“B”和“C”。
除了定制的功能之外,pandas 还有一些内置的功能,可以满足一些常见的任务。例如, highlight_null 函数标记缺失值。
df.style.highlight_null(null_color='yellow')
我们可以用 null_color 参数改变颜色。另一个有用的内置函数是 background_gradient ,它在 seaborn 的帮助下标记与值成比例的单元格。
import seaborn as snscm = sns.light_palette("green", as_cmap=True)df.style.background_gradient(cmap=cm)
值越大,背景颜色越深。缺失值与其余值分开。
Highlight_max 和 highlight_min 函数像我们的自定义 color_max 函数一样标记一列或一行中的最大值和最小值。
df.style.highlight_min(color='lightgreen', axis=1)
df.style.highlight_max()
axis 参数的默认值为 0,执行列操作。
Set_properties 功能允许组合多种风格选择。
df.style.set_properties(**{'background-color': 'lightblue',
'color': 'black',
'border-color': 'white'})
另一个非常有用的函数是 bar ,它在单元格上绘制条形,条形的长度与单元格中的值成比例。
df.style.bar(color='lightgreen')
通过使用 align 参数,我们可以用不同的颜色显示负值和正值。
df.style.bar(align='mid', color=['red', 'lightgreen'])
传送样式
我们在这里使用的样式函数非常简单。然而,我们也可以创建更复杂的样式函数来增强数据帧的信息能力。我们可能希望在我们处理的所有数据帧上使用相同的样式。Pandas 提供了一种在数据帧之间转换样式的方法。
我们首先将样式保存到 styler 对象中。
style = df.style.applymap(color_negative_values).apply(color_max)
style
让我们创建另一个示例数据帧。
df2 = pd.DataFrame({'col1':np.random.random(8),
'col2':np.random.randn(8),
'col3':np.random.randint(-5,5,8)})
df2
然后,我们可以创建另一个 styler 对象,并使用保存在前一个 styler 对象中的相同样式。
style2 = df2.style
style2.use(style.export())
style2
我们已经覆盖了
- 如何创建自定义样式函数并应用于数据框架
- 如何使用内置样式函数
- 如何将样式从一个 styler 对象转移到另一个
在 pandas 用户指南的样式部分有其他可用的样式和格式选项。
感谢您的阅读。如果您有任何反馈,请告诉我。
StyleGAN v2:训练和潜在空间探索笔记
**内容:**在这篇文章中,我将展示我在训练多个 StyleGAN 模型和探索学习的潜在空间时收集的笔记、想法和实验结果。
**为什么:**这是一个想法/考虑的垃圾场,范围从显而易见的到“神圣的钼”,旨在为其他有类似兴趣和意图的人提供洞察力或讨论的起点。因此,可以浏览一下,看看是否有什么感兴趣的东西。
我也在这里大量利用坎宁安定律。
许多考虑因素适用于 StyleGAN v1 和 v2,但是所有生成的结果都来自 v2 模型,除非明确指定。
就代码资源而言:
- StyleGAN v1 和 v2 官方回购
- v1 用编码器(+方向学习)和v2 用编码器
这里的所有内容都是通过我定制的 Jupyter 笔记本在这些回复的基础上生成的。
值得一提的是勤勤恳恳分享代码、实验和宝贵建议的人: Gwern ( TWDNE ), pbaylies, gpt2ent, xsteenbrugge, Veqtor , Norod78 , roadrunner01 。所有这些都非常值得关注。
培养
资料组
对于自定义数据集,需要预先创建一组图像,确保所有条目具有相同的方形和颜色空间。然后,您可以生成 tf 记录,如这里的所述。
正如人们多次指出的那样,这个模型非常渴求数据。数据集大小要求因图像内容而异,但一般目标是 4 到 5 个数量级,比如有镜像时大约 50k,没有镜像时加倍。这适用于从头开始的训练,而在微调的情况下,已经在非常小的数据集上进行了许多实验,提供了有趣的结果。
我主要用两个“时尚”数据集进行实验
- 服装(~30k 包装照片)
- 鞋类(~ 140,000 包照片)
来自鞋类和服装数据集的真实图像样本
但是也将展示一些在人工策划的艺术数据集上的实验(每个数据集大约 1k 张图片)。
真实图像样本(弗兰克·弗兰泽塔,埃贡·席勒,阿尔丰斯·穆夏)
请注意,时尚数据集的内容一致性更高(在位置、背景等方面。).与艺术作品相比。因此,无论数据集大小如何,我们都希望前者能够达到更高的生成精度。
服装图像是应该启用镜像增强的一个例子,因为我们可以免费加倍我们的训练集,学习服装的语义不变属性用于水平镜像。
相反,鞋类是应该禁用镜像的情况,因为数据集中的所有图像都是对齐的,并且学习镜像版本对于网络来说只是不必要的负担。
关于大小,我选择 512 来首先验证结果。从之前其他网络的实验来看,我相信这是一个捕捉图案、材质和纽扣、拉链等小细节的好方法。我还计划在 256 上进行下一次迭代,并验证所学表述的质量以及与训练制度的比较。
我建议,如果你有合适的硬件资源,并且已经用较小的分辨率验证了你的数据集,那么就转到全 1024 分辨率(或更高)。
火车
人们可以从头开始训练模型,或者利用以前训练的结果,将学习到的表示微调到新的数据集。
从头开始训练就像运行以下程序一样简单
python run_training.py -num-gpus=2 -data-dir=<your_data_dir> -config=config-f -dataset=<your_dataset_name> -mirror-augment=True -result-dir=<your_results_dir>
我们已经讨论过镜像增强,GPU 的数量取决于您的设置。
服装数据集多次训练的 fid50k 曲线比较
配置用于控制模型的架构和属性,从 config-a (最初的 SyleGAN v1)开始,逐步添加/更改组件(权重解调、惰性正则化、路径长度正则化)到config-e(v2 的完整更新设置),加上 config-f ,一个更大的网络版本 config-e 和本文中使用的默认设置。
对于我的 512 大小的数据集,我选择了 config-e 。在 config-f 中增加的复杂性主要是由在训练时探索网络对更高分辨率的隐含关注时注意到的信息瓶颈引起的,因此我的基本原理是增加的复杂性只会对训练稳定性更加有害。
微调用于节省时间,依赖于先前模型已经学习的结构,并试图使这样的结构适应新的目标数据集。我也见过人使用与原始数据集不完全相关的图像进行微调,所以这很大程度上取决于你的目标。微调提供了关于训练质量的更快的视觉反馈,因此更容易运行多次迭代和实验,这是最初了解更多模型行为和超参数的好方法。
要微调现有网络,需要指定要重新启动的快照。对于 v2,这是在run _ training . py中完成的,通过添加和修改以下内容
train.resume_pkl = "your_network_snapshot.pkl" # Network pickle to resume training from, None = train from scratch.
train.resume_kimg = 0.0 # Assumed training progress at the beginning. Affects reporting and training schedule.
train.resume_time = 0.0 # Assumed wallclock time at the beginning. Affects reporting.
请注意,根据您的快照指定resume_kimg
是多么重要,因为它用于控制训练计划(如学习率衰减)。
监测进展
StyleGAN v1(左)和 v2(右)的训练进度对比
在训练时,我看到的主要度量是 Frechet 初始距离(FID) ,默认情况下,它是在 50k 图像上每 50 个训练刻度计算一次。如 repo 自述文件中所述,可以调用其他指标。注意,Tensorflow 日志是在目标目录中生成的,可以通过运行 tensorboard 来访问
tensorboard --logdir <LOGS_TARGET_DIR>
除了 FID 之外,您还可以在这里检查分数/假和分数/真,这分别是假图像和真图像的鉴别器预测。由于标签最初可能会产生误导,因此值得再次指出,这些不是损失值,而是鉴别器的纯预测输出。
张量板图
我试图从这些图表中获得一些指导,但发现很难提取网络运行情况的精确信息。理想情况下,人们希望鉴别器不能区分真假,因此趋向于零,因为这只是随机猜测。其他次要指标也是基于损失选择。例如,默认情况下,鉴别器使用带有 R1 正则化的逻辑损失,提供梯度罚分图。
对于我的数据集,FID 很好地映射到个人感知的图像质量,但由于度量是基于从 inception v3 模型中提取的特征之间的汇总统计比较来计算的,因此它可能对其他类型的数据集没有帮助,特别是度量值越趋于零。
我仍然建议避免在短期训练期间进行视觉比较,因为我们的主观近似判断往往会因我们所观察的特定示例或甚至仅因噪声贡献而产生偏差,尽管假样本中没有可察觉的变化,但网络可能仍在改进。
约 10,000 公里后为鞋类数据集生成的图像
另一方面,通过视觉检查,人们可以很容易地发现像模式崩溃这样的问题,如以下为穆卡数据集生成的假样本所示。
穆卡数据集的部分模式折叠示例
这是部分模式崩溃的一个例子,生成器被减少到只生成几个例子,在多样性方面有所损失。造成这种情况的一个主要原因可能是数据集的规模较小,再加上常见的重复条目。
请参见下面的 Franzetta art 示例,尤其是与训练曲线相关的示例。虽然有些条目可能会给人模式崩溃的印象,但更有可能的是,对于该特定示例,训练数据集中的重复项太多了。
Franzetta 数据集的 FID50k 曲线,带有在最后一步生成的假图像样本
调整和超参数调谐
一个像样的数据集通常应该提供一个遵循帕累托分布的良好的训练曲线。官方自述文件指定了不同配置的训练时间,但是正如所说的,你将在训练的第一部分获得大部分的改进;棘手和繁琐的部分是试图达到更好的质量细节。
平台是一种常见的情况,模型很少或没有改进。另一种可能但不太常见的行为是发散或爆炸,在初始步骤改进后,模型开始恶化,并以指数形式退化为纯噪声结果。
针对这种情况采取的行动是从先前的检查点重新训练(如先前的微调部分所述),根据识别的问题合理地调整超参数。正如经常提到的,这本身就是一门艺术,强烈地基于直觉、经验和运气。
根据目标、模型状态等,有多种可能性…以下是一些最常见的建议,并附有一些经验笔记。
- 像往常一样,如果你的数据集在大小或噪音方面有明显的缺陷,花些精力去修复它们,而不是冒险在模型调优上浪费时间
- learning-rate (lr) ,在这里您可以降低 lr 以获得潜在的更稳定(但缓慢)的训练进度。您还可以根据架构中可能存在的两个组件之间的不平衡,单独调整鉴频器和发生器的 lr。对此, Shawn Presser 在推特上指出v2 其实有一个 bug ,针对这个 bug,生成器 lr 值被错误地用作鉴别器 lr。在试验 G/D lr 平衡之前,一定要修补这个部分。我试着增加 lr,只是为了搞笑,但总是以快速突然的发散结束。
- 批量,增加批量也可以提供更稳定的训练或从局部最小值突破。这是基于这样的想法,即随着越来越多的预测用于计算梯度,权重更新和训练方向将越精确。我用更大的 minibatch 运行的多个实验迫使 FID50k 增加了一个很好的百分点,但其中一些很快变得不稳定并爆炸。此外,请注意您的设置的内存限制,v2 更昂贵,1024 分辨率的培训需要至少 16 GB 内存的 GPU。
值得指出的是,StyleGAN 有两个不同的批量参数,minibatch_size_base
和minibatch_gpu_base
。前者是要使用的实际最大 minibatch 大小,而后者是单个 GPU 一次处理的大小。这意味着这两个参数需要根据您的设置的 GPU 数量进行调整,因为梯度会累积,直到达到基本迷你批次大小。
训练曲线:用相同的数据集测试不同的超参数
关于这些方面,我想再次建议 Gwern StyleGAN v1 post ,因为它提供了深入的细节和参考,如果你想进一步探索 GAN-training,还有三篇额外的优秀论文:稳定生成性对抗网络训练:调查(2019) ,GAN 的哪些训练方法实际上是趋同的?(2018) ,训练甘斯的改进技术(2016) 。
一些行为仍然困扰着我,比如在我从之前的检查点(相同的配置)重新开始训练后,是什么导致了损失分数的变化。
潜在空间探索
服装和鞋类数据集的结果
漫步在林荫道上
以上是我的服装和鞋款潜在空间探索的一些例子。其思想只是生成 N 个样本向量(从高斯分布中提取)并使用任何优选的转换函数在它们之间顺序转换。在我的例子中,这个函数只是一个固定帧数的线性插值(相当于变形)。
请注意,我们依赖于非常初始的潜在向量 z. 这意味着我们使用 StyleGAN 映射网络来首先生成潜在向量 w ,然后使用 w 来合成新图像。由于这个原因,我们可以依靠截断技巧,丢弃潜在空间中表现不佳的区域。我们想要指定所生成的中间向量 w 必须接近平均值多少(基于映射网络的随机输入来计算)。ψ (psi)值衡量了 w 与平均值的偏差,因此可以针对质量/品种的权衡进行调整。ψ=1 相当于没有截断(原始的 w ),而值越接近 0,我们越接近平均值,质量有所提高,但多样性有所减少。
截断技巧在起作用,这里线性间隔从-0.5(左上)到 1.5(右下)
编码真实图像
我们经常希望能够获得关于目标模型的真实图像的代码/潜在向量/嵌入,换句话说:我应该馈送给我的模型的输入值是什么,以生成我的图像的最佳近似。
一般来说,有两种方法:
- 通过网络的编码器组件传递图像
- 优化潜在(使用梯度下降)
前者提供了一个快速的解决方案,但在训练数据集之外推广时存在问题,不幸的是,对我们来说,它不是现成的标准样式。该架构根本不学习显式编码功能。
我们只剩下使用感知损失的潜在优化选项。我们为参考和生成的图像提取高级特征(例如,从像 VGG 这样的预训练模型中),计算它们之间的距离,并优化潜在表示(我们的目标代码)。该目标代码的初始化对于效率和效果来说是一个非常重要的方面。最简单的方法是简单的随机初始化,但可以做很多事情来改进这一点,例如通过学习从图像到潜像的显式编码函数。想法是随机生成一组 N 个示例,并存储生成的图像和生成它的代码。然后,我们可以在这些数据上训练一个模型(例如 ResNet ),并在实际的 StyleGAN 编码过程之前使用它来初始化我们的 latent。参见关于改进初始化的丰富讨论。
用于 v1 的编码器和用于 v2 的编码器为该操作提供代码和分步指南。我还推荐以下两篇文章: Image2StyleGAN 和 Image2StyleGAN++和,它们很好地概述了 StyleGAN 的图像编码,考虑了初始化选项和潜在空间质量,并分析了图像编辑操作,如变形和样式混合。
w(1)对 w(N)
StyleGAN 使用映射网络(八个完全连接的层)将输入噪声(z
)转换为中间潜在向量(w
)。两者的大小都是 512,但是中间向量是为每个样式层复制的。对于在 1024 尺寸图像上训练的网络,该中间向量将是形状(512,18),对于 512 尺寸,它将是(512,16)。
编码过程通常在这个中间向量上完成,因此可以决定是优化w(1)
(意味着只有一个 512 层,然后根据需要平铺到每个样式层)还是整个w(N)
。官方放映员操作前者,而改编通常依赖于单独优化所有w
条目,以达到视觉保真度。关于这个话题,请参见这个 Twitter 帖子。
使用 Nvidia FFHQ 模型投影到 w(N)和 w(1)的比较
当投影不适合模型训练分布的参考时,更引人注目,就像在下面的示例中为 FFHQ 模型投影服装图像。
一般来说,人们总是会注意到,对于高分辨率,投影仪似乎无法匹配参考图片的精细细节,但这很可能是使用 256x256 分辨率的感知损失的结果,如本主题所示。
学习方向
StyleGAN 对潜在空间解缠的改进允许以令人愉快的正交方式探索数据集的单个属性(意味着不影响其他属性)。
鉴别模型学习区分目标属性的界限(例如,男性/女性、微笑/不微笑、猫/狗),而我们感兴趣的是跨越这些界限,垂直于它们移动。例如,如果我从一张悲伤的脸开始,我可以缓慢但稳定地移动到同一张脸的微笑版本。
这应该已经提供了如何学习新方向的提示。我们首先从我们的模型中收集多个样本(图像+潜像),并针对我们的目标属性对图像进行手动分类(例如,微笑与不微笑),试图保证适当的类别表示平衡。然后,我们训练一个模型来对我们的潜在客户和人工标签进行分类或回归。此时,我们可以使用这些支持模型的学习功能作为过渡方向。
罗伯特·卢森堡分享了【FFHQ 官方车型的学习方向。
样从玩弄微笑潜向
用于前馈图像处理的 StyleGAN2 蒸馏是一篇非常新的论文,通过在 StyleGAN 生成的不成对数据集上训练的“学生”图像到图像网络来探索方向处理。该论文旨在克服编码性能瓶颈,并学习能够有效地应用于真实世界图像的变换函数。
来自论文“用于前馈图像处理的 StyleGAN2 蒸馏”的例子
结论
我的很多实验最初都是为了评估 StyleGAN 模型学习的潜在空间有多好(表示学习),以及获得的嵌入对于下游任务(例如,通过线性模型的图像分类)有多好。一方面,我将继续致力于这种评估,试图涵盖其他生成模型类型,如自回归和基于流程的模型。
我也有兴趣探索这种模型的纯图像合成能力,以及有效的语义混合和编辑的日益增长的潜力,特别是与我对绘画、数字绘画和动画的热情有关的方面。自动线条画着色、动画绘画、帧插值已经有了一些很棒的免费工具,但是对于 辅助绘图 还有很多可以做的,特别是从更语义的角度来看。实际改进的空间也很大:泛化能力、加快推理时间、训练优化和迁移学习。
接下来,我还想超越纯粹的二维画布,更多地了解在 3D 图形领域已经取得的惊人成就。去噪是我现在经常依赖的东西,可微渲染只是让我意乱情迷,为了闭环,又回到了 GAN 进行连续的 3D 形状生成。
引用科学家卡罗里·索尔奈-费希尔
“多么美好的活着的时光”
你可以在 Github 上查看我的代码,在 Twitter 上关注我的更多实验和解释,并在 Instagram 上查看我的图形结果。
免责声明 :目前我不能分享数据集和训练模型。抱歉。
StyleGAN2 投影。一种可靠的图像取证方法?
一些需要尝试的实验。还有艺术。
幻觉妄想
W 随着 StyleGAN2 ,一种全新品质的 GAN 驱动的图像生成方式进入了舞台。在性能和结果方面有显著的改进。康纳缩短写了一篇全面介绍这款新车型:
- 更好的图像质量(和分辨率)
- 最大限度地减少图像伪影(如“斑点”或“水滴”)
- 风格混合(效果更好)
- 将图像投影到潜在空间
这里有一个简短的视频介绍 StyleGAN2,由 NVidia 团队的开发人员(Tero Karras 等人)制作。
**Colab 笔记本:**最近你还可以在这款 Colab 笔记本中试用 StyleGAN2(由 Mikael Christensen 改进了一些类似投影的功能)。
真相是什么?
关于真理的问题比以往任何时候都更加重要。各个时代的哲学家、艺术家和其他人都在寻找真理和谎言的区别。
在数字时代,我们得到了严峻的消息:证据受到质疑。“一图胜千言”这种老套的观念已经不管用了。我们有#deepfakes、图像生成和其他(音频)视觉建设性的可能性。我们不能确定我们现在看到的图像是否代表真实事件,或者它是否是几秒钟前生成的。
所以我们不得不谈谈图像取证。
现在已经有多种方法来鉴别真假图像:
最明显(但不是最靠谱)的方法就是训练自己去检测假货。
- Kaggle 开启 DeepFake 检测挑战。
- 有一个网站http://www.whichfaceisreal.com/开玩笑地训练你去发现被放大的图像。
如何检测假图像?
与比根相比,斯泰尔根是一个压倒性的发展。尽管如此,它在人脸生成方面还是有一些缺陷:
- 对称不是斯泰勒根的朋友。
- 你可能会在脸上和头发上发现奇怪的人造物,比如“气泡”。
- 耳环不一样(最普遍的因素之一)。
- 背景很奇怪。
<= This image shows various GAN glitches.
With StyleGAN2 new standards were established. “Bubble artifacts” were mostly fixed. Is it way too hard to detect fakes?
StyleGAN2 developers added a brilliant method to detect fake: 投影。
什么是 StyleGAN2 投影?
方法很聪明。StyleGAN 将一个给定的图像投射到潜在空间——生成图像的起源。
它与反向图片搜索有一些表面上的相似之处(如使用 TinEye 或谷歌图片搜索进行查找,如果图片是库存照片):
神秘的股票形象女孩(阿丽亚娜)
在某些情况下,它不仅会导致原始股票图像提供者,甚至会导致独特的人——就像上面的例子中的股票图像模型 Ariane (另一个故事)。
StyleGAN2 投影将相关图像与生成 GAN 图像的潜在空间进行比较,并寻找原点。
理论上。在实践中(你可以在 Colab 笔记本里尝试一下),它……很复杂。
投影实验
已经有一些杰出的艺术家和研究人员对投影进行了令人惊叹的线程和测试,如吉恩·科岗、乔纳森·弗莱、马里奥·克林格曼、迈克尔·克里斯滕森,仅举几例。不过还是自己试试吧。经验主义法则。
现状核实
第一次(一如既往),我做了一个自我实验。只是为了确定我不是在某个潜在的空间里产生的:
因此,正如你(希望)看到的,这两张图片是不可比较的。我是真实的(又是)。
用 ArtBreeder 创建的图像。
接下来,我检查了我用 ArtBreeder 生成的这个绅士(你已经读过这个奇妙的系统)。由于 ArtBreeder 实现了用于面部生成的 StyleGAN2,您可以假设这是相同的潜在空间。但是…
**这个人是真的吗?**原物和投影相似但不相同。
甘+我的脸=无法察觉的假
事情是这样的:自从art breader最近增加了上传你的图像并将它们与潜在空间中生成的图片混合的可能性,你不能再指望可用的图像了。
幸运的是,ArtBreeder 提供了血统功能,在这里你可以“按谱系”追踪到根源。
对于这位先生来说,一部分是我的脸,和另一个人混在一起:https://artbreeder.com/lineage?k=45f6f4c1750ed4fe014202fb
已经不是纯粹的 StyleGAN 了。
StyleGAN2 生成的图像
让我们看看潜在空间本身。让我们用 StyleGAN2 直接创建图像。我做到了。很多都是。很好玩。
现在让我们随机挑选一张脸:
如你所见,这些面孔也很相似,但仍然不相同!
从这张夸张的插值图像中,我得到了令人惊讶的最佳结果:
我看到了第一张神秘的脸,瞧!
所以如果你偶然发现这位女士穿着异国情调的时装,你可以肯定地知道:这是假的。(如果你到那时还不好奇的话)。
结论
投射到潜在空间的想法很棒——而且是 StyleGAN2 所有品质不可避免的。假检测不再是人类的任务。我们不可靠。
尽管如此,还是有可能防止投影和反向搜索。因此,开发人员仍然必须找到如何不使我们的世界陷入完全混乱的方法。(剧透:来不及了)。
艺术呢?
说到人工智能,我总是指内在的艺术。你可以做许多你以前不能做的创新的事情(查看我的系列艾&艺术)。有一些新的艺术方法是几年前在最奇怪的梦里也想不出来的。
有了投影,我们可以做一些我们已经用谷歌深梦体验过的事情。我称之为盲目崇拜。
在我的定义中:
Pareidolia 是人脑识别各处模式的能力(即使它们不在那里)。在石器时代,这是一项至关重要的技能。我们最好下次把丛林和老虎混淆起来,而不是我们认不出丛林里的老虎。
石器时代已经过去,但我们仍处于这种觉知状态,看到火星上的脸和烤面包上的耶稣。
ParAIdolia 是神经网络(如 CNN)识别其接受训练的模式动机的能力。即使是在白噪音中。这就是为什么所有那些狗在最初的深度梦实验中。
StyleGAN2 正在铺开,可用的 Colab 笔记本仍然提供了有限的型号选择: 人脸教堂马、 等。但是 面孔 是一个有趣的面孔,因为我们可以尝试崇拜偶像。
***side note:***Jonathan Fly 对非人脸和艺术品进行了实验,StyleGAN 能找到的不仅仅是上面这些。
所以,如果想知道 StyleGAN 是否梦到过大阪的惠比寿塔摩天轮:
假马里奥看起来像一个表情符号:
东京变成了一张令人毛骨悚然的脸:
最后,甚至装饰图案也变成了一场可怕的噩梦:
在这张来自的历史照片中,大都会艺术博物馆最近的展览 StyleGAN 认识到了一些非常令人不安的事情:
一个有趣的实验是,当乔纳森让斯泰尔根看一点点,而不是直到最终结果时,他用投影飞了起来。因此,即使非人类的模式也变成了人类。这里只是一个仍然来自他的综合 项目口袋妖怪 。
出自: 项目口袋妖怪 作者乔纳森·弗莱(iforcedabot.com)
如你所见,技术和艺术的界限再次被湮灭。
这些是人类和机器之间惊人的本体论对话。
你会在潜在空间里发现什么?
发表你的发现吧!
设计熊猫数据框架:不仅仅是数字
让原始数据更有洞察力
数据帧是 Python 中操作和存储数据的最标准方法——但是您知道您可以存储的不仅仅是数字吗?Pandas 有多种方法来设计您的数据框架,既方便数据管理者,也方便查看数据的人。
首先,我们将生成一个样本数据帧。它有五列,每行十行,都是从正态分布中随机抽取的。
为了根据条件规则给数据帧着色,需要创建一个颜色映射。它以函数的形式存在,接受一个值,返回一个字符串“color: [color]”。该函数将负值涂成红色。标准颜色是可以接受的,但是十六进制代码也可以。
通过使用.style.applymap
功能,颜色图被应用于数据帧。
现在,它看起来像这样:
例如,假设我们想用黄色突出显示每列中的最大值。就像给文本涂上某种颜色一样,我们需要创建一个样式函数。因为此函数突出显示系列中的最大值,而不是每个值的条件,所以此函数接受完整的列(系列)并返回该列中每个单元格的样式说明列表。
在这种情况下,不使用“color: [color]”,而是使用“background-color: [color]”(通常,颜色可以是标准颜色名称或十六进制代码)。
注意,因为这个函数应用于每一列而不是一个值,所以不要使用apply_map
而是使用apply
。
您可能会发现,如果您之前已经应用了某些东西,那么应用.style.apply
将会产生一个错误。这是因为使用函数创建的不是数据帧,而是样式化的对象。要组合许多样式元素,请使用 Python 方法链。
另一种方法是简单地将方法堆叠起来,例如.style.highlight_null().apply().apply_map()
。
如果您想标记所有 NaN 值,使用.style.highlight_null
。这对于使丢失的值更加明显特别有用。
要使数据帧成为热图——也就是说,值根据它们的值进行着色——使用.style.background_gradient
方法。该方法接受一个cmap
(颜色映射)参数,该参数指示它应该如何着色。在本例中,cmap
是使用 seaborn 的light_palette
创建的,它接受一个根颜色(在本例中,是蓝莓的十六进制代码)。第三行的cmap
参数也可以设置为标准的调色板名称,如viridis
或magma
。
要设置固有的数据帧属性,使用.style.set_properties
。它将一个字典作为参数,包含各种属性及其值。
人们甚至可以在 Pandas 数据框架中创建“条形图”,其中每个条形对应一个列的值。这对可视化非常有帮助。在这种情况下,subset
指的是上面有条形的列。
如果你喜欢这个,
你可能会喜欢我的其他熊猫和 Python 数据科学库教程。
这个备忘单包含了你最常需要的一个情节的要素,以一种清晰和有组织的方式,用…
medium.com](https://medium.com/swlh/your-ultimate-python-visualization-cheat-sheet-663318470db) [## 处理日期时间时你必须知道的 6 种方法
迄今为止最混乱的数据类型
medium.com](https://medium.com/analytics-vidhya/6-methods-you-must-know-when-dealing-with-datetime-fa0160fe579a) [## 您的终极数据挖掘和机器学习备忘单
特性重要性、分解、转换等
medium.com](https://medium.com/analytics-vidhya/your-ultimate-data-mining-machine-learning-cheat-sheet-9fce3fa16)
R 和 Python 在通过神经网络建模数据方面的风格差异
数据科学文体学
如何使用 R 和 Python 对神经网络路径进行建模,并为一组预测器和目标变量生成预测
数据科学方法的核心步骤是对数据进行建模,以产生准确的预测。最后,有大量的方法和算法可供探索。这篇博客用 R 和 Python 介绍了一种在建模数据时不断发展的方法,此外还有以前的方法( 决策树 , 贝叶斯定理 **),**这些方法模拟了大脑的功能。
1.神经网络导论
数据科学中的神经网络代表了再现非线性学习的尝试,该非线性学习发生在自然界中发现的神经元网络中。一个神经元由树突组成,收集来自其他神经元的输入,并组合输入信息,以便在达到某个阈值时产生响应,该响应被发送给其他神经元。输入(Xi)通过组合函数从上游神经元收集,然后传递到激活函数以产生具有预测能力(y)的最终输出响应。
组合函数通常是求和,将节点输入和连接权重的线性组合生成单个标量值。根据下面的等式, X 表示节点 J 的第 i 个输入, W 表示与节点 J 的每个输入相关联的权重, comb 表示组合函数的最终结果。
给定节点 j 的组合函数
一旦组合函数导致一组数值结果,激活函数就沿着这条路径前进。可能有一系列选择,但最常见的是 sigmoid 函数。原因是它结合了线性、曲线和常数行为,同时使用自然对数的基数(e= 2.718…).通用公式如下所示。
广义 sigmoid 激活函数
一旦激活函数被定义,来自组合函数的值被应用于它,以便产生来自神经网络路径的输出。这些值将代表对所考虑的目标变量的预测。
应用于组合函数结果的 Sigmoid 激活函数
神经结构由称为节点的人工神经元的分层、前馈和连接网络组成。
1。分层:最少有一个输入层、一个隐藏层和一个输出层
2。前馈:没有回路和循环的单向流动
3。连接:相邻层中的每个节点都与另一个节点相连
神经网络的分层特性是其优势和弱点,因为隐藏层中的节点越多,其处理复杂模式的能力就越强,但如果以泛化为代价,也可能导致过拟合。
维基共享通过维基百科
神经网络不是静态模型,它会不断学习。对于来自训练数据集的每个观察,产生输出值,然后与一组训练观察的目标变量的实际值进行比较,并计算误差(实际输出)。为了测量输出预测与实际目标值的吻合程度,大多数神经网络模型使用误差平方和(SSE)。
误差平方和
使用神经网络的主要好处是,由于其非线性结构,它们对于嘈杂和复杂的数据非常稳健。然而,基本的内部工作仍然难以人为解释。
2.用 Python 创建神经网络模型
在 Python 中开始构建神经网络的起点是上传相关的库,其中有keras.models
、keras.layers
和keras.utils
。这些是收集和定义神经网络模型的各种组件的必要前提。
Keras 是一个用 Python 编写的开源神经网络库。它能够运行在 TensorFlow、微软认知工具包、Theano 或 PlaidML 之上。旨在实现深度神经网络的快速实验,它专注于用户友好、模块化和可扩展。
import numpy as np
import pandas as pd
from numpy import loadtxt
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Activation
from keras.utils import to_categorical
from keras.regularizers import l1
from sklearn.utils import class_weight
其次,上传或创建相关数据帧是进行分析的基础,在神经网络的情况下,选择非线性数据集是明智的,尤其是当它们与视觉记录相关时。首先,我们可以随机生成一个数据集来模拟代码。在这个例子中,对收到多少援助的预测(Y)被探索为冲击类型和位置(X1,X2)的函数。我们可以通过组合命令insert
和tolist
来指定要插入的变量的属性数量和类型,从而将数值变量转换为分类变量。
df = pd.DataFrame(np.random.randint(0,1000,size=(1000,1)), columns= ['AidMillion'])
category = pd.cut(df.AidMillion,bins=[0,500,1000],labels=['Below_500_Mill','Above_500_Mill'])df.insert(2,'Aid_Given',category)
df.Aid_Given = df.Aid_Given.tolist()TypeShock = (['Draught','Floods','Famine'])
df["TypeShock"] = np.random.choice(TypeShock, size=len(df))Location = (['Urban','Rural'])
df["Location"] = np.random.choice(Location, size=len(df))
对于神经网络,有必要将所有分类变量转换成数值变量。在 Python 中实现这种转换的命令应该是astype(‘category’).cat.codes.
另外,我们可以使用train_test_split
命令预先分割数据帧。
df['TypeShockNum'] = df['TypeShock'].astype('category').cat.codes
df['LocationNum'] = df['Location'].astype('category').cat.codes
df['Aid_GivenNum'] = df['Aid_Given'].astype('category').cat.codesdf_train, df_test=train_test_split(df,test_size=0.33,random_state=2)
df.head()
一旦相关变量被转换,下一个关键步骤是以一种可以通过神经网络算法处理的方式定义预测器和目标变量。在 **Python 中,**这可以通过设置变量的子集并确保每个变量都处于np.array
的形式下来实现。
X_train = np.array(df_train[["TypeShockNum","LocationNum"]])
y_train = np.array(df_train[["Aid_GivenNum"]])X_test = np.array(df_test[["TypeShockNum","LocationNum"]])
y_test = np.array(df_test[["Aid_GivenNum"]])
然后,创建神经网络的最关键时刻是定义要测试的模型。在 Python 中,第一步是定义我们希望探索的是顺序还是功能应用程序接口(API)。前者允许您为大多数问题逐层创建模型,但不允许模型共享层或具有多个同时输入或输出。后者使您能够创建具有更大灵活性的模型,因为您可以轻松定义可能具有多个不同输入源、生成多个输出目标或重用层的模型。在这种情况下,使用更简单的顺序模型。
model = Sequential()
其次,我们通过使用密集类开始构建完全连接的层。这是我们希望测试的层中有多少神经元或节点的规范,输入维度表示为input_dim
以及使用特定参数的激活函数。在模型中,我们可以表示各种层类型。最常见的是密集,但也可能是卷积、池化或循环。在密集层中,我们可以定义几个项目,例如:
1)表示输出空间维度的单元的数量。没有完美的公式来定义最佳单元数,起点是模型中输入和输出及其属性的平均值。在我们的例子中,数据集有 2 个输入,总共有 5 个属性和 1 个输出。这些值通知一系列迭代以创建最佳模型。
**2)激活函数: 如果没有指定任何东西,则不应用激活(即“线性”激活:
*a(x) = x*
)。否则,通常将激活函数应用于节点的输出,以限制或限定其值。激活函数有助于限制值,并有助于决定节点是否应该被“触发”。它们可以是线性、sigmoid、双曲正切或校正线性单位(ReLU)函数。可以包括其他元素。例如,
[***kernel_initializer***](https://keras.io/initializers/)
描述了用于初始化权重的统计分布。[***kernel_regularizer***](https://keras.io/regularizers/)
在优化期间对层参数或层活动施加惩罚,以并入网络优化的损失函数中。***activity_regularizer***
作为输出的函数工作,主要用于调整隐藏单元。其他组件可以在这里找到。
除了密集层,其他元素也可以添加到模型中。例如,Dropout
函数的工作原理是基于概率从后续层的先前激活中“删除”输入变量。它具有模拟具有非常不同的网络结构的大量网络的效果,并且反过来,使网络中的节点通常对输入更鲁棒。
**model.add(Dense(3, input_dim=X_train.shape[1], activation='sigmoid', activity_regularizer=l1(0.001)))model.add(Dropout(0.1))
model.add(Dense(2))
model.add(Dropout(0.1))
model.add(Dense(1))
print(model.summary())**
为了用 Python 从目前创建的模型中产生预测,编译是必要的。在这个关键步骤中,我们需要通过考虑目标变量的性质来定义损失函数。我们可以使用以下选项:
**1)mean _ squared _ error是回归问题的损失函数,它计算数据集中每个示例的实际目标值和预测目标值之间的平方差,然后返回它们的平均值。
2)mean _ absolute _ error是回归问题的损失函数,计算数据集中每个示例的实际目标值和预测目标值之间的差异,然后返回它们的平均值。
3)mean _ absolute _ per%
4) 二元 _ 交叉熵 是针对两类/二元分类问题的损失函数。通常,交叉熵损失用于计算模型的损失,其中输出是 0 到 1 之间的概率数。
5) 分类 _ 交叉熵 是针对多类(两类以上)分类问题的损失函数。
在模型函数中,我们还必须选择一个优化器。每当神经网络完成通过网络传递一批输入时,它必须决定如何使用预测值和实际值之间的差异来调整节点上的权重,以便网络优化其解决方案。确定该步骤的算法被称为优化算法**。最常见的是:**
1) 随机梯度下降 (
*SGD*
)计算网络损失函数相对于网络中每个个体权重的梯度。内斯特罗夫加速梯度(NAG)也可用于加速梯度下降。
2) 自适应梯度(*Adagrad*
***)*是一种更先进的机器学习技术,它以可变的学习速率进行梯度下降。通过对不频繁参数的大更新和对频繁参数的小更新,保留和加强了节点梯度的历史权重。因此,它非常适合处理稀疏数据。
3) 均方根传播 (*RMSprop*
)是对 Adagrad 的一种修正,学习率进一步除以所有平方梯度的指数衰减平均值,得到全局调整值。
4) 自适应矩估计 (*Adam*
)除了存储过去梯度平方的指数衰减平均值外,它还保留过去梯度的指数衰减平均值。
最后,我们还可以依靠一种“平衡”模式来应用于通过神经途径使用的权重。A class_weight.compute_sample_weight
实用程序可以通过下面的公式n_samples / (n_classes * np.bincount(y))
变换 y 的值,自动调整与输入数据中的类频率成反比的权重
**model.compile(loss='binary_crossentropy', optimizer='RMSprop', metrics=['accuracy'])**
**一旦在 **Python、中定义并编译了模型,我们就可以根据一组参数来拟合模型。在fit
函数中,我们将指定:1)模型中的关键变量,2)运行模型的epochs
的数量,这意味着在整个数据集上的迭代次数,3)batch_sizes
,这是每次梯度更新使用的训练数据样本的数量,以及引用测试数据集中等效变量的validation_data
。一旦定义完毕,我们就可以通过model.evaluate
命令运行模型并评估其结果。如下所示的最终输出指示训练和测试数据集的损失函数和准确度系数。我们的目标是精度尽可能接近 1,并且损失函数产生的结果接近 0。呈现的输出表明模型仍然需要修正和更多的迭代来正确地参数化它。
**history=model.fit(X_train, y_train, epochs=200, validation_data=(X_test,y_test),batch_size=50, verbose=0, sample_weight= sample_weightsloss_acc_metric_train = model.evaluate(X_train, y_train, verbose=1)
loss_acc_metric_trainloss_acc_metric_test = model.evaluate(X_test, y_test, verbose=1)
loss_acc_metric_test**
3.创建神经网络模型 R
与前面的 Python 示例类似,在 R 中,我们将使用 Keras 作为创建神经网络的关键包。我们还需要安装tensorflow
和reticulate
来运行我们的模型。Keras 的使用允许在两种编码语言之间使用非常相似的编码风格。
**library(keras)
library(tensorflow)
library(reticulate)
library(kerasR)**
第一步仍然是创建或上传相关数据框架,作为进行分析的基础。在本例中,我们将随机生成一个数据集来模拟 R 中的代码。和前面的例子一样,收到的援助预测(Y)是冲击类型和位置(X1,X2)的函数。我们还可以通过命令ifelse
指定属性,将数字目标变量转换成分类变量。
**df <- data.frame(replicate(1,sample(0:1000, 1000, rep=TRUE)))
colnames(df) <- c("AidMillion")
df$Aid_Given <- ifelse(df$AidMillion <= 500, "Above_500_Mill", "Below_500_Mill")df$TypeShock <- sample(c('Draught','Floods','Famine'), size = nrow(df), replace = TRUE)df$Location <- sample(c('Urban','Rural'), size = nrow(df), replace = TRUE)**
为了有合适的变量进行分析,我们需要将分类变量转换成数字变量。在 R 中,我们的预测变量和目标变量的转换需要通过as.factor
和as.numeric
命令将每个分类双重转换为因子和整数。要将目标变量转换成零和一的值,我们可以依靠ifelse
来表达相关的条件。随后,我们可以通过命令runif
将数据帧分成测试和训练帧。
**df$LocationNum<-as.numeric(factor(df$Location))
df$TypeShockNum<-as.numeric(factor(df$TypeShock))
df$Aid_GivenNum<-ifelse(df$Aid_Given=="Above_500_Mill",1,0)set.seed(8)
n<- dim(df)[1]
train_df<-runif(n)<0.60
df_train<- as.data.frame(df[train_df, ])
df_test<- as.data.frame(df[!train_df, ])head(df)**
所有变量都是数字格式后,在 R 中创建合适的目标变量和预测变量也需要进一步操作,以确保目标变量成为数组,预测变量成为矩阵。与 Python 相比,这需要一个额外的步骤,因为变量的选择不能与array
和data.matrix
命令结合使用。这需要单独完成,而 Python 中的 numpy 允许组合转换。
**X <- df_train[c("TypeShockNum","LocationNum")]
y <- df_train[c("Aid_GivenNum")]X_t <- df_test[c("TypeShockNum","LocationNum")]
y_t<- df_test[c("Aid_GivenNum")]X_train <- data.matrix(X)
Y_train <- array(y$Aid_GivenNum)
X_test <- data.matrix(X_t)
Y_test <- array(y_t$Aid_GivenNum)**
一旦变量被转换,我们将定义模型**。R 中的这一步在风格上与 Python 完全相似,只是有一些小的不同。在定义了顺序模型之后,我们将使用美元符号来添加层和 dropout 函数。在第一层中,参数的唯一区别是语义上的。例如,我们将使用input_shape
代替 input_dim 来表示预测器的数量。其余的仍然非常相似,包括其他参数的名称。**
**mod <- Sequential()
model$add(Dense(units=3, activity_regularizer=regularizer_l1(0.001), input_shape = ncol(X_train), activation="sigmoid"))model$add(Dropout(rate = 0.1))
model$add(Dense(units = 2))
model$add(Dropout(rate = 0.1))
model$add(Dense(units = 1))
model**
一旦模型被定义,模型就准备好进行编译**。在 R 中,这是通过keras_compile
命令完成的,同时保持大部分参数的定义方式与之前 Python 中损失函数和优化的示例相同。一旦定义了编译标准,就可以根据与 Python 中表达的参数相同的措辞来使模型适合训练变量。除了一些措辞上的变化,比如需要在验证数据规范之前添加list
,以及在函数中插入我们的模型,没有重大的差异需要报告。要显示结果,在 R 中更容易,因为我们可以只调用函数的结果来查看它们,而不需要进一步的求值命令。**
就损失函数而言,这种模拟的最终结果是可以接受的,但是精度仍然太低。
**keras_compile(model, loss = 'binary_crossentropy', optimizer = RMSprop(), metrics = c('accuracy'))history <-fit(model, X_train, Y_train, batch_size = 30, epochs = 250, verbose = 0, validation_data = list(X_test, Y_test))history**
4.用 R 和 Python 绘制模型和预测
**一旦模型生成了相关的预测,我们就可以绘制结果来查看在各个迭代(时期)中损失和准确性结果的进展。在 **Python 中,这要耗费更多的时间,因为我们需要定义绘图的各种参数来绘制模型在精度和损失方面的表现。下面的结果表明,在第 50 次迭代之后,精确度有了显著的提高,损失函数有所下降。
**plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()**
另一方面,在 R. 中绘制我们的模型的损失和准确性的进展要容易得多,只需调用plot
函数,我们就可以访问我们的损失和准确性函数的趋势。这再次证明了 R 是一种非常注重视觉的语言,可以非常容易地生成相关的情节。我们可以再次看到我们的模型在第 50 个纪元前后有了显著的改进(也称为数据集上的迭代)。
**plot(history)**
最后,我们可以将预测值添加到测试数据集中,以进一步验证它们的一致性。在 Python 中,predict
和舍入函数的组合可以生成一系列预测值,我们可以在测试数据集中使用这些预测值进行进一步分析。
**predictions = model.predict(X_test)
predictions = [round(x[0]) for x in predictions]
X_test['predictions'] = predictions
X_test.head(7)**
同样,在 R 中,我们可以预测应用于测试数据集的值,对它们进行舍入,并通过使用美元符号来创建一个新变量,以推进我们的比较。除了语义上的一些变化,方法仍然是命令 predict 为测试样本中的输入样本生成输出预测。
**pred <- predict(model, (X_test))
df_test$pred <-round(pred, digits = 0)
head(df_test,5)**
5.最终反射
虽然这些模型的输出可以得到显著的改进,但这篇博客的目的是为了说明在 Keras 中创建神经网络时,从风格的角度来看,R 和 Python 是多么相似。事实是,神经网络可能比迄今为止所展示的要复杂得多。它可以是多层感知器、卷积网络或递归网络。它可以具有共享的要素提取图层、多个输入或多个输出。虽然这是一个不断发展的领域,但对基础概念的基本理解足以模拟神经网络。这可以为我们提供一个基础,通过测试各种参数和优化功能,不断改进和构建我们所知道的东西。
除了这种方法之外,还有其他可以探索的数据建模方法。敬请关注即将推出的方法!
R 和 Python 在通过回归分析建模数据方面的风格差异
科学文体学
如何使用 R 和 Python 通过不同版本的回归分析对数据进行建模,回归分析代表一项估算任务,为不同类型的目标变量生成预测
数据科学方法的核心步骤是通过分类、聚类或评估任务对数据建模。最后,有大量的方法和算法可供探索。本博客用 R 和 Python 对不同类型的回归分析进行了基本介绍,这是对之前介绍的其他方法的重要补充(决策树贝叶斯定理 )。回归分析
1.回归分析导论
在统计建模中,回归分析是一组统计过程,用于估计因变量(通常称为“结果变量”)和一个或多个自变量(通常称为“预测值”、“协变量”或“特征”)之间的关系。(维基百科)
回归模型可用于因果分析和交叉验证,代表两个截然不同的范围。在没有实验的情况下,回归不能导致因果关系的陈述,但它可以用于交叉验证的目的,这提高了关系的预测准确性和模型的 内部有效性 。因果推断需要一个包括所有相关预测因素的模型,而不是一个只有有限解释因素的观察研究。因此,一个简单的滞后变量或与结果相关的变量可以产生一个在多个样本中验证的模型,而不一定导致因果推断。
换句话说,回归分析可用于交叉验证,以确保预测的可重复性。另一方面,回归分析可以在更广泛的人群中建立因果联系,并与实验的 外部有效性 相关。因果推理需要一个反映实验设计的样本结构,以及由专业知识支撑的清晰的逻辑连接。
2.普通最小二乘(OLS)回归模型
回归可以是简单的,也可以是多重的。简单回归只考虑一个预测因子,而多重回归将分析扩展到包括一个以上的因子。线性多元回归是一个参数模型,由以下等式定义,其中 x 代表预测变量,各种βeta代表未知模型参数,其值使用可用证据进行估计。
传统参数多元回归
普通最小二乘法 ( OLS )符号定义了用于估计线性回归模型中未知参数的线性最小二乘法。OLS 通过最小二乘法原理选择一组预测值的线性函数的参数。OLS 最小化给定数据集中观察到的目标变量与线性函数预测的目标变量之间的差异的平方和。下面的公式显示了第 i 次观测 y 的残差测量数据点( xi 、伊)与超平面之间的垂直距离。该公式旨在评估实际数据和模型之间的拟合程度。下面的公式显示了第 i 次观察 y 测量的数据点(*, yi )与超平面之间的垂直距离的残差*。(维基百科)这个公式意在评估实际数据和模型之间的吻合程度。****
残差平方和
此外,OLS 的应用依赖于以下假设,这些假设对于验证该方法的使用是必要的(改编自本 来源 ): 1 .回归模型在系数和误差项中是线性的,这意味着其函数形式遵循一组参数,而不是对曲率
2 建模的能力。误差项的总体均值为零,回归模型中的常数迫使残差均值等于零
3。所有的独立变量都与误差项不相关,因此 OLS 模型不会将任何方差归因于其误差
4。误差项的观测值彼此不相关,并且信息不会预测后续观测值的误差项
5。误差项具有恒定方差(无异方差),因为它不会因每次观察或一系列观察而改变
6。没有自变量是其他解释变量的完美线性函数(不存在多重共线性)
7。误差项呈正态分布,如果残差遵循正态概率图上的线,则意味着它们呈正态分布****
以下示例基于随机生成的数据集,因此可能不满足以下假设,但仍然值得考虑,以便了解回归建模中各种计算背后的代码。然而,对特定目标变量的分布和均值的行为进行分析,将告知要利用的回归类型。
3.R 和 Python 中的普通最小二乘(OLS)
在 Python 中开始构建 OLS 回归的起点是上传相关的库,其中statsmodels.api
代表了产生回归结果的最具定义性的库。Statsmodels 允许用户探索数据、估计统计模型和执行统计测试。描述性统计、统计测试、绘图函数和结果统计的广泛列表可用于不同类型的数据和每个估计量
**import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
import statsmodels.api as sm**
其次,上传或创建相关数据框架是进行分析的基础。在回归分析的情况下,最好是根据主题相关性选择变量。在本例中,对获得多少援助(Y)的预测是作为预测因素(如冲击类型、位置和持续时间)组合的函数进行研究的。
**df = pd.DataFrame(np.random.randint(0,1000,size=(1000,1)), columns= ['IncomeLoss'])df["DurationMonths"] = np.random.randint(1, 12, df.shape[0])TypeShock = (['Draught','Floods','Famine'])
df["TypeShock"] = np.random.choice(TypeShock, size=len(df))Location = (['Urban','Rural'])
df["Location"] = np.random.choice(Location, size=len(df))df["AidMillion"] = np.random.randint(0, 1000, df.shape[0])
category = pd.cut(df.AidMillion,bins=[0,500,1000],labels=['Below_500_Mill','Above_500_Mill'])
df.insert(2,'Aid_Given',category)**
为了建立 OLS 模型,有必要通过对标签进行编码将所有分类变量转换成数值变量。在 Python 中实现这种转换的命令应该是le.fit_transform
。此外,我们可以使用train_test_split
命令将数据帧分割成一列并测试一列,以简化估算的验证过程。
**le = preprocessing.LabelEncoder()
y1=df['Location']
df['LocationNum']= le.fit_transform(y1.astype(str))y2=df['TypeShock']
df['TypeShockNum']= le.fit_transform(y2.astype(str))df_train, df_test=train_test_split(df, test_size=0.33, random_state=2)df.head()**
****上传或生成数据帧后,我们需要定义预测变量和目标变量。在 Python 中,这可以简单地通过在两个方括号中指定预测变量和目标变量来完成。一旦明确定义了变量,我们将需要通过sm.add_constant
向回归中添加一个常量值。然后,可以通过运行sm.OLS
命令轻松检索回归结果。输出非常详细,并提供了一系列统计值,可以对这些值进行进一步的解释。在这种情况下,模型是从随机生成的值中创建的,因此它的解释能力非常有限。
**X=pd.DataFrame(df[['DurationMonths','IncomeLoss','LocationNum','TypeShockNum']])
y=np.asarray(pd.DataFrame(df[['AidMillion']]))
X=sm.add_constant(X)model01_test= sm.OLS(y, X).fit()
model01_test.summary()**
****为了验证整个数据集的分析,我们可以在测试数据集上运行相同的回归。在 Python 中,我们将使用类似的代码,唯一的区别是从df_test
中提取变量。结果似乎是相似的。没有一个变量有显著的系数,强调这个输出只是为了举例说明要使用的代码。
**X=pd.DataFrame(df_test[['DurationMonths','IncomeLoss','LocationNum', 'TypeShockNum']])
y=np.asarray(pd.DataFrame(df_test[['AidMillion']]))
X=sm.add_constant(X)model01_test= sm.OLS(y, X).fit()
model01_test.summary()**
与前面的例子不同,我们不需要上传很多包来产生 OLS 输出。因此,在 R 中的第一步是创建或上传相关数据帧,作为进行分析的基础。与前一个例子一样,对接受援助(Y)的预测将作为一系列预测因素的函数来探讨。我们还可以通过命令as
指定属性,将数字目标变量转换成分类变量。
**df <- data.frame(replicate(1,sample(0:1000, 1000, rep=TRUE)))
colnames(df) <- c("IncomeLoss")df$DurationMonths <- sample(0:12, dim(df), rep=TRUE)df$Type <- sample(c('Draught','Floods','Famine'), size = nrow(df), replace = TRUE)df$Location <- sample(c('Urban','Rural'), size = nrow(df), replace = TRUE)df$AidMillion <- sample(0:1000, dim(df), rep=TRUE)
df$Aid_Given <- ifelse(df$AidMillion <= 500, "Above_500_Mill", "Below_500_Mill")**
为了将目标变量转换成零和一的值,我们可以依靠从as.numeric
到as.factor
的双重转换,以便以可行的形式表达变量来运行回归。随后,我们可以通过命令runif
将数据帧分为测试帧和训练帧。
**df$AidMillion<- as.numeric(as.factor(df$AidMillion))
df$DurationMonths<- as.numeric(as.factor(df$DurationMonths))
df$LocationNum<- as.numeric(as.factor(df$Location))
df$TypeShockNum<- as.numeric(as.factor(df$Type))
df$IncomeLoss<- as.numeric(as.factor(df$IncomeLoss))set.seed(8)
n<- dim(df)[1]
train_df<-runif(n)<0.75
df_train<- df[train_df, ]
df_test<- df[!train_df, ]head(df)**
一旦数据框架准备就绪,相关变量被编码成数值因子,公式就不需要将变量的规格具体化。在 R 中,lm 命令提示直接在公式中定义所有相关变量和数据帧的选项。另一方面,输出不太详细,没有像 Python 中那样指定其他统计参数的范围。同样,该模型不会产生任何显著的系数,因为它是随机生成的。
**model01<- lm(formula = AidMillion ~ DurationMonths+ IncomeLoss+ TypeShockNum+ LocationNum, data= df)
summary(model01)**
为了验证分析,我们可以在测试数据集上运行相同的回归。类似于 Python,同样在 R 中,我们将使用类似的代码,唯一的区别是从函数内部的df_test
提取变量。模型的结果似乎是相似的。没有一个变量有显著的系数,R 平方只是稍微高一点。
**model01_test<- lm(formula = AidMillion ~ DurationMonths+IncomeLoss+TypeShockNum+LocationNum, data= df_test)
summary(model01_test)**
4.R 和 Python 中的模型评估估计
可以通过查看各种维度来评估回归模型,如平均绝对误差、给定一组参数的目标变量预测以及模型比例参数的平方根。所有这些推导可以指示预测元素的位置或其行为。
为了生成目标变量的预测(估计),Python中的一个简单的predict
命令可以生成一系列估计值。
**y_pred=model01.predict(X)
y_pred**
预测器生成后,在 Python 中我们可以通过sklearn.metrics
中的mean_absolute_error
命令计算平均绝对误差。平均绝对误差取 y 的实际值和预测值之间的距离,并求出这些距离的平均值。这是一个重要的指标,表明如果 MAE 较小,则模型在预测方面表现出色,而 MAE 较大则表明您的模型在某些方面可能有问题。MAE 近似为 0 意味着您的模型是输出预测器的完美拟合。在这种情况下,MAE 非常高,这意味着模型不够充分。
绝对平均误差
**ytrue= df[['AidMillion']]
sklearn.metrics.mean_absolute_error(y_true=ytrue, y_pred=y_pred)**
平均绝对误差
为了在 Python 中验证根据一组特定参数对目标变量的估计,np.column_stack
产生一个数组,该数组一旦插入预测command
中,就会根据为每个参数提供的位置产生目标值。在这种情况下,参数将表示为:常量值(1)、持续时间(从 0 到 12)、收入损失量(从 0 到 1000)、位置(0,1)和冲击类型(0,1,2)。
**est01=np.column_stack((1,1,500,1,1))
est02=np.column_stack((1,2,500,0,2))
model01.predict(est01), model01.predict(est02)**
按参数位置的预测值
最后, Python 还允许我们通过应用于回归模型的np.sqrt
命令轻松计算数组的正平方根,从而计算出标准误差。估计量的均方误差衡量误差平方的平均值,即估计值和实际值之间的平均平方差。这是另一个重要的适合度指标,可用于分析回归中的误差是否准确,尤其是当误差接近零时。
均方误差
**np.sqrt(model01.scale)**
标准误差输出
在 R 中,目标变量的预测生成可通过predict
命令激活。这与 Python 非常相似,正如在其他情况下观察到的那样,这里的风格差异是将各种参数的规范放在括号内。
**X<- data.frame(DurationMonths= df$DurationMonths, IncomeLoss= df$IncomeLoss, TypeShockNum=df$TypeShockNum, LocationNum =df$LocationNum)ypred<- predict(object=model01, newdata=X)
head(ypred)**
预测响应示例
在 R 中,MAE 的计算包含在应用于预测和真实目标值的同名命令MAE
中。这与 Python 中的sklearn.metric
非常相似。为了进行模型估计,可以在训练和测试数据集之间比较该值,以确认其有效性。代码下面的输出只代表整个数据集的输出。
**ytrue<- df$AidMillion
MAE(y_pred=ypred, y_true=ytrue)**
MAE 输出
为了计算标准误差,在 R 中的lm
输出已经有了这个细节。事实上,从下面可以看出,剩余标准误差是模型本身生成的可视化输出的一部分。这是 R 中的一个特殊特性,在 Python 中无法以同样的方式找到。
此外, R 还可以选择运行逐步回归,而 Python 没有这个预编码命令。这是一种拟合回归**模型的方法,其中预测变量的选择由自动程序执行。在每一步中,基于一些预先指定的标准,考虑将一个变量添加到解释变量集或从解释变量集中减去。输出显示了 Akaike 信息标准 (AIC),它是样本外预测误差的估计值,因此是给定数据集的统计模型的相对质量。给定数据的模型集合,AIC 估计每个模型相对于其他每个模型的质量。因此,AIC 为模型选择提供了一种手段。**
**library(MASS)
model01_step<- stepAIC(object=model01)**
5.R 和 Python 中的广义线性模型(GLM)
除了线性回归模型之外,还有另一套回归模型考虑了不同类型的目标变量。OLS 模型通常适用于连续变量,而 GLM 模型适用于预测值为二进制或数字离散响应的情况。当目标变量对于每组预测变量值都具有正态分布时,我们可以使用线性回归模型。
另一方面,如果我们试图预测一个二进制响应变量(像是或否的情况),线性预测器的二进制响应集的链接函数将是一个对数函数,如下式所示。
线性预测函数
然后,为了分离平均值,我们可以使用一个指数函数,该函数以某种方式归一化,从而产生一个总是在 0 和 1 之间的值。换句话说,回归模型的值应该被用作目标变量为 1 的概率。
隔离平均值
反向工作,我们就能够通过将目标变量等同于指数函数的完整符号的扩展来制定参数形式的模型。因此,该公式代表适用于二进制目标值的逻辑回归。
逻辑回归模型
****作为 Python 中逻辑回归的一个例子,我们可以指定一个二元变量,如位置(1 =城市,0=农村)和一组数值预测值。然后,sm.Logit
命令激活一个输出的生成,在这种情况下,虽然从解释的角度来看,它不会导致一个强大的模型,但它仍然可以作为一个参考的例子。
**X=pd.DataFrame(df[['DurationMonths','IncomeLoss', 'TypeShockNum']])
y=np.asarray(pd.DataFrame(df[['LocationNum']]))
X=sm.add_constant(X)logistic01= sm.Logit(y, X).fit()logistic01.summary()**
****在 R 中,与之前的公式相似,目标变量是二进制变量。在这种情况下,我们将在括号前指定glm
和family
类型。这一规范似乎非常重要,因为它还提供了根据目标变量的性质调整到其他类型的回归模型的机会,而无需以显著的方式改变公式。重要的是,没有提到伪 R 调整值或对数似然性。相反,与 Python 不同,输出强调了 AIC 和偏差分布。
**df$LocationNum<-ifelse(df$Location=="Urban",1,0)logistic01<- glm(formula = LocationNum ~ DurationMonths+IncomeLoss, data= df, family=binomial)summary(logistic01)**
另一种类型的目标变量可以是事件的计数,例如,某件事情发生了多少个月或多少次。因此,该变量的分布将是最小值为零的出现次数。这类目标变量的回归模型是泊松。下面是推导回归方程的各种数学步骤。最初,我们会将线性预测值等同于对数函数,以使分布正常化。然后,在分离出平均值后,我们可以通过使用指数表达式为泊松回归导出一个完整的参数函数。
链接函数、均值和泊松回归方程
在 Python 中,我们可以通过将目标变量指定为以月为单位的持续时间来轻松运行泊松回归。那么回归的规范似乎与逻辑类型完全不同。我们需要导入stattools
,然后将sm.GL
放在括号前,最后将家族sm.families.Poisson()
声明为回归参数的一部分。下面的结果显示了很强的显著性,但不应过多解释这些值,因为它是随机生成的数据集。
**import statsmodels.tools.tools as stattoolsX=pd.DataFrame(df[['AidMillion','IncomeLoss', 'TypeShockNum']])
y=np.asarray(pd.DataFrame(df[['DurationMonths']]))poisreg01=sm.GLM(y,X, family=sm.families.Poisson()).fit()poisreg01.summary()**
****在 R,泊松回归是一个简单的变量变化和一个新的家庭类型的说明,即poisson
。在逻辑回归建模中,似乎没有必要对前面的例子做进一步的改变。与 Python 在stattools
中的输出不同,它会引出更多关于异常及其行为的信息。输出没有显示与任何预测值的显著关系,如前所述,这是一个随机生成的数据集,仅用于说明目的。
**poisson01 <- glm(formula = DurationMonths~ AidMillion+ IncomeLoss+ LocationNum, data= df_test, family=poisson)summary(poisson01)**
6.最终想法
各种回归说明了根据目标变量的不同性质可以选择的不同类型的模型。要开发一个有效的模型,还需要考虑许多其他因素,例如,目标变量如何在各种预测器之间分布,以及误差在不同场景和多次迭代中的表现如何。此外,选择与主题相关的变量并由之前研究的专业技术支持也很重要。到目前为止所展示的应该只是一个基础,让我们继续尝试不同的回归模型,并从手头的数据中学习!
除了基本的回归概念,还有其他方法通过关联或其他考虑因素来对数据建模,例如维度!建模数据可以采用其他形式和形状。
R 和 Python 在通过朴素贝叶斯分类器建模数据方面的风格差异
数据科学文体学
如何使用 R 和 Python,根据与事件相关的条件的先验知识,预测事件的概率
由于数据科学方法的最具决定性的方面是对数据进行建模,以产生估计和强大的预测,因此有大量的方法和算法可以探索这一目标。这篇博客提出了另一种建模数据的方法,超越了之前关于 决策树的博客中所解释的方法,即朴素贝叶斯分类方法。
这种分类方法是贝叶斯定理的衍生,贝叶斯定理描述了基于可能与事件相关的条件的先验知识的事件概率。这个定理的构想者是英国统计学家、哲学家和长老会牧师托马斯·贝叶斯(1701-1761)。这个定理成为他最著名的成就。贝叶斯定理的一个应用也是基于对概率的解释,即认知置信度的大小(信念、假设等的强度)。)而不是一个频率。这允许将概率应用于各种领域,而不仅仅是引用类附带的领域。
托马斯·贝叶斯 Wikimedia Commons via [Wikipedia](https://en.wikipedia.org/wiki/Thomas_Bayes#/media/File:Thomas_Bayes.gif)
1。贝叶斯定理
在数据科学中,通过将我们以前的知识(称为先验分布)与从观察数据中获得的新信息相结合,贝叶斯定理被应用于更新我们关于特定数据参数的知识。这导致更新的参数知识,也称为后验分布。
解释该定理的主要公式考虑了两个事件。在数据科学中,这两个事件可以是变量类型(预测值和目标值)。我们可以考虑由两个预测值(X=X1,X2)组成的数据集,响应变量 Y 可以由多个类别(y1,y2,y3…)组成。通过贝叶斯定理,我们可以确定对于预测变量的特定组合,哪个类最有可能。*
由分析前类值 y*的可能性给出的先验概率和当响应对应于特定类时数据如何表现的表示的组合产生了后验概率**。等式左侧的分母描述了数据在不参考目标变量的类值的情况下如何表现,也称为数据的边际概率。在没有关于参数的先验知识的情况下,我们可以使用一个无信息先验,它表示所有类值都是同等可能的。在后一种情况下,后验概率仅基于数据。**
在 Y 的 3 个不同的可能类值的情况下,对于常数 X 值,我们可以计算 Y 的三个可能值中的每一个的贝叶斯概率,如下式所示。最大后验假设告诉我们将所选预测值 X 的记录分类为具有最高后验概率的目标变量 Y 的值。
重要的是,即使我们有一个以上的预测变量,类条件独立性假设将各种事件或变量描述为独立的。因此,我们预测因子的选择应该考虑这一假设,确保 X1 和 X2 之间没有关系。
2.Python 中的朴素贝叶斯定理
在 Python 中应用贝叶斯定理的起点是上传相关的库,其中有一个名为MultinomialNB
的多项式朴素贝叶斯分类器,它适用于具有离散特征的分类(例如文本分类的字数)。
import pandas as pd
import numpy as np
from sklearn.naive_bayes import MultinomialNB
import statsmodels.tools.tools as stattools
其次,上传或创建相关数据框架是进行分析的基础。在这种情况下,为了模拟定理,我们可以随机生成一个数据集。在数据集中,预测因子和目标变量的选择可以源于特定的分析需要。在这个例子中,对收到多少援助的预测(Y)被探索为冲击类型和位置(X1,X2)的函数。
df = pd.DataFrame(np.random.randint(0,1000,size=(1000,1)), columns= ['AidMillion'])category = pd.cut(df.AidMillion,bins=[0,500,1000],labels=['Below_500_Mill','Above_500_Mill'])
df.insert(2,'Aid_Given',category)
df.Aid_Given = df.Aid_Given.tolist()df["TypeShock"] = np.random.choice(TypeShock, p=[0.40, 0.30, 0.30], size=len(df))Location = (['Urban','Rural'])
df["Location"] = np.random.choice(Location, size=len(df))df.head()
为了在 Python 中进行分析,我们需要考虑一个测试和一个训练数据帧。可以分割主数据框架,或者选择具有相同变量的另一个信息源。在这种情况下,可以使用train_test_split
命令分割主数据帧。此外,如果打算手动执行贝叶斯计算,我们可以通过pd.crosstab
导出预测值的边际概率和条件概率。
df_train, df_test=train_test_split(df, test_size=0.40, random_state=8)t1=pd.crosstab(df_train['Aid_Given'], df_train['TypeShock'])
t1['Total']=t1.sum(axis=1)
t1.loc['Total']=t1.sum()
t1t2=pd.crosstab(df_train['Aid_Given'], df_train['Location'])
t2['Total']=t2.sum(axis=1)
t2.loc['Total']=t2.sum()
t2
****
为了在 Python 中应用贝叶斯算法,我们需要将每个预测器转换成哑元。这可以通过对解释目标变量所需的每个变量(冲击类型、位置)使用stattools.categorical
命令来完成,并通过命令 pd.concat
将它们连接成一个数据帧。
x_loc_ind= np.array(df_train['Location'])
(x_loc_ind, x_loc_dict)= stattools.categorical(x_loc_ind, drop= True, dictnames=True)
x_loc_ind= pd.DataFrame(x_loc_ind)x_shock_ind= np.array(df_train['TypeShock'])
(x_shock_ind, x_shock_dict)= stattools.categorical(x_shock_ind, drop=True, dictnames= True)
x_shock_ind=pd.DataFrame(x_shock_ind)X=pd.concat((x_loc_ind, x_shock_ind), axis=1)X.head()
将预测变量转换成虚拟矩阵后,为了清晰起见,定义 Y 变量是有用的。在预测器和目标变量被很好地定义后,就可以将代表朴素贝叶斯算法的MultinomialNB
命令应用于训练数据集。
Y= df_train['Aid_Given']
Bayes_01=MultinomialNB().fit(X,Y)
决定性的一步是在测试数据集上测试朴素贝叶斯估计器**。为了做到这一点,我们需要像以前一样将测试数据中的 X 变量设置为虚拟变量。一旦为测试数据集设置了预测变量,就可以使用命令predict
生成预测,该命令为测试数据集中的每条记录生成一个预测值数组。**
x_loc_ind_test= np.array(df_test['Location'])
(x_loc_ind_test, x_loc_dict_test)= stattools.categorical(x_loc_ind_test, drop=True, dictnames= True)
x_loc_ind_test= pd.DataFrame(x_loc_ind_test)x_shock_ind_test= np.array(df_test['TypeShock'])
(x_shock_ind_test, x_shock_dict_test)= stattools.categorical(x_shock_ind_test, drop= True, dictnames= True)
x_shock_ind_test=pd.DataFrame(x_shock_ind_test)X_test= pd.concat((x_loc_ind_test, x_shock_ind_test), axis=1)Y_predicted= Bayes_01.predict(X_test)
在对 Bayes 对象(在本例中命名为 Bayes_01)使用了predict
命令之后,我们最终可以创建一个实际和预测目标类(高于和低于 5 亿)的列联表,这可以帮助我们理解我们的模型的准确性。
ypred = pd.crosstab(df_test['Aid_Given'], Y_predicted, rownames=['Actual'], colnames=['Predicted'])ypred['Total'] = ypred.sum(axis=1); ypred.loc['Total']=ypred.sum(); ypred
为了测试 Python 的准确性水平,我们可以简单地对测试数据集中记录总数中实际条目与预测条目相对应的频率进行求和。总的来说,该模型只有 51%的准确率,这意味着只有 1/2 的预测是正确的。该模型在预测 500 Mill 以上级别时比基线模型表现更好(58.3%对 48%),而在预测 500 Mill 以下级别时比基线模型表现差(44.3%对 48%)。
PerformanceGlobal=(112+92)/400
PerformanceAbove500=(112/192)
PerformanceBelow500=(92/208)
PerformanceGlobal, PerformanceAbove500, PerformanceBelow500
3.R 中的朴素贝叶斯定理
就像我们在前面的例子中所做的一样,在 R 中应用贝叶斯定理的第一步也需要上传或生成包含预测值和目标变量的数据集。在这种情况下,建议使用相同的数据集结构,预测值仍然是冲击类型和位置,而目标变量是给定 aid 的分解。
df <- data.frame(replicate(1,sample(0:1000, 1000, rep=TRUE)))
colnames(df) <- c("AidMillion")df$Aid_Given <- ifelse(df$AidMillion <= 500, "Above_500_Mill", "Below_500_Mill")df$TypeShock <- sample(c('Draught','Floods','Famine'), size = nrow(df), replace = TRUE)df$Location <- sample(c('Urban','Rural'), size = nrow(df), replace = TRUE)df$Aid_Given <- as.factor(df$Aid_Given)
head(df)
一旦选择了数据帧,我们要么将它分成两部分,要么上传一个具有相同变量的相似数据集。为了将从训练数据集生成的预测值应用于测试数据集,有必要使用两个数据框架。如果我们决定使用相同的数据帧,那么runif
命令可以帮助我们做到这一点。
set.seed(8)
n<- dim(df)[1]
train_df<-runif(n)<0.60
df_train<- df[train_df, ]
df_test<- df[!train_df, ]
一旦数据帧准备好进行分析,我们就可以创建两个表来手工计算概率(如果我们愿意的话)。列联表也有助于理解预测值的分类属性在各类目标变量中的分布**。请注意与 Python 的区别,在 R 中,我们必须为每个表指定列名和行名,而没有轴的指定。**
t1<- table(df_train$Aid_Given, df_train$TypeShock)
colnames(t1)<- c("Draught","Floods","Famine")
rownames(t1)<- c("Above_500_Mill","Below_500_Mill")
addmargins(A=t1, FUN=list(Total=sum), quiet=TRUE)t2<- table(df_train$Aid_Given, df_train$Location)
colnames(t2)<- c("Urban","Rural")
rownames(t2)<- c("Above_500_Mill","Below_500_Mill")
addmargins(A=t2, FUN=list(Total=sum), quiet=TRUE)
****
一旦我们创建了列联表,下一步就是通过库e1071
应用贝叶斯算法。命令naiveBayes
比 Python 中的对等命令产生了更多关于先验和条件** 概率的信息。之间的另一个风格差异是在 Bayes 命令中明确指定了解释预测值和目标变量之间关系的公式。**
library(e1071)
Bayes01 <- naiveBayes(formula= Aid_Given~ TypeShock+ Location, data=df_train)Bayes01
R 中的最后一步是通过命令predict
将 object Bayes01 中生成的目标变量的预测类应用于测试数据集,生成最终列联表。和前面的表格一样,我们需要定义rownames
、colnames
和边距来创建一个可读的表格。这是与 Python 风格的一个关键区别。
ypred <- predict(object=Bayes01, newdata=df_test)
test.preds <- table (df_test$Aid_Given, ypred)rownames(test.preds)<- c("Actual:Above_500_Mill","Actual:Below_500_Mill")
colnames(test.preds)<- c("Predicted:Above_500_Mill","Predicted:Below_500_Mill")
addmargins(A=test.preds, FUN=list(Total=sum), quiet=TRUE)
一旦生成列联表,我们就可以评估模型的性能与先验计算中规定的基线值。总体而言,该模型的准确率为 50.4%,这意味着只有 1/2 的预测是正确的,就像我们前面的例子一样。与基线模型相比,该模型在预测 500 Mill 以下级别方面表现更好(51.8%对 46.5%),而在预测 500 Mill 以上级别方面,该模型表现稍差(49.62%对 53.4%)。
PerformanceGlobal=(131+71)/401
PerformanceAbove500=131/264
PerformanceBelow500=71/137
PerformanceGlobal; PerformanceAbove500; PerformanceBelow500
由于数据集是随机生成的,这些结果的唯一目的是说明性的。遵循之前博客中强调的所有步骤,以确保相关的专业知识与精心准备的数据框架相结合,从而产生有意义的分析,这仍然是非常关键的。
在这另一种建模方法之后,下一篇博客将继续解释建模数据的其他方法。敬请关注即将推出的方法!
卡格尔·新冠肺炎公开研究数据集挑战赛(CORD-19)提交的解决方案
这篇文章描述了为 Kaggle CORD-19 竞赛提交的解决方案。
迈向数据科学 是一份以研究数据科学和机器学习为主的媒体刊物。我们不是健康专家,这篇文章的观点不应被解释为专业建议。
CORD-19 竞赛说明
2020 年 3 月 17 日,随着全球新冠肺炎封锁的开始,Kaggle 宣布与艾伦人工智能研究所合作举办新冠肺炎开放研究数据集挑战赛(CORD-19) 比赛,并与 Chan Zuckerberg Initiative、乔治敦大学安全和新兴技术中心、微软研究院、IBM 和国家医学图书馆-国家卫生研究院合作,并与白宫科技政策办公室协调。
CORD-19 数据集
CORD-19 数据集是一个开放的资源,包含超过 167,000 篇关于新冠肺炎、新型冠状病毒和相关冠状病毒的学术文章(随着时间的推移逐渐增加),由上述六位合作者创建。这些文章代表了迄今为止可用于数据挖掘的最广泛的机器可读冠状病毒文献集合。由于冠状病毒文献的快速增加,对这些方法的需求越来越迫切,使得医学界难以跟上。数据集也可以在语义学者上找到。
竞赛的目的是为世界人工智能专家和 NLP 社区提供一个机会,开发文本和数据挖掘工具,帮助医疗界找到高优先级科学问题的答案,并将这些内容的见解联系起来,以支持全球范围内正在进行的新冠肺炎响应工作。
比赛分两轮进行,最初的关键问题列表选自 NASEM 的 SCIED(国家科学院、工程和医学委员会关于新出现的传染病和 21 世纪健康威胁的常务委员会)研究主题和世界卫生组织为新冠肺炎制定的研发蓝图。
第一轮截止日期为 2020 年 4 月 16 日,包括以下主题的 9 项任务:
- 关于传播、潜伏期和环境稳定性,我们知道些什么?
- 我们对新冠肺炎风险因素了解多少?
- 我们对疫苗和疗法了解多少?
- 我们对病毒遗传学、起源和进化了解多少?
- 关于医疗保健已经发表了什么?
- 关于伦理和社会科学的考虑已经发表了什么
- 我们对非药物干预了解多少?
- 我们对诊断和监控了解多少?
- 关于信息共享和跨部门协作,已经发表了哪些内容?
第二轮截止日期为 2020 年 6 月 16 日,包括以下主题的 8 项任务:
- 创建处理与新冠肺炎相关的因素的汇总表
- 创建治疗、干预和临床研究的汇总表
- 创建汇总表,说明与新冠肺炎相关的风险因素
- 创建用于新冠肺炎诊断的汇总表(提交的解决方案)
- 创建与新冠肺炎相关的材料研究汇总表
- 创建汇总表,说明与新冠肺炎相关的模型和未决问题
- 创建处理与新冠肺炎相关的人口研究的汇总表
- 创建处理与新冠肺炎相关的患者描述的汇总表
已提交的诊断类别解决方案:
在第一轮中,大多数提交的文章展示了分析和分类文章类型和摘要内容的各种解决方案。第 2 轮的任务主要集中在 NLP 的“信息提取”技术上,这意味着解决方案必须回答特定的问题或检索与 COVID 相关的特定搜索查询的相关信息。参与者被要求提供 CSV 格式的文章汇总表,并保存到 Kaggle 笔记本的输出文件夹中。的。CSV 文件应包含符合表格格式的汇总表,表格格式在标题为target_table
的文件夹中有描述和演示。我提交的材料涉及任务 4,新冠肺炎的诊断。
为了完成上述任务,我决定从文章的正文中提取相关信息,而不是摘要,因为这种信息可能不会在那个级别提供,而且许多文章没有摘要。
图 1:1000 篇净身文章的文字分布
然而,从正文中提取相关信息的挑战是从提供的文章正文中找到包含相关信息的正确的文本片段。图 1 显示了 1000 篇文章的单词分布,这些文章的正文被清除了停用词。超过 95%的文章平均包含 5000 个单词。因此,找到每篇文章中最相似的句子是至关重要的。
因此,我分三个阶段设计了一个解决方案(见图 2):
- 阶段 1 加载数据并预处理两个数据集的句子:诊断任务和 Kaggle 文章。
- 第二阶段计算任务句和文章正文句的 Word2Vec 句子相似度,选出排名靠前的句子。
- 阶段 3 对排名靠前的句子应用 BERT 预训练问答模型,以找到汇总表查询的准确答案。
图 2:提交的解决方案概述(3 个阶段)
环境设置:
Kaggle 为参与者提供了一个 jupyter 笔记本电脑环境,容量为 10 个 CPU,1 个 GPU,最大 5 GB 磁盘和 16 GB RAM。为了参加竞赛,你需要公开你的私人笔记本。为了这次提交,我在 Kaggle notebook 中开发了我的代码,这些代码可以在我的公共 github 库中找到。
然而,由于在 Kaggle 笔记本上安装变压器的容量问题,我不得不在 azure data science Linux 虚拟机上运行部分代码。
阶段 1:数据加载和预处理:
与数据集相关联的元数据如下:
请注意,在撰写这篇博客时,上面的数字与实际的数据集并不匹配。
从 Kaggle 输入目录加载数据后,生成一个字典来提取结合元数据和 json 文件内容的汇总表所需的列,如下所示:
准备 Kaggle 数据集:
一旦所有的数据都被加载,我在第二阶段和第三阶段将数据二次抽样到“paper_id”、“abstract”和“body”中。然后,最终结果在“paper_id”上与原始数据集合并。
开发了一系列函数来实现预处理步骤:
- 使用 NLTK 英语标记器将文章的正文分成句子,该标记器通过应用词性标记来识别句子。
- 小写所有的单词
- 去掉标点符号
- 标记所有的句子
Kaggle 数据集的第一阶段的结果是句子及其干净标记的熊猫数据框架。
准备任务数据集:
如前所述,对于 CORD-19 Kaggle 提交,选择了第 2 轮的任务 4,并准备了以下数据集:
阶段 2:应用句子相似度
在这个阶段,我在 Kaggle 的句子和任务数据集之间应用了句子相似性技术,如下所示。
句子相似度或语义文本相似度是衡量两段文本有多相似,或者它们表达相同意思的程度。相关任务包括释义或重复识别、搜索和匹配应用程序。用于文本相似性的常用方法从简单的词向量点积到成对分类,以及最近的深度神经网络。
句子相似度通常通过以下两个步骤计算:
- 获得句子的嵌入
- 取它们之间的余弦相似度如下图所示:
图 3: 资料来源:通用语句编码器
Word2vec 是一个用于从文本中学习单词嵌入的预测模型,由 Google research 于 2013 年推出。
简而言之,单词嵌入是将单词表示成向量的一种方式,即语料库中有共同上下文的单词在向量空间中会靠得很近,如男-女、国王-王后等。
图 4: 来源:可视化单词向量
有两种不同的模型架构可用于产生 word2vec 嵌入:连续词袋(CBOW) 或**连续跳格。**前者使用周围单词的窗口(“上下文”)来预测当前单词,而后者使用当前单词来预测周围的上下文单词。更多关于 word2vec 的详细信息,请参见 word2vec 上的本教程和本博客。
我使用了**预训练的 word2vec 单词嵌入。**这些嵌入在谷歌新闻语料库上进行训练,并为 300 万个英语单词提供 300 维嵌入(向量)。参见此链接了解嵌入的原始位置。
Doc2vec 是 word2vec 的扩展,它产生文档的嵌入。这里,“文档”指的是由多个记号/单词组成的更大的块。对于这个解决方案,我还应用了 doc2vec,其中的文档是实际的句子。然而,word2vec 的结果比第 3 阶段稍好,因此,这个解决方案只关注 Word2Vec。
TF-IDF 或术语频率-逆文档频率是一种加权方案,旨在衡量一个单词在更广泛的语料库(整个文章正文)中对文档(或 Kaggle 文章的句子)的重要性。权重“与单词在文档中出现的次数成比例增加,但被单词在语料库中的频率抵消”(教程链接)。
对于语料库 cc 中句子***【s】***中的术语 t ,则 TF-IDF 权重为:
其中:
TFt,s= termt出现在句子 s
dft =包含 term t
N 的句子数量=语料库的大小。
余弦相似度是向量之间常见的相似度度量。直观地,它测量任意两个向量之间的角度余弦。对于向量 a 和 b ,余弦相似度为:
我计算了所有单词嵌入的 TF-IDF 加权平均值以及 Kaggle 数据集和任务数据集的每个句子之间的余弦相似度,并找到了每篇文章中排名最高的句子。代码的更多细节可以在 github 上找到,第二阶段的成果如下。
例如,为一篇文章提取的与任务 4 中的诊断句子相似的排名前十的句子是:
['In addition to the poorly understood but well observed advantageous nature of narrow sutures on the prevention of abdominal incisional hernias, studies assessing for this type of suture and comparing it with other suturing techniques also carry a number of limitations, which may limit the generalizability of their results.',
'Participants will be randomly assigned to their treatment arms in a 1:1 ratio, according to a computer generated schedule, stratified by type of surgery (vascular or non-vascular), using permuted blocks of variable sizes.',
'Their results showed a lower incidence of wound infections, dehiscence, and incisional hernias with their new fascial closure technique as compared to the conventional one.',
'In addition, several studies showed that the clinical detection of ventral abdominal incisional hernias is a simple, rapid, radiation-free, and cost-effective method to rely on .',
'Nevertheless, major studies such as the STITCH trial relied on physical examination as the primary means of detecting incisional hernias .',
'We will use the chi-square or Fisher exact test if the expected count of any of the outcomes is less than 5 per cell for analysis of the incidence of dichotomous outcomes (fascia dehiscence, incisional hernia, wound seroma, wound infection, and intervention for wound complications).',
'To that effect, the modality for the detection of incisional hernias remains subjective to the experience of the physician or investigator.',
'Investigating the prevention of incisional hernias using different suturing techniques requires adequate detection of this complication as a prerequisite.',
'On the other hand, some studies showed that ultrasound can be a superior modality for incisional hernia detection with a sensitivity ranging between 70 and 98% and a specificity between 88 and 100% .']
阶段 3:使用微调过的 BERT 应用问题回答
阶段 1 和阶段 2 的结果是类似于 Kaggle 任务的句子。在第 3 阶段,我使用如下微调的 BERT 应用了问答技术。
问题回答是一项经典的自然语言处理任务,包括确定回答用户“问题”的相关“答案”(从提供的段落中摘录的文本片段)。这项任务是机器理解的一个子集,或者测量机器理解一段文本的程度。[ 1
BERT (来自变形金刚的双向编码器表示)是谷歌在 2019 年推出的预训练语言模型,在各种各样的 NLP 任务中呈现最先进的结果,包括问答(SQuAD v1.1)、自然语言推理(MNLI)、文本分类、名称实体识别等。,只需对特定于任务的数据集进行几次微调。BERT 的关键技术创新是应用了 Transformer 的双向训练,这是一种流行的注意力模型,用于学习文本中单词(或子单词)之间的上下文关系。[ 1
SQuAD( 斯坦福问答数据集)是一个阅读理解数据集,由人群工作者就一组维基百科文章提出的问题组成,其中每个问题的答案都是相应阅读文章的一段文字或跨度,或者问题可能无法回答。“SQuAD 1.1 是 SQuAD 数据集的上一版本,包含 500+篇文章的 100,000+个问答对”。【2】
**如何针对问答任务微调 BERT:**下图显示了如何针对问答任务微调 BERT。BERT 将问题-段落对插入到班数据集中作为输入,[SEP]
表示是用于分隔问题/答案的特殊分隔符。在输出层,它输出Start/End
来表示段落中的答案。
图 5:为 QA 微调 BERT(来源)
这里有一个很棒的关于微调 BERT 的问答教程。为了节省这篇文章的时间和空间,我跳过描述每个步骤。更多细节可以在我的 github 上找到。
**注意:**安装变形金刚库需要相当大的内存。在这个阶段,我不能使用 Kaggle 笔记本,第二阶段的结果保存在一个 csv 文件中,第三阶段是在 Linux 虚拟机上开发的,使用标准 NC6、6 个 vCPUs 和 56GB RAM。
使用了以下 BERT 预训练模型:
阶段 3 的结果是与诊断任务相关的问题的答案。对于此特定任务,文章摘要表格应遵循表格格式:Group 6 - Diagnostics
。Publication date Study-type Study Link Journal Study Type Detection Method Sample Obtained Sample Measure of Evidence Speed of assay FDA approval Added on DOI CORD_UID
因此,提出了以下问题:
学习类型是什么?
用什么检测方法?
样本量是多少?
获得了什么样本?
证据的衡量标准是什么?
化验的速度是多少?
是 FDA 批准的吗?
结果
图 6 显示了 20 个样本的结果。我已经删除了表格中的一些内容,以适应这一页。
图 6:最终结果(20 个样本)
这些结果表明,该解决方案可有效检测特定信息,如方法类型 : pcr、胸部 x 射线、蛋白质印迹、获得的样本 : 血液、纯化病毒、vp1 基因,以及数字数据,如样本量 : 25 gl,2 周或更长时间,> 400,000 名成人、分析速度:该解决方案还显示了提取背景信息的有希望的结果,如 s 研究类型 : 观察、调查和报告、行为实验, fda 批准: *机构伦理研究委员会,FDA 已批准使用普瑞巴林 fibr,美国 FDA 批准。*对于证据度量的情况,提取了精确公式 (ρ ( τ,x p ( τ ) ) 以及概念证据:更快的实验室和数据分析周转、表面等离子体共振(spr)分析、图论和最小生成树(mst)。****
结论和未来工作:
这篇文章描述了为 Kaggle 竞赛(CORD-19)第 2 轮诊断任务提交的解决方案(链接到 github )。该解决方案在两个数据集的数据预处理的 3 个阶段(图 2)中实现:诊断任务和 Kaggle,计算任务句子和文章正文句子之间的单词嵌入和 Word2Vec 句子相似性,并选择排名靠前的句子,最后对排名靠前的句子应用 BERT 预训练的 QA 模型,以找到汇总表的准确答案。
结果(图 6)表明,该解决方案可以有效地检测特定信息、数字数据以及从文章正文中提取上下文信息。
对于未来的工作,作者计划通过应用其他知识提取方法来继续这项研究,包括:微软新冠肺炎 Azure 认知搜索,它对由 Azure 健康文本分析 和 Azure 认知搜索 支持的相同 CORD-19 数据集进行分类。