熊猫数据框中每行应用函数的 12 种方法
来自 Pexels 的 Victor Freitas
编程技巧
如何有效地遍历 Pandas 数据帧中的行,并对每一行应用一个函数。
在数据争论期间,对 Pandas 和数据帧中的所有行应用函数是最常见的操作之一。熊猫 DataFrame [apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html)
函数是做这件事最明显的选择。它将一个函数作为参数,并沿着数据帧的轴应用它。然而,它并不总是最好的选择。
在本文中,您将测量 12 个备选方案的性能。有了配套的代码实验室,你可以在你的浏览器中全部尝试。不需要在你的机器上安装任何东西。
问题
最近,我在为一个电子商务应用程序分析用户行为数据。根据用户进行文本和语音搜索的次数,我将每个用户分为四组:
- **没有搜索:**根本没有搜索的用户
- **仅文本:**仅进行文本搜索的用户
- **仅语音:**仅进行语音搜索的用户
- Both: 同时进行文本和语音搜索的用户
这是一个巨大的数据集,根据选择的时间片,有 10 万到 100 万用户。用 Pandas apply
函数计算它非常慢,所以我评估了其他选择。这篇文章是从中提炼出来的经验教训。
我不能分享那个数据集。所以我挑选了另一个类似的问题来展示解决方案:艾森豪威尔方法。
艾森豪威尔方法:根据重要性和紧急程度将任务分成 4 个部分。
根据任务的重要性和紧迫性,艾森豪威尔方法将其分配到 4 个箱中的一个。每个框都有一个关联的操作:
- 重要而紧急的事情:马上做
- 重要但不紧急:安排留待以后
- 不重要但紧急:委派给别人
- 既不重要也不紧急:删除浪费时间。
我们将使用下图所示的布尔矩阵。重要性和紧急性布尔值为每个动作生成二进制整数值:DO(3),SCHEDULE(2),DELEGATE(1),DELETE(0)。
我们将分析将任务映射到某个操作的性能。我们将测量 12 个选项中哪一个花费的时间最少。我们将为多达一百万个任务绘制性能图。
在 Google Colab 或 Kaggle 打开伴侣笔记本正是时候。如果您想查看运行中的代码,可以在阅读时执行代码实验室中的单元格。继续执行设置部分中的所有单元格。
测试数据
Faker 是一个方便的生成数据的库。在代码实验室中,它用于生成包含一百万个任务的数据帧。每个任务都是数据帧中的一行。它由任务名称(str
)、截止日期(datetime.date
)和优先级(str
)组成。优先级可以是以下三个值之一:低、中、高。
生成的数据帧中的前 5 个任务
优化数据帧存储
我们将最小化存储大小,以消除其对任何替代方案的影响。大约 200 万行的数据帧占用 48MB:
**>>>** test_data_set.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2097153 entries, 0 to 2097152
Data columns (total 3 columns):
# Column Dtype
--- ------ -----
0 task_name object
1 due_date object
2 priority object
dtypes: object(3)
memory usage: 48.0+ MB
代替str
,优先级可以存储为熊猫categorical
类型:
priority_dtype = pd.api.types.CategoricalDtype(
categories=['LOW', 'MEDIUM', 'HIGH'],
ordered=True
)test_data_set['priority'] = test_data_set['priority'].astype(priority_dtype)
现在让我们来看看数据帧的大小:
**>>>** test_data_set.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2097153 entries, 0 to 2097152
Data columns (total 3 columns):
# Column Dtype
--- ------ -----
0 task_name object
1 due_date object
2 priority category
dtypes: category(1), object(2)
memory usage: 34.0+MB
大小减少到 34MB。
艾森豪威尔行动函数
给定重要性和紧急程度,eisenhower_action
计算 0 到 3 之间的整数值。
def eisenhower_action(is_important: bool, is_urgent: bool) -> int:
return 2 * is_important + is_urgent
在本练习中,我们将假设优先级高的任务是重要的任务。如果截止日期在接下来的两天内,那么任务就是紧急。
通过使用due_date
和priority
列计算任务(即数据帧中的一行)的艾森豪威尔行动:
**>>>** cutoff_date = datetime.date.today() + datetime.timedelta(days=2)**>>>** eisenhower_action(
test_data_set.loc[0].priority == 'HIGH',
test_data_set.loc[0].due_date <= cutoff_date
)2
整数 2 表示需要的动作是调度。
在本文的其余部分,我们将评估将eisenhower_action
函数应用于数据帧行的 12 种备选方案。首先,我们将测量 100k 行样本的时间。然后,我们将测量和绘制多达一百万行的时间。
Pandas DataFrame:对每一行应用一个函数来计算一个新列
方法一。循环遍历数据帧的所有行
在传统的 Python 循环中处理每一行的最简单方法。这显然是最糟糕的方法,任何头脑正常的人都不会这么做。
def loop_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2) result = []
for i in range(len(df)):
row = df.iloc[i]
result.append(
eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date)
) return pd.Series(result)
不出所料,这花费了惊人的时间:56.6 秒。
%timeit data_sample['action_loop'] = loop_impl(data_sample)1 loop, best of 5: 56.6 s per loop
它建立了最坏情况下的性能上限。由于其成本是线性的,即 O(n ),因此它为比较其他替代方案提供了一个很好的基线。
线级剖析
让我们使用 line_profiler 来看看是什么花费了这么长时间,但是对于一个 100 行的小样本:
%lprun -f loop_impl loop_impl(test_data_sample(100))
其输出如下图所示:
用于在 Python 循环中处理 100 行数据帧的行级探查器的输出。
从数据帧中提取一行(第 6 行)需要 90%的时间。这是可以理解的,因为 Pandas DataFrame 的存储是【column-major】:一列中的连续元素按顺序存储在内存中。因此,将一行中的元素放在一起是非常昂贵的。
即使我们从 100k 行的 56.6 秒中去掉 90%的成本,也需要 5.66 秒。这仍然很多。
行为主和列为主的数据存储布局。Pandas Dataframe 使用以列为主的存储,因此获取一行是一项开销很大的操作。图片由作者根据Creative Commons BY-NC-ND 4.0 International许可发布。
方法二。用iterrows
函数遍历行
让我们试试 Pandas [iterrows](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iterrows.html)
函数,而不是在 Python 循环中处理每一行。
def iterrows_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2) return pd.Series(
eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date)
for index, row in df.iterrows()
)
大约需要 9.04 秒。循环所用时间的四分之一:
%timeit data_sample['action_iterrow'] = iterrows_impl(data_sample)1 loop, best of 5: 9.04 s per loop
方法三。用itertuples
函数遍历行
Pandas 有另一种方法,[itertuples](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.itertuples.html)
,它将行作为元组来处理。
def itertuples_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2) return pd.Series(
eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date)
for row in df.itertuples()
)
它的表现令人惊讶,只用了 211 毫秒。
%timeit data_sample['action_itertuples'] = itertuples_impl(data_sample)1 loops, best of 5: 211 ms per loop
方法四。熊猫apply
作用于每一排
Pandas DataFrame [apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html)
功能相当多才多艺,是热门选择。要让它处理这些行,您必须传递axis=1
参数。
def apply_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return df.apply(
lambda row:
eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date),
axis=1
)
这也给了我一个惊喜。用了 1.85 秒。比itertuples
差 10 倍!
%timeit data_sample['action_impl'] = apply_impl(data_sample)1 loop, best of 5: 1.85 s per loop
方法五。Python 列表理解
DataFrame 中的列是一个系列,可用作列表理解表达式中的列表:
[ foo(x) for x in df['x'] ]
如果需要多个列,那么可以用zip
来做一个元组列表。
def list_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return pd.Series([
eisenhower_action(priority == 'HIGH', due_date <= cutoff_date)
for (priority, due_date) in zip(df['priority'], df['due_date'])
])
这也抛出了一个惊喜。只用了 78.4 毫秒,甚至比itertuples
还要好!
%timeit data_sample['action_list'] = list_impl(data_sample)10 loops, best of 5: 78.4 ms per loop
方法六。Python 地图函数
Python 的[map](https://docs.python.org/3/library/functions.html#map)
函数接受函数和可迭代的参数,并产生结果。
**def** map_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
**return** pd.Series(
map(eisenhower_action,
df['priority'] == 'HIGH',
df['due_date'] <= cutoff_date)
)
这比列表理解稍微好一点。
%timeit data_sample['action_map'] = map_impl(data_sample)10 loops, best of 5: 71.5 ms per loop
方法七。…向量化…
熊猫的真正力量体现在矢量化上。但是它需要将函数解包为向量表达式。
def vec_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return (
2*(df['priority'] == 'HIGH') + (df['due_date'] <= cutoff_date))
它提供了最好的性能:只有 20 毫秒。
%timeit data_sample['action_vec'] = vec_impl(data_sample)10 loops, best of 5: 20 ms per loop
根据函数的复杂程度,向量化可能需要很大的努力。有时候,甚至可能不可行。
方法八。NumPy vectorize
功能
Numpy 为通过向量化从 Python 迁移到 NumPy 提供了替代方案。例如,它有一个vectorize()
函数,可以向量化任何标量函数来接受和返回 NumPy 数组。
def np_vec_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return np.vectorize(eisenhower_action)(
df['priority'] == 'HIGH',
df['due_date'] <= cutoff_date
)
毫不奇怪,它的性能仅次于熊猫矢量化:35.7 毫秒。
%timeit data_sample['action_np_vec'] = np_vec_impl(data_sample)10 loops, best of 5: 35.7 ms per loop
方法九。Numba 装饰公司
到目前为止,只使用了熊猫和 NumPy 包。但是如果你愿意接受额外的包依赖,还有更多选择。
Numba 常用于加速应用数学函数。它有各种用于 JIT 编译和矢量化的装饰器。
import numba[@numba](http://twitter.com/numba).vectorize
def eisenhower_action(is_important: bool, is_urgent: bool) -> int:
return 2 * is_important + is_urgentdef numba_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return eisenhower_action(
(df['priority'] == 'HIGH').to_numpy(),
(df['due_date'] <= cutoff_date).to_numpy()
)
它的vectorize
装饰器类似于 NumPy vectorize
函数,但是提供了更好的性能:18.9 毫秒(类似于熊猫矢量化)。但是它也会给出缓存警告。
%timeit data_sample['action_numba'] = numba_impl(data_sample)The slowest run took 11.66 times longer than the fastest. This could mean that an intermediate result is being cached.
1 loop, best of 5: 18.9 ms per loop
方法 10。使用pandarallel
进行多重处理
pandarallel
包使用多个 CPU,并将工作分成多个线程。
from pandarallel import pandarallelpandarallel.initialize()def pandarallel_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return df.parallel_apply(
lambda row: eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date),
axis=1
)
在 2 个 CPU 的机器上,用了 2.27 秒。对于 100k 条记录和 2 个 CPU,拆分和簿记开销似乎没有回报。
%timeit data_sample['action_pandarallel'] = pandarallel_impl(data_sample)1 loop, best of 5: 2.27 s per loop
方法 11。使用 Dask 并行化
Dask 是一个并行计算库,支持扩展 NumPy、Pandas、Scikit-learn 和许多其他 Python 库。它为在多节点集群上处理大量数据提供了高效的基础设施。
import dask.dataframe as dddef dask_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return dd.from_pandas(df, npartitions=CPU_COUNT).apply(
lambda row: eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date),
axis=1,
meta=(int)
).compute()
在 2 个 CPU 的机器上,用了 2.13 秒。像pandarallel
一样,只有在许多机器上处理大量数据时,收益才有意义。
%timeit data_sample['action_dask'] = dask_impl(data_sample)1 loop, best of 5: 2.13 s per loop
方法 12。利用 Swifter 实现机会并行化
Swifter 自动决定哪个更快:使用 Dask 并行处理还是简单的 Pandas 应用。使用起来非常简单:只需一个词就能说明熊猫的功能:df.**swifter**.apply
。
import swifterdef swifter_impl(df):
cutoff_date = datetime.date.today() + datetime.timedelta(days=2)
return df.**swifter**.apply(
lambda row: eisenhower_action(
row.priority == 'HIGH', row.due_date <= cutoff_date),
axis=1
)
它在这个用例中的性能预计非常接近熊猫矢量化。
%timeit data_sample['action_swifter'] = swifter_impl(data_sample)10 loops, best of 5: 22.9 ms per loop+
Pandas 数据帧行的迭代性能比较
绘图有助于理解备选方案相对于输入大小的相对性能。Perfplot 是一个方便的工具。它需要一个设置来生成给定大小的输入和一个要比较的实现列表。
kernels = [
loop_impl,
iterrows_impl,
itertuples_impl,
apply_impl,
list_impl,
vec_impl,
np_vec_impl,
numba_impl,
pandarallel_impl,
dask_impl,
swifter_impl
]labels = [str(k.__name__)[:-5] for k in kernels]perfplot.show(
setup=lambda n: test_data_sample(n),
kernels=kernels,
labels=labels,
n_range=[2**k for k in range(K_MAX)],
xlabel='N',
logx=True,
logy=True,
#equality_check=None
)
它生成如下所示的图。
熊猫数据框应用功能的替代方案。左图:对熊猫数据帧的 100,000 行应用函数所用的时间。右图:在 Pandas 数据框架中,以对数比例绘制多达一百万行。图片由作者根据Creative Commons BY-NC-ND 4.0 International许可发布。
以下是对该地块的一些观察:
- 对于这个用例,渐近性能顺序稳定在数据帧中大约 10k 行。
- 由于图中的所有线条都变得平行,性能差异在双对数标度图中可能不明显。
itertuples
和apply
一样简单易用,但性能却提升了 10 倍。- 列表理解比
itertuples
好 2.5 倍,尽管对于一个复杂的函数来说写起来有些冗长。 - NumPy
vectorize
比 List 理解力强 2 倍,使用起来和itertuples
和apply
函数一样简单。 - Pandas 矢量化比 NumPy
vectorize
要好大约 2 倍。 - 只有在许多机器上处理大量数据时,并行处理的开销才有回报。
高效迭代 Pandas 数据帧行的建议
对所有熊猫行独立执行操作是一种常见的需求。以下是我的建议:
- ****向量化数据帧表达式:尽可能这样做。
- NumPy
**vectorize**
: 它的 API 不是很复杂。它不需要额外的软件包。它提供了几乎最好的性能。如果矢量化数据框架并非不可行,请选择此项。 - ****列表理解:当只需要 2-3 个数据帧列,并且数据帧向量化和 NumPy 向量化由于某种原因不可行时,选择此选项。
- **熊猫
**itertuples**
**功能:其 API 类似apply
功能,但性能比apply
高 10 倍。这是最简单、可读性最强的选择。它提供了合理的性能。如果前面三个都不行,就这么做。 - Numba 或 Swift: 使用它来开发并行化而不增加代码复杂性。
了解各种替代方案的成本对于做出明智的选择至关重要。使用timeit
、line_profiler
和perfplot
来测量这些备选方案的性能。平衡性能和易用性,为您的使用案例确定最佳替代方案。
如果你喜欢这个,请:
与此信息图分享:
熊猫 DataFrame apply()函数的 5 个简单快速的替代方法。不需要脂肪库。图片由作者提供,并在Creative Commons BY-NC-ND 4.0 International许可下发布。
原载于ML4Devs.com。**
一个简单的强化学习问题
入门
通过将一次罚球赌注建模为马尔可夫链并使用值迭代,开始强化学习
与麦克斯·奇西克合著
本文假设读者熟悉基本的强化学习(RL)概念。这篇 文章 提供了一个很好的高层次概述。这里的目的是解决一个简单的问题,以便说明 RL 问题是如何设置的,这样您就能够开始编写自己的项目了。
你需要在 100 次罚球中投进 90 次才能赢得赌注。您可以在一年内无限制尝试,并且您需要指定每次尝试的开始时间。你应该如何决定是继续目前的尝试还是重新开始?在成功完成赌注之前,您预计要打多少杆?你的重置策略对这个数字有什么影响?强化学习可以回答这些问题。
根据二项式分布,78%的射手一次尝试成功的概率为 0.14%,这相当于 365 次尝试成功的概率为 40%。让我们假设 78%是你的命中率,因为这给出了赢得或输掉赌注的合理概率(高于 80%几乎保证成功,低于 70%几乎保证失败)。
方法 1:强化学习—马尔可夫链
如果从一个状态转移到下一个状态的概率完全基于当前状态(即先前的状态不影响概率),则随机过程是一个马尔可夫链。这个赌注可以被建模为一个马尔可夫链,以投篮次数和失误次数作为状态。
有 1001 种不同的可能状态(0 到 10 次未命中,0 到 90 次成功)⟹11 * 91 = 1001。因此,赌注可以由 1,001×1,001 矩阵来表示,其中行表示当前状态,列表示未来状态,元素𝑋𝑖𝑗 {∀ 𝑖,𝑗∈[0,1000]}表示从𝑖状态转移到𝑗.状态的概率
首先,让我们假设你一直投篮直到失败或成功(投中 90 篮或错过 11 篮)。然后将矩阵 P 的状态 0 到 1000 定义为[篮子已做,篮子未做]。先列出所有不完整的状态,然后在最后列出代表赢得赌注的状态:
0,1,…,89 = [0,0],[0,1],…,[0,89];
90,91,…,179 = [1,0],[1,1],…,[1,89];
⋮
900,901,…,989 = [10,0],[10,1],…,[10,89];
990,991,…,1000 =[0,90],[1,90],…,[10,90];
概率矩阵 P 的图解(图片由作者提供)
吸收态是一旦进入就不会离开的状态。然后,让矩阵𝑇是矩阵𝑃的子集,只包括跃迁(非吸收)状态。𝑇 = 𝑃₀:₉₉₀,₀:₉₉₀,因为最后十个状态代表成功,所以一旦进入其中一个状态就不会再尝试*(这就是我们将最后十个状态设置为成功状态的原因,这样可以很容易地删除它们)。*
定义矩阵𝐶,使得每个元素𝑋𝑖𝑗都是在进入一个吸收态之前,在任何时间点从𝑖态到𝑗态的预期跃迁数(即使中间进入了其它态)。可以看出,矩阵𝐶计算如下:
那么第 0 行的总和就是成功所需的预期总发射数。当拍摄到失败或成功时,预期拍摄到成功的次数为 35,418 。当基于二项式分布重置时(如果当前状态比新尝试成功的可能性低,则重置),总拍摄次数减少到 13,262:
使用二项式重置策略射击失败/成功时的预期射击次数
方法 2a:强化学习—值迭代:确定最佳策略 我们能够直接计算重置策略和预期投篮次数,因为我们知道投篮次数是一个二项分布的随机变量。然而,许多强化学习问题的底层分布是未知的,例如预测库存管理问题的客户订单或预测扑克游戏中对手的行动。因此,我们将使用值迭代来计算最优重置策略,以说明如何处理未知分布。
首先,我们定义给定环境中代理可用的状态、动作和奖励:
- 定义每个状态对(投篮命中,投篮未中)的奖励为 0,除了设置状态中的赌注是赢,[90,0],[90,1],…,[90,10]。将获胜州的值设置为 100(任意选择)。
- 每种状态下可能的 2 个动作:继续射击或重置赌注。
然后将每个状态/动作对的初始值设置为 0,并重复迭代每个对,以使用贝尔曼方程求解更新的值估计,直到连续迭代之间的最大差异变得任意小。
V(s)=R(s,a)+γ÷V(s′),其中:
- V(s)是当前状态的值
- R(s,a)是状态 s(射击或重置)下动作 a 的回报
- γ是贴现因子
- v(s′)是下一个状态的值
每个状态都有两个值,一个是继续出手,等于出手后的预期奖励值加上下一个状态的值,每个状态都有一个重置下注的值,这个值简单来说就是等于起始状态的值(因为重置时永远不会有奖励)。国家的价值是这两个价值中最高的。例如,89 时的值 makes,10 次未中(下一次出手的结果不是赢得赌注就是重置赌注)等于:
v[89,10] = max(动作[出手]: 78% * 100 + 22% * 0.98 * v[0,0],动作[重置]: v[0,0]);
= max(动作[拍摄]:78.0047,动作[复位]:0.0217);
=动作【拍】:78.0047。
不出所料,这种状态下的最佳政策是继续当前的尝试。这也证明了状态是如何相互依赖的:v[0,0]依赖于 v[89,10],但是 v[89,10]也依赖于 v[0,0],因此,为什么需要继续迭代计算,直到从一次迭代到下一次迭代的值变化几乎为 0。
值迭代代码:
作者提供的图像:使用值迭代的最佳重置策略(例如,如果第 5 次失误发生在第 30 次拍摄时或之前,则尝试重置)
从马尔可夫链代码来看,这种重置策略总共有 13,026 个预期镜头,与二项式方法相比提高了 1.7%。
方法 2b:模拟——计算预期射击次数
由于分布并不总是已知的,我们还将使用数值迭代确定的最佳策略,通过模拟来计算预期的射击次数。
我们模拟大量尝试,取成功前的平均出手次数来估计期望值。为此,我们生成一个足够大的 0 到 1 之间的均匀随机数列表,低于投篮命中率的值表示投篮命中,高于投篮命中率的值表示投篮不中。然后,我们确定是否达到了代表失败的任何重置阈值。如果没有达到重置阈值,那么至少进行了 90 次罚球,结果是成功的。然后计算每次尝试成功所需的击球次数,并取这些值的平均值。
模拟代码:
上述代码 10 次迭代的平均结果是 13,145 个预期镜头,比上面直接计算的值高 0.9%。
运行模拟还有一个额外的好处,那就是我们可以估计直到成功的射击次数的分布:
1217 次模拟成功尝试的模拟镜头分布(图片由作者提供)
结论
我们能够找到我们问题的封闭形式的解决方案,因为它是一个马尔可夫链。然而,许多强化学习问题更加复杂,需要迭代方法。我们展示了这样一种方法,值迭代,也可以解决这个问题。策略迭代是本文没有涉及的另一种有用的方法。
感谢您的阅读,并祝您好运解决自己的强化学习问题!
补充阅读
- https://www . Dartmouth . edu/~ chance/teaching _ AIDS/books _ articles/probability _ book/chapter 11 . pdf
- https://www . cis . upenn . edu/~ cis 519/fall 2015/lections/14 _ reinforcement learning . pdf
应用向量误差修正模型看商品价格的变化如何推动工业生产
不同商品的影响程度和方向不同!
安特·罗泽茨基在 Unsplash 上的照片
新冠肺炎的爆发给各行各业带来了前所未有的负面影响,制造业首当其冲。2020 年第二季度,美国工业生产指数同比下降 14.4%。工业生产的萎缩可能会对投入资源造成负面需求冲击,进而压低大宗商品价格,尤其是能源和金属价格。
同时,商品价格的变化也会影响供应、生产成本,从而影响生产决策。例如,石油输出国组织(石油输出国组织)、俄国和其他国家在 2020 年 4 月达成的延长石油减产的临时协议旨在在冠状病毒封锁导致需求暴跌后支撑油价。
然而,能源和金属价格之间的关系可能更加复杂,这不仅是因为它们之间的多向联系,还因为存在时滞效应、短期和长期均衡。在本文中,我将尝试应用向量误差修正模型(VECM)(1)调查美国商品价格与工业生产之间的关系(2)预测近期工业生产和商品价格的变动。以下所有代码,请参考我的 Github 链接这里。
数据
时间范围
这项工作将侧重于 1990 年 1 月至 2020 年 7 月期间。
商品价格数据
从世界银行的商品市场网站上,我们可以下载不同商品的月度价格数据。其中,以下是能源、工业金属和贵金属的代表。
能源 —原油(布伦特)、煤炭(南非)、天然气(美国)
工业金属 —铝、铁矿石、铜
贵金属 —铂金、白银
顺便提一下,2019 年,石油和天然气这两种传统能源仍然占美国工业部门总能源使用量的 74.0%,这是自 1950 年有数据以来的最高纪录。相比之下,总共只有 9.5%是由可再生能源贡献的,比 2011 年 10.1%的峰值略有下降。多么可悲的情况!!!
工业生产指数数据
美国工业生产指数的数据可以从美联储银行的网站下载。
根据定义,工业生产指数是一项经济指标,衡量位于美国制造、采矿、电力和天然气公用事业(不包括美国境内的公用事业)的所有设施的实际产出。
向量误差修正模型
介绍
E 经济理论认为,经济变量之间在其水平上存在长期均衡,这可以使这些变量保持平稳而不取差异,这就是所谓的协整。
向量误差修正模型(VECM) 是一种在短期关系(差异)之上捕捉此类长期均衡关系(水平)的方法。关于 VECM 及其与向量自回归(VAR)模型的差异的更详细的解释可以在这里找到。
在应用 VECM 之前,让我们研究一下原始时间序列数据是否是平稳的,这意味着时间序列的方差不依赖于时间。如果时间序列是稳定的,那么绘制的图形看起来就像白噪声。
从下面的非差分时间序列和相关矩阵的线图来看,它们很可能是非平稳的,并且它们之间存在协整关系。
(左)所有选定时间序列的折线图;(右)由于规模差异,不包括铝、铜和铂
所选时间序列之间的相关矩阵
非差异变量的自相关函数(ACF)分析
在继续之前,让我们看一下 9 个非差分时间序列的自相关函数图,它表明它们肯定是非平稳的。
差异变量的自相关函数分析
如果我们在第一次差分后对变量作图,差分变量的 ACF 看起来可能是稳定的。这表明每个时间序列都是综合 I(1)的。增强的 Dickey-Fuller (ADF)测试可以进一步证实这一点。
差分变量的增广 Dickey-Fuller 检验—平稳性检验
无效假设是数据是非平稳的。因此,如果 p 值较低,则数据是平稳的,具有较高的统计显著性。
差异变量的 ADF 检验结果有力地支持了时间序列是 I(1)整体的假设。在建模之前,需要对这些时间序列进行一次差分。
格兰杰因果检验——因果关系的检验
N ext,我们想通过格兰杰因果检验来看看时间序列之间是否存在因果关系。潜在的故事是,如果 X 的先前值可以预测 Y 的未来值,那么 X Granger 导致 Y。通过估计 X 对 Y 的滞后值的回归来执行 f 检验。如果 p 值很小,我们可以拒绝 X 的滞后值的所有系数都是 0 的零假设,即滞后的 X 对未来 Y 具有预测能力
为简单起见,下面只显示美国工业生产指数的测试结果。结果显示,除天然气价格外,所有商品价格都对美国工业生产有预测力。因此,我们在剔除天然气价格后进行 VEC 建模是合适的。
Johansen 协整检验——协整检验
在下一步,我们将通过 Johansen 协整检验来检验时间序列之间是否存在协整(长期)关系。
该检验的结果表明,在滞后 1 和滞后 2 的序列之间分别存在 3 和 2 个协整关系。此外,在 95%的显著性水平上,样本期内第 3、4、5 和 6 个滞后时间序列之间存在 1 个协整关系。因此,我们可以说 VEC 建模适合对这些时间序列数据进行建模。
VECM 评估和分析
负荷系数(alphas)代表时间序列收敛到长期均衡关系的速度。
石油、煤炭、铝和银价格的 alphass 值在 0.05 显著性水平上具有统计显著性,而铜和铂价格的 alpha 值在 0.10 显著性水平上具有显著性。然而,铁矿石价格的 alpha 值在统计上并不显著。
从结果来看,我们知道铁矿石价格对美国工业生产指数的外生作用很弱。弱外生性意味着偏离长期不直接影响弱外生变量。这种效应来自于那些非弱外生变量的后续滞后。换句话说,**其他商品价格的滞后是弱外生变量(铁矿石价格)**回归长期均衡的驱动力。
**贝塔系数是实际的长期关系系数。**美国工业生产指数的贝塔系数标准化为 1,以便于解释其他贝塔系数。
其中,白银价格的贝塔系数为-6.0521,这意味着从长期来看,白银价格上涨 1 美元将导致美国工业生产指数下降 6.0521。同样,石油、煤炭和铝的贝塔系数分别为-3.5384、-0.4791 和-0.0793。
相比之下,铁矿石价格的贝塔系数为 1.2618,这意味着从长期来看,铁矿石价格上涨 1 美元将导致美国工业生产指数上涨 1.2618。类似地,铂和铜的贝塔系数分别为 0.1313 和 0.0334。
脉冲响应函数
脉冲响应函数(IRF)显示了一个变量在另一个或同一个变量在前期(月)增加 1 个单位时的响应。蓝色曲线表示单位冲击随时间推移的影响,虚线表示 IRF 的 95%置信区间。在这里,我们试图观察为期 24 个月的脉冲响应。
让我们关注美国工业生产指数的 IRF。
首先,从上图的第一列可以有趣地看到,如果工业生产指数在前一个月经历了 1 个单位增长的冲击,所有商品的价格都会上涨。这一观察结果可以得到需求冲击逻辑的支持。
第二,从上图的第一行我们可以看到石油、铝、铁、铜和银的价格受到一个单位的正冲击会导致工业生产上升,尽管幅度和持续时间不同。背后的基本原理可能是在大宗商品价格上涨的情况下,矿业、电力和天然气公用事业行业提高产量的动力增强。
第三,当煤炭和铂金价格经历一个单位的正向冲击时,会给工业生产指数带来负面影响。这些商品价格的上涨可能会导致制造业的投入成本上升,从而阻碍工业生产。
你可能会注意到,在工业生产指数中可能有两个主导但相互矛盾的因素——制造业和采矿业。大宗商品价格的上涨可能会鼓励采矿和公用事业活动,但会放缓制造业。
如果我们看看其他商品的 IRF,会发现许多有趣的现象。例如,油价每波动一个单位就会对煤炭价格产生负面影响,反之亦然。可以说明替代效应。因此,对每种商品的工业用途以及它们之间的关系进行深入调查可能是值得的。
动态预测
最后但同样重要的是,下面是美国工业生产指数和商品价格未来一年的动态预测图。
事实上,预测与我们的预期惊人地一致。
(一)工业生产短期内难以回升,甚至可能进一步小幅下降。美国经济尚未发出强劲的复苏信号。相对疲软的趋势可能会持续更长时间。
**(二)除白银外,所有商品价格将维持在类似水平。**需求、供应和地缘政治仍然是影响大宗商品价格的基本面。没有一些具体事件,如 3 月份俄罗斯—沙特阿拉伯石油价格战,大宗商品价格趋于稳定。
**(三)目前银价的上涨趋势可能会持续。**除了工业用途,在宽松的货币政策下,白银还可以作为价值储存手段。
结论
本文使用了一个流行的计量经济学模型— 向量误差修正模型(VECM) 来帮助我们**理解工业生产和不同商品价格之间的短期和长期关系。**该模型成功地在数据和现实之间建立了联系。
**脉冲响应函数或动态预测显示的结果符合我们的预期和经济原理。**我希望这能提高你通过经济计量模型分析和预测经济的兴趣。
谢谢您们。下次见。
参考
- 弗朗兹·x·莫尔。(2019).向量误差修正模型(VECMs)简介。
- 约翰·克莱门茨。(2019).方股票之间的长期关系。
- 纱丽玛依特拉。(2019).使用 VAR & VECM 的时间序列分析:统计方法。
- 塞尔瓦·普拉巴卡兰。(2019).向量自回归(VAR)——Python 中的综合指南及示例。
- 美国能源信息管理局。(2020).月度能源回顾。
- 世界银行集团。(2020).【2020 年 4 月商品市场展望。
如果你对我写的东西感兴趣,不要错过成为 Medium 会员的机会。您将可以完全访问所有…
medium.com](https://medium.com/@hudsonko/membership)
如果你有兴趣了解如何应用因子和聚类分析进行国家分类,你可以看看我下面的另一篇文章。谢了。
让我们更多维度地了解这个世界!!!
towardsdatascience.com](/factor-analysis-cluster-analysis-on-countries-classification-1bdb3d8aa096)
为 OpenAI 的赛车游戏应用深度 Q 网络
**摘要。**使用 OpenAI 的经典环境 carr acing-v 0(2D 自动驾驶汽车环境)以及基于定制的环境修改,创建了 Deep Q-Network (DQN)来解决经典和定制环境。通过使用 Resnet18 预训练架构和定制的卷积神经网络结构,这些模型用于解决经典和修改的环境。包罗万象,自定义环境不允许自由移动,最终造成灾难性的遗忘,使经典环境更适合训练。此外,预先训练的模型产生了更随机的结果,而定制的 CNN 架构导致了剧集和奖励之间更明确的相关性。因此,通过应用这种定制设计的架构,该模型能够定期超过 350 的奖励计数。
背景
OpenAI 推出的 Gym 是一个人工智能项目的开源银行。这个数据库已经放在一起,供开发人员使用各种人工智能技术,如强化学习和计算机视觉来解决这些环境[5]。针对这些任务的许多用户生成的解决方案都是公开可用的,从而为未来的开发提供了一个基准。这项研究中探索的环境是 CarRacing-v0,这是一个 2D 自动驾驶汽车环境。使用机器学习,一个依赖于大型数据集的人工智能子集[6],一个代理被训练来学习这个轨迹。
这项研究中使用的特定机器学习算法是深度 Q 网络——一种强化学习技术。这项技术建立在 Q-Learning 的基础上,这是一种简单的无模型强化学习算法[8],通过添加神经网络来实现。简单的 Q 学习算法基于先前的状态执行动作,如果先前没有探索过该状态,则该模型将随机动作[8]。神经网络是一种基于先前数据进行估计的工具[7]。因此,通过使用神经网络来估计 Q 值,而不是基于以前的状态和纯粹的随机动作,可以产生更有效的动作[3]。
如前所述,深度 Q 学习算法是 Q 学习的修改变体。这个独特的公式如下所示。
情商。1 深度 Q 网[13]。
使用深度卷积神经网络作为最佳行动的近似工具,可以通过最大奖励总和来描述,在产生各种观察结果并采取适当行动后,根据行为策略,在每个时间间隔对其进行折扣[13]。
情商。2 深 Q-网络的损失函数[13]。
该等式基于状态 s 和正在执行的动作 a 产生 Q 值。因此,这将产生 r(s,a)处的奖励以及来自未来状态 s '的 Q 值最高点。执行经验中继,代理的经验被存储在一个数据集中。在训练时,Q-Learning 应用于已经存储的经验的随机样本(显示在等式 2 中)。在这个等式中,gamma 是调节未来回报的贴现因子。
基本原理和理由
这项研究的目的是探索机器学习在现实世界中的应用。自 20 世纪 80 年代以来,自动驾驶汽车领域的发展得到了广泛的宣传和认可[15]。然而,这些进步并没有真正满足商业和社会需求。通过应用人工智能各个领域的进步,如机器学习、计算机视觉、强化学习和神经网络,可以生产出自动驾驶汽车来改善人类社会[15]。本文使用这些方法,将有助于讨论这一领域的发展。使用正向强化来激励车辆保持在期望的路径上,类似于为自动驾驶汽车开发的内容。
同样,这篇研究论文也有助于进一步探索不同学科和用途的机器学习发展。例如,这项研究的方法和结果可以应用于其他领域,如自然语言处理[18]和计算机游戏的强化学习[19]。
建筑
1.Pytorch 框架
使用动态计算图和渴望执行深度学习(由短语“定义-运行”而不是经典的“定义-运行”定义),在训练模型时增加了显著的价值。然而,实现这种方法的框架是以牺牲性能为代价的(Chainer[16]),而其他框架则导致使用表达性较差的语言,如 Dynet[17],从而限制了它们的应用。然而,通过 Pytorch 库中提供的实现选项和设计选择,可以使用动态执行,而不会牺牲大量的功率或性能[9]。
此外,Pytorch 通过结合使用自动微分和 GPU 加速来执行动态张量的即时执行。此外,Pytorch 在这样做的同时保持了与用于深度学习的领先库相当的性能水平[9]。这是因为这些张量类似于 NumPy 的“ndarrays ”,同时具有通过 GPU 应用的优势。因此,这加快了训练的速度[14]。
2.预训练模型
预训练模型是过去为解决其他类似问题而创建的模型。这些模型的架构是在模型中免费提供的,不需要太多额外的培训。这些包,尤其是 Pytorch 的包,包含了处理不同任务的模型定义。这些包括图像分类、逐像素语义分割、实例分割、对象检测、人物关键点检测和视频分类[12]。
根据定义,使用预先训练的模型被认为是迁移学习。虽然大多数层已经被训练,但是最终的层必须被操纵和整形,以具有与预训练模型的输出相同的输入。此外,在训练时,用户必须通过选择哪些层不被重新训练来优化预训练模型,因为如果所有层都被重新训练,这使得迁移学习的使用有些无用[10]。因此,典型的是整个预训练模型被冻结。
环境
1。经典环境
经典的 CarRacing-v0 环境既简单又直观。在没有任何外部修改的情况下,状态由 96x96 像素组成,从经典的 RGB 环境开始。对于每个帧,奖励等于-0.1,对于访问的每个轨道区块,奖励等于+1000/N,其中 N 由整个轨道中的区块总数表示。要被认为是成功的运行,代理必须始终达到 900 的奖励,这意味着代理在赛道上的最大时间是 1000 帧。此外,赛道外有一个障碍,如果越过,将导致-100 的处罚,并立即结束该集。在外面,赛道由草地组成,草地不会给你带来回报,但由于环境的摩擦,会导致车辆在赛道上的挣扎。总的来说,这个环境是一个经典的 2D 环境,明显比 3D 环境简单,使得 OpenAI 的 CarRacing-v0 简单得多。
图 1:经典 CarRacing-v0 环境的屏幕截图。
2。自定义环境
经典环境的边界迫使代理处于边界的限制之内。因此,一种理论产生了,用延伸的边界代替草地将迫使车辆在赛道上行驶,从而允许更快的学习时间。移除草只留下两个可能的位置,轨道或边界,然而在边界上会立即结束插曲,这意味着所有的州必须在轨道上。相反,在经典环境中,车辆必须花费大量时间学习草地的力学和施加在其上的摩擦力。越过更显著的障碍仍然给代理一个-100 的奖励,并且仍然导致代理在那一集被认为“完成”。
图 2:自定义 CarRacing-v0 环境的屏幕截图。图片作者。
CNN 模型和修改
虽然使用定制架构和预训练模型之间存在差异,但两者都有一些相似之处。两者的学习率为,贴现值等于
1.定制建筑
神经网络中的卷积层非常适合图像识别。由于该环境的图像识别方法,conv2d 层似乎是最合适的。使用 PyTorch 的 Conv2d 设计了一个网络。
- Conv2d(1,6)(内核大小为 4,步长为 4)
- ReLU 激活(真)
- Conv2d(6,24)(内核大小为 4,步长为 1)
- ReLU 激活(真)
- MaxPool2d(内核大小为 2)
- 展平图层
虽然图像最初是在 RGB 状态下识别的,但是每一帧都是使用灰度过滤器直接转换的。因此,输入通道必须从 1 开始。在 Conv2d 层之后,还必须实现线性层。
- 线性(((9 x 9)x 24),1000)
- ReLU 激活(真)
- 线性(1000,256)
- ReLU 激活(真)
- 线性(256,4)
由于线性图层的输入图层的性质,计算必须反映 Conv2d 图层。通过线性激活层发送的图像将是 84 x 84 的裁剪后图像。第一个 conv2d 层的卷积为 4 x 4,没有任何填充,步长为 4,大小降至 21 x 21。第二层的输入将为 21 x 21,并将再次应用 4 x 4 卷积,这次步长为 1,大小降至 18 x 18。最后,还有一个 MaxPool2d 层,内核大小为 2,因此总大小等于 9 x 9。这个数字乘以 24,即 conv2d 层的输出,产生线性激活的输入。
2.Resnet18 预训练模型
自发布以来,Resnet 已经成为迁移学习领域中最常见的预训练模型之一,因为它具有准确的结果和表示,特别是对于基于计算机视觉的任务。Resnet18 来自 Resnet 预训练模型系列,是具有 18 层的变体,输出 512 个通道。使用未经训练的 CNN,通常会大大减慢训练过程。该模型可简化如下:
- Resnet18 (18 层)(冻结)
- 线性(512,256)
- ReLU(真)
- 线性(256,4)
下图显示了解释的模型。512 的输入层是从 Resnet18 预训练模型接收的,添加的隐藏层的大小为 256,最终输出层的长度为 4。
3.用户化
许多 dqn 的方法是相同的,尤其是对于网络。然而,对待代理人和国家的方式各不相同。采用的许多策略有效地改进了训练时间,但是影响因方法而异。有些方法之前已经解释过了,有些没有。
- 裁剪:84 x 84 框架形状
需要图像的许多部分。但是,不需要底部。事实上,它会扰乱图像识别过程,因为黑色尤其可能被识别为地图的边界。因此,裁剪底部是优化模型所必需的。此外,固定图像的大小也有助于稳定模型。因此,边缘也从 PIL 图像中被裁剪掉,从左边 6 个像素到右边 6 个像素。
- 灰度:3 个通道到 1 个通道
将颜色(RGB)用于计算机视觉任务通常会使模型变得复杂,并引入更多通道。与普通 RGB 图像相比,使用一个通道而不是三个通道可以使模型的灰度级提高大约三倍。很多时候,使用颜色并没有增加任何好处,尤其是对于像 CarRacing-v0 这样简单的模型,其中图像识别部分没有实际学习侧那么重,尤其是因为环境不是 3D 的,而是保持了 2D 方法。
- 图像均衡:均衡图像
对于 PIL 图像,有一个函数将非线性映射应用于输入图像,以便在输出图像中创建灰度值的均匀分布。用于均衡“图像直方图”这种方法用于增加图像的对比度,由于使用了灰度图像,这是一个重要的步骤。
- ε波动:调整ε
培训需要 Epsilon,因为它允许模型进行必要的探索。然而,很多时候,应用的ε是不够的。因此,更多的ε和随机化是必要的。为了纠正这一点,自动调节ε而不是手动调节似乎是最好的办法。这个过程很简单;如果最后的 50 集比之前的 50 集有更好的改善,那么模型应该将ε减小 0.025。如果没有,模型应该改为添加 0.05,因为似乎需要更多的训练来完善模型。ε在其最大值时被设置为 1.0;在这一点上,所有的行动都是随机的。渐渐地,基于ε衰变,它会减少。
- 奖励修改:调整奖励
很明显,由于各种原因,在这种环境下分配的奖励不恰当。对通过边界的惩罚给出了比需要的更大的惩罚,导致代理由于大的奖励惩罚而限制其移动,阻止探索和尝试追踪。因此,奖励不得不从-100 修改为 0,以允许更好的训练,同时惩罚代理人在草地上停留每一步-0.05。奖励修改已针对自定义环境进行了测试。然而,由于灾难性遗忘的重要性,这对训练没有影响。
结果和评估
1.理论:灾难性遗忘
灾难性遗忘是模型可能经历的可怕循环之一,尤其是在使用神经网络时。灾难性遗忘,或有时被称为灾难性干扰,发生在训练一个新的任务或任务类别时,神经网络可能会忘记过去的信息来代替现在的信息[2]。对于定制环境,死亡率高得令人难以置信,这意味着代理在接受培训时几乎会立即死亡。然而,对于其他环境,如 CartPole,这不是什么大问题,但对于有些复杂的环境,如 CarRacing,这就产生了更大的问题。虽然对于大多数传统的 CarRacing-v0 环境来说,这个问题并不突出,但灾难性遗忘似乎正在整个定制的 CarRacing-v0 环境中大规模发生。
汽车,代理人,似乎死得太快,学习新的信息,并逐渐忘记它学习的一切,而是学习保持静止,试图防止超越边界,因为这种行动的反响产生了沉重的奖励惩罚,这是模型试图防止的。
转到经典模型,最初出现了相同的结果。代理人将了解到屏障将产生一个“死亡”状态,使代理人“学会”在一个圆圈中旋转,以试图防止任何死亡和巨额罚款。代理也将忘记它过去在赛道上的经历来做这个序列。这似乎是其他人试图解决环境的常见问题,但允许更多的剧集进行训练和探索,同时调整奖励惩罚,允许模型意识到赛道是目标路线。
然而,改变定制环境的奖励并没有增加变化,更多的训练和探索也没有。对于定制环境,代理人无论如何都会遭受灾难性遗忘的悲剧。
2.比较模型
在显示所示图表之前,前两个图表在最大ε为 1 的情况下被训练,而没有衰减 500 集。然后,根据显示的结果生成这些图表。
当使用预先训练的模型时,它似乎不如完全定制的架构训练得快。为了解决这个问题,冷冻层被解冻以重新训练,这在某种程度上消除了预先训练模型的目的。下面显示了在许多集的课程中使用迁移学习的结果,标题是“迁移学习探索”看起来在图表和它的学习曲线中有大量的波动。每集的奖励似乎是下降,然后上升,再上升。然而,如果不考虑异常值,仍然有轻微的上升趋势。
图表 1:使用来自 Resnet18 的预训练模型。
另一种方法使用定制的架构,产生了类似的结果,但结果的变化更加平缓,如下图所示,标题为“CNN- Stable Exploration”,再次将情节与奖励进行了比较。每集的奖励会逐渐增加,但并没有预期的那么快。该模型的奖励计数在 112 的值达到峰值。
图表 2:具有稳定ε的定制 CNN。
通过为初始训练过程分配更多的剧集,训练过程被加速。不是 500 集训练,而是 1000 集。ε衰减也增加了 15%,以允许更随机的初始探索。结果显示在下图中,带有经典的标题“CNN”看到的变化比其他图表更直接,表明学习的速度更快。此外,该模型在高于 125 的奖励计数处达到峰值,这比图 2 中的略低。然而,图 3 的峰值出现的时间比图 2 的峰值快大约 400 次。
图表 3:ε衰减较少的自定义 CNN。
最后一个图表,图表 4:CNN——更多的ε,有最好的结果。初始训练集比只有 500 个训练集的初始图表大五倍。不仅有 2500 个训练集,而且初始 epsilon 分配从 1.0 增加到 1.5。因此,允许更多的培训和学习,这可以从下图中看出。根据图表 4,奖励计数多次超过 350 的值。
图 4:更多训练和更多 epsilon 的定制 CNN。图片作者。
正如演示的那样,预训练模型似乎每集都有更随机的奖励流,同时似乎在开始时比定制模型训练得更快。然而,可以看出,与使用预训练模型的模型相比,应用定制 CNN 的模型逐渐增加每集的奖励,并导致更高的奖励峰值。
这些假设在许多测试中保持一致,上面给出的图表似乎不是这个假设的异常值。然而,无论使用哪种模式,它们都没有获得足够的奖励来被认为是成功的,因为没有一集汽车的总奖励是 900,更不用说连续 100 集了。
讨论研究和未来展望
1.双 dqn(双学习)
虽然 dqn 对许多环境都很有用,但一种称为双 dqn 的 dqn 变体——在双学习下——通常更好、更有效。与双 dqn 相比,dqn 往往更乐观,双 dqn 往往对选择的行动更怀疑,计算采取该行动的目标 Q 值[11]。总的来说,双 dqn 有助于减少对 Q 值的高估,使训练更快,学习更稳定[11]。由于该信息,可以理解,与所应用的经典 DQN 相比,使用双重学习对于该环境将会更加有效和有益。
2.Google Colab GPU(训练时间)
训练时间是深度学习的一个重要部分,因为学习需要大量时间来学习模型所应用的任何过程。在许多情况下,GPU 是必不可少的,因为它们可以成倍地提高训练速度,从而更快地训练模型,分配额外的训练时间来完善模型,并调整额外的变化。
将 Google Colab 用于可访问的云 GPU 允许更快的训练,然而,云程序对于需要渲染的环境来说不是很好。对于 CarRacing-v0 环境,在一集之后使用经典的“env.render()”是不可能的。在花了相当长的时间尝试在 Google Colab 上配置环境后,最好的结果是在运行代码后通过创建一个允许“show_video()”的函数来渲染最后一集。然而,这并不实际,因为它不允许我检查每一次迭代和每一集,并能够仔细分析发生了什么。
3.环境缺陷
虽然 OpenAI 有很多公众可以轻松访问的开源环境,如 CarRacing-v0,但在环境开发中并不完全出色。底部信息的相当不合标准的放置会妨碍代理的性能。应用在赛道上的糟糕的物理学迫使车辆原地打转。奖励分数和其他缺陷一起破坏了环境的整体结构,使代理的训练变得很有挑战性。
4.更多探索(艾司隆)
对于 Q 学习算法的任何变体,探索是学习如何发生的。允许更多的ε允许模型了解更多关于环境的信息以及如何解决环境问题。真的,理论上,更多的训练和更多的探索应该能够推动任何模型学习一个足以解决它的环境。
5.参考他人的作品
这个项目适用于“开放的健身房环境”社区的一个利基部分。如前所述,在这样的项目中使用 DQN 从任何角度来看都不是最佳的做法。然而,其他论文已经尝试使用这种方法,取得了不同程度的成功。例如,两名斯坦福大学研究人员在 2018 年 12 月发表的一篇论文试图将 dqn 用于相同的环境。这篇论文名为“简单赛车游戏的强化学习”,由 Pablo Aldape 和 Samuel Sowell 撰写。
Aldape 和 Sowell 在他们的项目中没有裁剪图像,而是将其留在经典的 96 x 96,节点大小为 9216。然而,他们随后提到,他们没有灰度化,甚至没有保留 RGB 颜色,而是每个节点都接受其各自像素的绿色通道[1]。这似乎是一种复杂的颜色操作方式,而正常的重新缩放可能更容易也更有效。此外,应该更好地利用作物,因为仪表栏上的颜色污染了环境的绿色屏幕,84 x 84 的作物可以消除它。
然而,他们的项目和这个项目也有一些相似之处。例如,分享了使用预培训模型作为一种培训形式。此外,两个模型都没有超过 900 的奖励阈值,因为两者都没有计算能力或时间来完全解决环境问题。
没有使用 DQN 解决 CarRacing-v0 环境的好例子。因此,下一篇与这种环境最接近的论文是一位法国博士生写的。在论文中,作者 Dancette 使用了卷积神经网络,并在结论中详细描述了该模型是如何训练的。Dancette 声称,该网络可以识别形状,以使汽车保持在所需的路径上[4],这比尝试 DQN 对这种环境更有用,因为这种环境最重要的部分是识别轨道并保持在其边界内。
这三个模型都收敛到不同的最大奖励计数,并能够在一个数字表中表示。可以看出,虽然这个 DQN 优于 Sowell 和 Aldape,但 Dancette 的神经网络模型明显更有效和实用。
这款 DQN 型号:300–350
索维尔和阿尔达普的 DQN 模型[1]:150–200
丹塞特的神经网络模型[4]:450–500
6.未来展望
对于这种环境,使用其他技术可能是有益的,例如,双 dqn 或近似策略优化(PPO)。如果 DQNs 再次用于这种环境,将需要更多的 epsilon、情节和训练,然而,这将比使用其他更可靠的技术更不实际。如果要再次使用 dqn,它们应该更好地应用于更短、更可预测的不同自动驾驶汽车环境。此外,这些不同的强化学习技术应该在更高级的 3D 环境中使用。与其他模拟的自动驾驶汽车环境相比,CarRacing-v0 相当简单。通过在几个 3D 车辆环境中训练使用深度学习算法(如神经网络和策略梯度)的各种模型,可以在自动驾驶汽车方面取得进展。
参考文献
[1]阿尔达佩,p .,&索维尔,S. (2018 年 12 月 18 日)。一个简单赛车游戏的强化学习。2020 年 9 月 14 日检索,来自https://web . Stanford . edu/class/aa 228/reports/2018/final 150 . pdf/
[2]《终身机器学习,第二版》终身机器学习,第二版|人工智能与机器学习综合讲座,www . morganclaypool . com/doi/10.2200/s 00832 ed 1 v01y 201802 aim 037。
[3] Mnih,v .、Kavukcuoglu,k .、Silver,d .、Graves,a .、Antonoglou,I .、Wierstra,d .、& Riedmiller,M. (2013 年 12 月 19 日)。用深度强化学习玩雅达利。ArXiv.Org。https://arxiv.org/abs/1312.5602
[4]丹塞特,C. (2018 年 04 月 09 日)。[Tutoriel]2020 年 9 月 10 日从https://cdancette.fr/2018/04/09/self-driving-CNN/检索到的
[5] Gym:开发和比较强化学习算法的工具包。(未注明)。OpenAI。检索于 2021 年 1 月 20 日,来自https://gym.openai.com/
[6]西蒙·奥(2018)。简单介绍机器学习及其在通信系统中的应用。IEEE 认知通信和网络汇刊,4(4),648–664。https://doi.org/10.1109/tccn.2018.2881442
[7] Krose,b .,Krose,B. J. A .,Smagt,P. V .,> Smagt,P. (1993 年)。神经网络导论。计算机科学杂志,1–135 页。https://www . researchgate . net/publication/272832321 _ An _ introduction _ to _ neural _ networks
[8]Fran ois-Lavet,v .,Henderson,p .,Islam,r .,Bellemare,M. G .,& Pineau,J. (2018 年)。深度强化学习导论。机器学习的基础和趋势,11(3–4),219–354。https://doi.org/10.1561/2200000071
[9] Paszke,a .,Gross,s .,Massa,f .,Lerer,a .,Bradbury,j .,Chanan,g .,Killeen,t .,Lin,z .,Gimelshein,n .,Antiga,l .,Desmaison,a .,KPF,a .,Yang,e .,DeVito,z .,Raison,m .,Tejani,a .,Chilamkurthy,s .,Steiner,b .,Fang,l .,l .,Chintala,S. (2019 年 12 月 3 日)。PyTorch:命令式的高性能深度学习库。ArXiv.Org。【https://arxiv.org/abs/1912.01703
[10]微调火炬视觉模型。(未注明)。检索于 2020 年 9 月 14 日,来自https://py torch . org/tutorials/beginner/fine tuning _ torch vision _ models _ tutorial . html
[11] Hasselt,V. H .,Guez,a .,& Silver,D. (2015 年 9 月 22 日)。双 Q 学习的深度强化学习。ArXiv.Org。https://arxiv.org/abs/1509.06461
[12]火炬视觉模型。(未注明)。检索于 2020 年 9 月 14 日,来自https://pytorch.org/docs/stable/torchvision/models.html
[13] Mnih,v .、Kavukcuoglu,k .、Silver,d .、Veness,j .、Bellemare,M. G .、Graves,a .、Riedmiller,m .、Fidjeland,A. K .、Ostrovski,g .、Petersen,s .、Beattie,c .、Sadik,a .、Antonoglou,I .、King,h .、Kumaran,d .、Wierstra,d .、Legg,s .、& Hassabis,D. (2015 年)。通过深度强化学习实现人类水平的控制。自然,518(7540),529–533。https://doi.org/10.1038/nature14236
【14】py torch 是什么?。(未注明)。检索于 2020 年 9 月 14 日,来自https://py torch . org/tutorials/beginner/blitz/tensor _ tutorial . html
[15] Janai,j .,Güney,f .,Behl,a .,& Geiger,A. (2017 年 4 月 18 日)。自动驾驶汽车的计算机视觉:问题、数据集和技术状态,ArXiv.Org。https://arxiv.org/abs/1704.05519
[16]星矢·托奎、肯塔·乌诺、绍黑·希多和贾斯汀·克莱顿。Chainer:深度学习的下一代开源框架。《2015 年第二十九届神经信息处理系统(NIPS)年会机器学习系统(LearningSys)研讨会论文集》。
[17]纽比格、戴尔、戈德堡、马修斯、阿马尔、阿纳斯塔西索普洛斯、巴列斯特罗斯、蒋、克洛索、科恩、杜、法鲁基、甘、加莱特、纪、孔、昆科罗、库马尔、马拉维亚、米歇尔、小田滋、理查森、萨福拉、斯瓦亚姆 DyNet:动态神经网络工具包。ArXiv 电子版,2017 年 1 月。
[18]k . Narasimhan、t . Kulkarni 和 r . Barzilay(2015 年 6 月 30 日)。使用深度强化学习的文本游戏语言理解。ArXiv.Org。https://arxiv.org/abs/1506.08941
[19]林,张,李,林,杨振宁.(2019).使用基于强化 Q 学习的深度神经网络玩视频游戏。电子学,8(10),1128。【https://doi.org/10.3390/electronics8101128
将人工智能应用于商业,去神秘化
如何将你的人工智能项目分解成容易理解的、有经济意义的部分
图片来源:pexels.com
人工智能和数据科学领域一直在经历一个极端的炒作周期。这项技术有着巨大的前景,但所有嘈杂的宣传都使筛选出价值实际在哪里,以及如何利用已经容易获得和访问的现有人工智能组件变得令人生畏或令人生畏。
虽然每个人都在谈论人工智能是商业和人们生活的下一次飞跃,但对于大多数各级商业领袖来说,自然的情感问题如下:
- 我的组织如何确保我们不会错过一些持续加速的重要事情?
- 我如何才能拥抱这些新技术,让它们给我的公司带来高价值的影响,同时又不会在这个过程中冒太多金钱或其他宝贵资源和精力的风险?
在这篇文章中,我试图通过分离炒作的情绪来勾勒出一个在人工智能和数据科学中取得成功的真正战略。我将尝试用一个简单易懂的方法来展示一个成功的人工智能或数据科学项目的研发过程。它将基于从许多项目中吸取的艰难教训。
1.澄清大术语:人工智能、数据科学、机器学习、大数据……还是什么?
在开始商业案例驱动的研发过程之前,我将试着澄清一下“大术语”,这样我们就都在同一页上了。围绕着他们每个人都有很多议论,但是不要让你自己被这些所吓倒或冲昏头脑。尤其是因为这些对不同的人来说意味着不同的东西,因为大肆宣传和过度使用。
人工智能
你可能已经注意到我在上面交替使用了术语 AI(人工智能)和数据科学。我故意这样做的。当谈到数据科学应用时,人工智能作为一个术语似乎出现在许多炒作中,它是一个注意力抓取器,它有一种冷静,让我们感觉我们生活在科幻世界的边缘。但从技术上来说,“AI”是一个相当模糊的术语,没有明确的界限,是一种让机器看起来和行为(有点)智能的每个学科的总称。
数据科学
这个名词是家里最小的。它指的是任何涉及数据分析和算法的东西,尤其是它们背后的科学:大数据分析/数据挖掘、机器学习、统计学、数学、信息和计算机科学。
那是 AI 还是 DS?
从现在开始,在这篇文章中,我将更多地使用“数据科学”这个术语,以达到“综合”的目的。
某个智者(我不记得具体是谁了)曾经说过,只要有东西被称为 AI,我们就在和“科幻小说”打交道。但一旦它在现实生活中实现,它就变成了一门“计算机科学”,而不再是人工智能了。这可能解释了为什么人工智能似乎总是关于未来,而不是过去或现在,尽管我们在日常生活中已经使用的许多东西在十年前肯定会被认为是科幻小说中的东西。
可能出于同样的原因,我个人在和朋友开玩笑、谈论人工智能奇点或处于“推销员模式”时会使用人工智能这个术语😉试图引起注意。当我在家做黑客、做实验、学习、参加 Kaggle 比赛,或者与团队讨论项目和策略时,我会谈论并查找数据科学。
这也适用于命名团队——最有可能的是,你会有一个数据科学团队为你的任何人工智能或数据科学商业机会工作。这样的团队将由数据科学家(能够处理数据探索、研究和商业机会验证的科学方面的数据科学博士)和数据工程师组成,他们知道如何处理大数据框架,如何将研究成果实施到运营环境中,等等。
机器学习
机器学习听起来几乎像人工智能,但在数据科学社区中,它是一个更具体的技术术语,指的是人工智能中专注于机器智能的学习部分的特定组件或过程。有许多机器学习算法,如(深度)神经网络、决策树、贝叶斯等,以及这些算法可以应用的应用领域或数据。数据可以是任何东西,从交易数据到图像、视频、音频和振动模式分析,甚至是音乐、自然语言处理(NLP)、用于预测性维护用例的感官诊断数据等。本质上,这些算法都是基于某种统计程序。
大数据
该术语实质上是指任何存在的数据量太大,以至于无法通过单台计算机中的“传统”数据处理工具进行处理或分析,这反过来需要特定的方法来解决与处理大量数据相关的问题。例如,重负载问题可能来自所需数据存储的大小(要求分布式存储和检索系统),或者来自近乎实时地处理信息的需要(要求机器学习方法),等等。
其他条款
显然,在研究这个主题时,您可能会遇到很多更密切相关的术语,包括数据挖掘、大数据分析、商业智能(BI)等,但为了简洁起见,我将把自己限制在今天装饰炒作场景的几个最大胆的术语上。
2。制定数据科学战略——先决条件理解
建立数据科学战略始于理解其基本前景、适用性和局限性。
2.1 商业数据科学的基本前景
就商业而言,数据科学的用处有两个主要原因。它帮助您寻找新的收入来源,并帮助您避免因效率低下、欺诈或人为错误而损失金钱,它通过查看您的数据并对其应用数据分析和机器学习技巧来实现这一点。
**举个例子。**早在 2005 年,我就曾在 Skype 早期担任后端开发人员。当 Skype 推出其第一项高级功能 SkypeOut calls 并大幅提升其收入时,它也开始因信用卡欺诈退款请求和罚款而损失约 10%的收入,并受到支付提供商的威胁,如果我们不找到减少欺诈的方法,就将被关闭。最初,我们开发了不同种类的硬编码欺诈检查,以阻止最明显的欺诈模式,但这是一场与风车的斗争——欺诈者擅长调整他们的行为,以至于在程序部署后几天,人工分析和硬编码的欺诈模式检查就变得无关紧要了。在某个时候,我开始开发一个基于朴素贝叶斯的机器学习管道,并最终成功地实时检测到 90%的欺诈交易,假阳性率保持在 0.1%以下。此外,它能够近乎实时地学习新的欺诈模式,即使欺诈形式不断演变,也能保持效率。
2.2 AI 在商业中的适用性
数据科学的好处在于,它的主要实现策略形式与您应用它们的领域无关。无论哪里有数据堆积或流动,都很有可能隐藏着巨大的积极影响的未开发机会。
顶尖的数据科学团队通常能够以相同的方式处理任何类型的数据,无论是处理交易、图像、视频、音频、振动、自然语言文本处理等。基于这些数据的具有重大商业价值的应用可以包括信用评分、欺诈检测、客户终身价值预测、图像识别、预测性维护、自然语言处理(NLP)聊天机器人、入侵检测(网络安全)、转换和流失预测等等。
2.3 AI 在商业中的局限性
到目前为止,它看起来就像一个普通的软件项目,对吗?只是加入了一些人工智能带来的酷感,就这样?错了!
这就是数据科学项目与普通软件项目的显著区别,如果你不注意它的局限性,它会变得非常混乱,几乎肯定是你浪费时间和金钱的项目;另一方面,如果你充分考虑到这种差异,它会对你的业务战略做出非常可控的成功贡献。
数据科学项目和普通软件项目之间的显著区别在于它的主要局限性:
1。概率的本质。在商业用例的背景下,机器学习算法通过概率而不是确定来工作。当考虑到它的答案时,你总是会有准确性的问题。请记住上面的欺诈检测示例 —总会有一定数量的“假阴性”和“假阳性”结果,但是检测到 90%的欺诈(这意味着避免了 9%的收入损失)仍然会使公司处于一个明显更好的境地,消除了支付提供商停止服务的风险,避免了重大损失,并且为了更大的利益,使欺诈者的日子更难过—即使代价是损失不到 0.1%的合法交易。
如果你的商业案例对“错误”答案零容忍,你就不能应用这些方法。然而,如果您的业务案例能够“足够好”地准确工作,那么它就变成了实现“足够好”结果的问题。
**例如,在自动驾驶汽车的一个非常极端的情况下,**当你有级联的人工智能组件在发挥作用时,人们可能会问,在那里出现错误是怎么回事!?答案是,在系统的传感实时数据分析中可能会有“错误”(用机器学习的术语来说),但结合某些鲁棒性原则的应用,这些错误可以缩小到单个组件,这些原则要求永远不要依赖单个数据源或传感器,这样这些错误就不会对任何人的财产或健康造成危险。
**2。做能力的问题。**数据科学的概率性质引出了另一个重要的问题:即使你的业务案例能够在行动过程中接受一些“错误”的答案,那么“足够好”的准确性水平到底能不能达到?你可以开发完整的框架软件,将你的机器学习算法无缝集成到你的操作环境中,它可以扩展等,但如果 ML 算法真的无法准确地做出对你的商业案例有意义的决策,那么围绕它的所有产品开发都将是浪费,甚至是适得其反。
这是数据科学项目的一个不变的现实——必要的准确性并不总是可以达到的(至少第一次尝试是不行的)。
3.该过程
列出了上面的注意事项后,接下来的事情实际上非常简单明了。
图片来源:【mooncascade.com
第一步:提出“问题”
任何数据科学项目的核心都是你希望你的系统回答的既定问题。当你考虑你的第一个(或下一个)人工智能应用时,确保你确切地知道你将回答什么问题,并确定它与你的业务影响有明确的联系。
问题示例:
- **问题:**我们能否预测保险申请中的欺诈行为?我们能否实时适应欺诈模式的变化?**影响:**避免因诈骗而亏钱。
- **问题:**能否检测危险品(放射性物质、武器部件等。)根据对相关文件、物流信息以及海港和机场货物的 x 光扫描结果的分析而被走私?**影响:**更安全的居住社区。
- **问题:**我们能否在系统实际崩溃之前预测机械故障?(这被称为预测性维护问题,例如,可以通过收听连接到机器主体的音频传感器并分析振动模式的变化来回答。)**影响:**避免机械故障和收入损失,甚至可能由此产生的损坏成本。
第二步:确定“足够好”的准确度对你来说意味着什么
一旦你确定了项目的问题,但在开始投入资金、时间和其他资源进行繁重的开发工作之前,重要的是要确定你必须如何回答这个问题,才能让你的商业案例有意义。换句话说,您需要为您的系统量化某种在业务案例中有意义的关键性能指标(KPI)目标。
**举个例子。**在欺诈检测的情况下,当触发欺诈检测时,您希望在实施自动交易阻止的同时确保可接受的误报率。KPI 目标可以是,例如,对于每 10%的检测到的实际欺诈,0.01%的误报是可以接受的,这样自动交易阻止才有意义。这在实践中为数据科学家提供了强有力的指导,他们可能会很容易地隔离相当大一部分欺诈,然后,对于确定性不再那么好的另一部分,可以应用一些其他措施(而不是简单的自动阻止)。
第三步:数据探索、研究和影响验证
直到流程的这一步,除了识别问题和建立有意义的 KPI 目标的一些基本工作之外,您几乎没有花费任何资源。
现在关键的问题是:这真的能做到吗?您的问题能否以超过最低 KPI 阈值的质量水平得到回答?**这是业务影响验证步骤。它的目的是识别所有相关的数据源,探索、操作、重组和整理数据,建立机器学习模型等。这将会产生影响。这一步的结果包括培训、测试和验证数据集,**允许您在实际的软件产品开发开始之前,就可以明确地确认产品的可行性。
通过使用术语“可论证地”,我指的是根据科学标准和质量的过程的可重复性——记住,我们正在与工作中的数据科学家(通常是博士级)打交道,重点是“科学家”这个词。科学方法的关键品质之一是可重复性。这意味着,从技术上来说,您的研究和数据探索的结果包括所有确切的步骤、脚本和数据字典,这些数据字典准确地显示了数据是如何获得、转换并划分为训练、测试和验证数据集、机器学习模型和演示说明的。
可以想象,这是需要投入一些初始资源的第一步,因为研究和数据探索是需要由有专门技能的人来完成的工作。尽管如此,与接下来的产品开发项目相比,这通常是相当精简和吝啬的。这里的想法是,只要项目的可行性仍然悬而未决,就要避免投资于产品开发。只有在研究证实了影响后,投资产品开发才有意义。你需要愿意冒险投资这些验证周期,对你的基金应用合理的资金管理方法和每个项目的止损决策策略。但是,除非你喜欢混乱的公司过山车,否则你不应该在数据推测中验证你的业务影响之前,冒险投资于产品开发。
当研究未能验证最初冲刺阶段的推测影响时,可能有几个原因:
- 你正在处理的数据可能太肤浅,或者缺乏容易发现和有意义的应用信号。在这种情况下,你还没有开始在产品开发上花费资源,这很好,你可以开始寻找其他想法来产生影响。
- 也可能是相关信号在您的数据中很明显,但它拒绝越过允许您验证业务案例的预期 KPI 目标阈值。在这种情况下,您可以与您的数据科学团队讨论构建更多您尚不具备的数据功能的可能性。这可能意味着需要几个月的时间让您现有的产品,即生成相关数据的产品,收集和存储额外需要的数据,之后您可以再次尝试您的研究,看看有问题的 KPI 目标是否可以实现。
第四步:产品开发
一旦您在步骤 3 中的研究成功,围绕结果开发适当的数据产品,使其无缝集成到您的运营环境中,扩展并使您能够创造真正的影响。
这个阶段看起来更像是常规的软件产品开发。在这里,你可以应用同样的原则,从构思和设计冲刺(如果涉及 UI 交互)开始,来验证目标用户是否会抓住新产品并接受这个想法。然后,您将开发您的第一个 MVP (最小可行产品)来进一步验证您是否在正确的轨道上,但这一次有来自现场的确凿证据,并迭代地继续开发您的产品并增加对您的业务案例的影响。
只要产品保持相关性,你通常总会有需要改进的地方。除了产品的常规软件开发部分之外,您还将继续监控产品的数据科学部分的性能,偶尔会重新审视研究周期,以排查数据源中的变化或加强/优化结果的影响。
4.大局
希望上面的流程布局能给你一些启发,告诉你如何开始将数据科学引入你的公司。在现实生活中,正如成功的产品一样,将会有更多连续的嵌套开发周期一个接一个地进行,并且您将应用于实现它们的原则将会随着您对该主题的学习和熟悉而发展。然而,一个蓬勃发展的数据科学项目的本质仍然是一样的:成功的数据科学产品是研究优先项目的产品,成功的数据科学产品管道战略是基于这样的项目。
成功的主要驱动力基本上是在整个过程中保持这两个原则,在任何步骤中都不要忘记:
- 确保你总是知道你想要的影响会是什么。确保你所做的事情确实意义重大,具有积极的影响。这是任何事物在商业环境中生存的基本规则——不仅仅是数据科学。
- **尽早并尽可能经常地验证关键假设。**在处理数据科学项目时,验证回答既定问题所需的准确性在经济意义上的影响级别上是可以实现的。
5.从这里去哪里?
如果你是一个成功的企业家,你可能已经知道,大多数大事都是从无数的实验中开始的。在数据科学领域也是如此。以下是识别数据科学机会的一些提示。
无论你在哪个领域工作,保持头脑风暴的习惯来寻找新的、令人兴奋的想法通常是一个好主意。因此,定期花一些时间思考你的业务以及你投入的工作,记住好的产品创意可以从最痛苦的问题中产生。
顾名思义,最适合用数据科学方法解决的问题是那些可以用科学严谨性分析数据的问题。如上所述,所讨论的数据可以是任何东西:交易、图像、音频信号、自然语言文本、视频剪辑、温度波动、其他环境传感数据等等。
当遇到一个潜在有趣(有影响力)的想法时,开始考虑量化它的影响(记住 KPI 目标),你有哪些类型的数据可以分析,以及你可以验证你的推测的方法。
将自动编码器异常检测应用于欺诈检测
信用卡欺诈可以归类为异常,使用 Keras 中实现的自动编码器可以检测欺诈
https://unsplash.com/photos/TFqKR4Ynjm8
我最近读了一篇名为用自动编码器进行异常检测的文章。这篇文章是基于生成的数据,因此将这个想法应用到现实世界的欺诈检测任务并验证它听起来是个好主意。
我决定使用来自 Kaggle *的信用卡欺诈数据集:
该数据集包含欧洲持卡人在 2013 年 9 月的信用卡交易。
该数据集显示了两天内发生的交易,其中 284,807 笔交易中有 492 笔欺诈。数据集高度不平衡,正类(欺诈)占所有交易的 0.172%。
这是一个非常不平衡的数据集,是通过异常识别欺诈的良好候选对象。
让我们从数据发现开始:
在使用主成分分析将维度从 30 减少到 3 后,我们将绘制一个更小的图。该数据有 32 列,其中第一列是时间索引、29 个未知特征、1 个交易量和 1 个类别。我将忽略时间索引,因为它不是静止的。
您的第一反应可能是有两个集群,这将是一个简单的任务,但欺诈数据是黄色点!在大星团中有三个可见的黄色点。因此,让我们对正常数据进行二次抽样,同时保留欺诈数据的数量。
现在可以看到,正常交易聚集在一个磁盘中,而欺诈交易则更加分散。
我们将构建一个具有 3 层编码器和 2 层解码器的自动编码器:
https://medium . com/swlh/anomaly-detection-with-auto encoders-2bd 23 edbd 9 e
自动编码器会将我们的数据编码到一个子空间中,并在标准化数据的同时将特征解码回来。我们的期望是,autoencoder 将学习正常交易的特征,并且在应用时输入将类似于输出。对于异常,输入和输出会有很大的不同,因为它是意外的数据。
这种方法的好处是它允许我们使用无监督学习,并且我们通常有大量正常的交易数据。数据标注通常昂贵、困难,并且在某些情况下不可用。手动数据标记还包括人工交互,这导致了带有人工偏见的实现。可以看出,在模型训练中,我们只使用正常的交易特征,而不使用标签。
让我们加载数据并训练我们的自动编码器:
我的模型解决了 8.5641e-04 的验证损失。(可以低至 5.4856e-04。)
使用该模型,我们将计算正常交易的均方误差(mse ),并计算所有 mse 值的 95%的阈值。
我们发现我们的阈值(截止值)为 0.002。如果均方差高于 0.002,我们会将交易视为异常。让我们选择 100 个欺诈样本和 100 个正常样本,并根据阈值绘制:
可以看出,与正常交易相比,大多数欺诈性交易具有较高的均方误差。看起来很有希望。
我们放弃了 5%的正常交易。仍有低于阈值的欺诈交易。这可以通过使用更好的特征提取来改善,因为一些欺诈数据似乎具有与正常交易非常相似的特征。信用卡欺诈的一些有价值的特征是前一小时/天/周的交易次数,如果交易是在发行国以外的国家发起的。
未来任务:
- 通过使用超参数优化来使用更好的模型。
- 分析数据以了解特征。
- 将这些结果与 SVM 或 K-均值聚类等常用方法进行比较。
这篇文章的完整代码可以在 Github 上找到:
异常检测与自动编码器-信用卡欺诈案件博客帖子为这个回购:https://blog.berkgokden.com 代码…
github.com](https://github.com/bgokden/anomaly-detection-with-autoencoders)
在 Github 和 Linkedin 上关注我:
[## 伯克·格登-高级软件工程师-卡斯帕。人工智能| LinkedIn
请在联系之前阅读摘要:我是一名电气工程师,但我目前正在从事…
www.linkedin.com](https://www.linkedin.com/in/berkgokden/)
*信用欺诈数据集的确认
该数据集是在 Worldline 和 ulb(布鲁塞尔自由大学)机器学习小组( http://mlg.ulb.ac.be )关于大数据挖掘和欺诈检测的研究合作期间收集和分析的。在https://www.researchgate.net/project/Fraud-detection-5和 DefeatFraud 项目的页面上可以获得关于相关主题的当前和过去项目的更多细节
引用作品:
安德烈亚·达尔·波佐洛、奥利维尔·卡伦、里德·约翰逊和吉安卢卡·邦坦皮。非平衡分类的欠采样概率校准。2015 年 IEEE 计算智能和数据挖掘研讨会(CIDM)
安德烈亚·达尔·波佐洛;奥利维耶·卡兰;勒·博尔涅,扬·艾尔;沃特肖特,哔叽;邦坦皮,吉安卢卡。从从业者的角度吸取信用卡欺诈检测的经验教训,应用专家系统,41,10,4915–4928,2014 年,Pergamon
安德烈亚·达尔·波佐洛;贾科莫博拉奇;奥利维耶·卡兰;阿里皮、塞萨尔;邦坦皮,吉安卢卡。信用卡欺诈检测:现实建模和新型学习策略, IEEE 神经网络和学习系统汇刊,29,8,3784–3797,2018,IEEE
达尔·波佐洛,安德里亚用于信用卡欺诈检测的自适应机器学习ULB·MLG 博士论文(g .邦坦皮指导)
法布里齐奥·卡希洛;安德烈亚·达尔·波佐洛;扬·阿勒·勒博尔涅;奥利维耶·卡兰;马泽尔、扬尼斯;邦坦皮,吉安卢卡。 Scarff:使用 Spark 进行流式信用卡欺诈检测的可扩展框架,信息融合,41,182–194,2018,Elsevier
法布里齐奥·卡希洛;扬·阿勒·勒博尔涅;奥利维耶·卡兰;邦坦皮,吉安卢卡。现实生活中信用卡欺诈检测的流式主动学习策略:评估和可视化,国际数据科学与分析杂志,5,4,285–300,2018,施普林格国际出版公司
Bertrand Lebichot,Yann-al Le Borgne,何丽云,Frederic Oblé,Gianluca Bontempi 用于信用卡欺诈检测的深度学习领域适应技术,INNSBDDL 2019:大数据和深度学习的最新进展,第 78-88 页,2019 年
Fabrizio Carcillo,Yann-al Le Borgne,Olivier Caelen,Frederic Oblé,Gianluca Bontempi 在信用卡欺诈检测中结合非监督和监督学习信息科学,2019 年
将人工智能技术应用于在 X 射线图像中检测新冠肺炎的网络应用程序的开发
放弃
此处开发的自动检测 X 射线图像中新冠肺炎的研究严格用于教育目的。最终应用并不旨在成为用于诊断人类新冠肺炎的可靠和准确的诊断系统,因为它还没有经过专业或学术评估。
介绍
新冠肺炎是一种由病毒(新型冠状病毒冠状病毒)引起的疫情病,这种病毒已经感染了数百万人,在几个月内导致数十万人死亡。
根据世界卫生组织(世卫组织),大多数新冠肺炎患者(约 80%)可能无症状,约 20%的病例可能需要医院护理,因为他们呼吸困难。在这些病例中,大约 5%可能需要呼吸衰竭治疗的支持(通气支持),这种情况可能会使重症监护设施崩溃。快速检测病毒携带者的方法是抗击疫情的关键。
什么是冠状病毒?
冠状病毒是导致呼吸道感染的病毒家族。这种新型冠状病毒制剂是 1919 年底在中国发现病例后发现的。它会导致一种叫做冠状病毒(新冠肺炎)的疾病。
1937 年首次分离出人类冠状病毒。然而,直到 1965 年,这种病毒才被描述为冠状病毒,因为它在显微镜下看起来像一个皇冠。在下面的视频中,您可以看到新型冠状病毒病毒的原子级 3D 模型:
点击图片查看 YouTube 视频
为什么是 x 光?
最近,在应用机器学习来辅助基于计算机断层扫描(CT)的新冠肺炎诊断方面已经观察到了一些有前途的努力。尽管这些方法取得了成功,但事实仍然是,新冠肺炎是一种正在各种规模的社区中大力传播的传染病,尤其是最需要帮助的人。
x 光机更便宜、更简单、操作速度更快,因此对于在更贫困或更偏远地区工作的医疗专业人员来说,比 CT 更容易获得。
目标
抗击新冠肺炎的重大挑战之一是检测病毒在人群中的存在。因此,该项目的目标是使用扫描的胸部 X 射线图像,自动检测肺炎患者(甚至无症状或未患病的人)中导致新冠肺炎的病毒。这些图像经过预处理,用于训练卷积神经网络(CNN)模型。
CNN 类型的网络通常需要大量数据集才能运行。尽管如此,在这个项目中,应用了一种称为“迁移学习”的技术,这在数据集很小的情况下非常有用(确诊的新冠肺炎患者的图像)。
开发了两种分类模型:
- 检测新冠肺炎与诊断具有正常胸部 X 线结果的患者
- 新冠肺炎与肺炎患者的检测
正如论文新冠肺炎图像数据收集中所定义的,所有类型的肺炎(除了由新冠肺炎病毒引起的)都被认为是“肺炎”(并以肺炎标签分类)。
对于模型的训练,使用了 的工具、库、资源,TensorFlow 2.0 (带 Keras),这是一个开源的平台,用于机器学习,或者更准确的说,深度学习。最终的模型是在 Flask 中开发的 web 应用程序(web-app)的基础,用于在接近现实的情况下进行测试。
下图为我们提供了最终应用程序如何工作的基本概念:
从存储在 web-app 用户计算机上的胸部 x 光扫描图像(User_A.png)中,该应用程序决定该图像是否属于被病毒污染的人(模型预测:[阳性]或[阴性])。在这两种情况下,应用程序都会告知预测的准确性(模型准确性:X%)。为了避免两者的错误,原始文件的名称和它的图像被显示给用户。图像的新副本存储在本地,其名称被添加到预测标签加上准确度值。
这项工作分为 4 个部分:
- 环境设置、数据采集、清洁和准备
- 模型 1 培训(Covid/正常)
- 模式 2 培训(Covid/Pneumo)
- 用于在 X 射线图像中检测新冠肺炎的 Web 应用程序的开发和测试
灵感
该项目的灵感来自于 UFRRJ(巴西里约热内卢联邦农村大学)开发的 XRayCovid-19 项目的概念验证。UFRRJ XRayCovid-19 是一个正在进行的项目,该项目将人工智能用于新冠肺炎医疗系统的诊断过程。该工具的特点是易于使用,响应时间效率高,结果有效,我希望将这些特点扩展到本教程第 4 部分中开发的 Web 应用程序。下面是一个诊断结果的打印屏幕(使用了新冠肺炎数据集 1 的一幅图像):
该大学所开展工作的科学基础可以在 Chowdhury 等人的论文中看到 2020,AI 能否帮助筛查病毒性和新冠肺炎肺炎?
除了用于比较模型的结果之外,另一项激动人心的工作也启发了这个项目,这就是 Chester 应用程序 Chester:由蒙特利尔大学的研究人员开发的一个 Web 交付的本地计算胸部 X 射线疾病预测系统。Chester 是一个免费的简单原型,可以由医疗专业人员用来了解深度学习工具的现实,以帮助诊断胸部的 X 射线。该系统被设计为第二意见,其中用户可以处理图像以确认或帮助诊断。
当前版本的 Chester (2.0)使用 DenseNet-121 型卷积网络对超过 106,000 幅图像进行了训练。这款网络应用没有检测到新冠肺炎,这是研究人员未来版本应用的目标之一。下面是一个诊断结果的打印屏幕(使用了新冠肺炎数据集 1 的一幅图像)
人工智能放射学助理切斯特
在下面的链接中,你可以访问 切斯特 甚至下载 app 离线使用。
谢谢
这部作品最初是基于 Adrian Rosebrock 博士发表的优秀教程开发的,我强烈推荐深入阅读。此外,我要感谢 Nell Trevor,他在 Rosebrock 博士工作的基础上,进一步提供了如何测试最终模型的想法。在下面的链接中,Nell 通过 PythonAnyware.com 网站提供了一个在 X 射线图像中对新冠肺炎进行真实测试的网络应用:新冠肺炎预测 API 。
第 1 部分—环境设置和数据准备
数据集
*训练模型以从图像中检测任何类型的信息的第一个挑战是要使用的数据(或图像)的数量。原则上,图像的数量越多,最终的模型就越好,这与新冠肺炎探测项目的情况不同,一旦公开的图像不多(记住,这个疫情只有几个月大)。然而,像 Hall 等人 使用小数据集 *,上的深度学习从胸部 X 射线中发现新冠肺炎的研究证明,使用迁移学习技术仅用几百张图像就可以获得有希望的结果。
如介绍中所解释的,训练两个模型;因此,需要 3 组数据:
- 新冠肺炎确认了一组 x 光图像
- 常规(“正常”)患者(无疾病)的一组 X 射线图像
- 一组 x 光图像显示肺炎,但不是由新冠肺炎引起的
为此,下载了两个数据集:
数据集 1:新冠肺炎
约瑟夫·保罗·寇恩和保罗·莫里森与蓝岛·新冠肺炎影像数据集,arXiv: 2003.11597,2020
新冠肺炎或其他病毒性和细菌性肺炎(MERS、SARS 和 ARDS)阳性或疑似患者的 X 射线和计算机断层扫描图像的公开数据集。).数据从公共来源收集,以及通过医院和医生间接收集(蒙特利尔大学伦理委员会批准的项目# CERSES-20–058-D)。所有的图像和数据都可以在下面的 GitHub 库中找到。
数据集 2:肺炎和正常人的胸部 x 光图像
Kermany,Daniel 张、康;Goldbaum,Michael (2018),“用于分类的标记光学相干断层扫描(OCT)和胸部 X 射线图像”,Mendeley Data,v2。
通过深度学习过程,一组经过验证的图像(OCT 和胸部放射摄影)被分类为正常和某种类型的肺炎。图像被分成训练集和独立的患者测试集。数据可在网站上获得:https://data.mendeley.com/datasets/rscbjbr9sj/2
胸部 x 光的种类
从数据集中,可以找到三种类型的图像,PA、AP 和侧位(L)。左侧图像(L)很明显,但是 X 线 AP 和 PA 视图之间有什么区别?简单地说,在拍摄 X 射线的过程中,当 X 射线从身体的后部穿过到前部时,它被称为 PA(后部——前部)视图。而在 AP 视图中,方向是相反的。
通常,X 射线是在身体任何部位的 AP 视图中拍摄的。这里一个重要的例外恰恰是胸部 x 光。在这种情况下,最好通过 AP 查看 PA。但是如果病人病得很重,不能保持他的姿势,可以对胸部进行 AP 型 x 光检查。
由于绝大多数胸部 X 射线是 PA 型视图,这是用于训练模型的视图选择类型。
定义培训 DL 模型的环境
理想的情况是从新的 Python 环境开始。为此,使用终端,定义一个工作目录(例如:X-Ray_Covid_development ),然后在那里用 Python 创建一个环境(例如:TF_2_Py_3_7 ):
*mkdir X-Ray_Covid_development
cd X-Ray_Covid_development
conda create — name TF_2_Py_3_7 python=3.7 -y
conda activate TF_2_Py_3_7*
进入环境后,安装 TensorFlow 2.0:
*pip install — upgrade pip
pip install tensorflow*
从现在开始,安装训练模型所需的其他库。例如:
*conda install -c anaconda numpy
conda install -c anaconda pandas
conda install -c anaconda scikit-learn
conda install -c conda-forge matplotlib
conda install -c anaconda pillow
conda install -c conda-forge opencv
conda install -c conda-forge imutils*
创建必要的子目录:
*notebooks
10_dataset —
|_ covid [here goes the dataset for training model 1]
|_ normal [here goes the dataset for training model 1]
20_dataset —
|_ covid [here goes the dataset for training model 2]
|_ pneumo [here goes the dataset for training model 2]
input -
|_ 10_Covid_Imagens _
| |_ [*metadata.csv goes here*]
| |_ images [*Covid-19 images go here*]
|_ 20_Chest_Xray -
|_ test _
|_ NORMAL [*images go here*]
|_ PNEUMONIA [*images go here*]
|_ train _
|_ NORMAL [*images go here*]
|_ PNEUMONIA [*images go here*]
model
dataset_validation _
|_ covid_validation [*images go here*]
|_ non_covidcovid_validation [*images go here*]
|_ normal_validation [*images go here*]*
数据下载
下载数据集 1(新冠肺炎),并将文件 metadata.csv 保存在:/input /10_Covid_Images/下,并将图像保存在/input/10_Covid_Images/images/下。
下载数据集 2(pneumono 和 Normal),将图像保存在/input/20_Chest_Xray/(保持原来的测试和训练结构)下。
第 2 部分—模型 1—Covid/正常
数据准备
- 从我的 GitHub 下载笔记本:10 _ Xray _ Normal _ covid 19 _ Model _ 1 _ Training _ tests . ipynb保存在子目录/notebooks 中。
- 进入笔记本后,导入库并运行支持功能。
构建 Covid 标签数据集
从输入数据集(/input/10_Covid_Images/)中,创建将用于训练模型 1 的数据集,该数据集将用于要用 Covid 和 normal 标签定义的图像的分类。
*input_dataset_path = ‘../input/10_Covid_images’*
metadata.csv 文件将提供有关/images/文件中图像的信息
*csvPath = os.path.sep.join([input_dataset_path, “metadata.csv”])
df = pd.read_csv(csvPath)
df.shape*
metadat.csv 文件有 354 行和 28 列,这意味着在子目录/images/中有 354 个 X 射线图像。让我们分析它的一些列,以了解这些图像的更多细节。
通过 df.modality,有 310 个 X 射线图像和 44 个 CT(断层摄影)图像。CT 图像被丢弃,并且 df.findings 列显示 310 个 X 射线图像被细分为:
*COVID-19 235
Streptococcus 17
SARS 16
Pneumocystis 15
COVID-19, ARDS 12
E.Coli 4
ARDS 4
No Finding 2
Chlamydophila 2
Legionella 2
Klebsiella 1*
从可视化的角度来看 235 张确认的新冠肺炎图像,我们有:
*PA 142
AP 39
AP Supine 33
L 20
AP semi erect 1*
如引言中所述,只有 142 个 PA 型图像(后-前)用于模型训练,因为它们是胸片中最常见的图像(最终数据帧:xray_cv)。
xray _ cv.patiendid 列显示,这 142 幅图像属于 96 名不同的患者,这意味着在某些情况下,同一患者拍摄了不止一张 x 光照片。由于所有图像都用于训练(我们对图像的内容感兴趣),因此不考虑这些信息。
到 x 射线 cv.date,观察到有 8 张最近的图像拍摄于 2020 年 3 月。这些图像在要从模型训练中移除的列表中被分离。从而在以后用作最终模型的验证。
*imgs_march = [
‘2966893D-5DDF-4B68–9E2B-4979D5956C8E.jpeg’,
‘6C94A287-C059–46A0–8600-AFB95F4727B7.jpeg’,
‘F2DE909F-E19C-4900–92F5–8F435B031AC6.jpeg’,
‘F4341CE7–73C9–45C6–99C8–8567A5484B63.jpeg’,
‘E63574A7–4188–4C8D-8D17–9D67A18A1AFA.jpeg’,
‘31BA3780–2323–493F-8AED-62081B9C383B.jpeg’,
‘7C69C012–7479–493F-8722-ABC29C60A2DD.jpeg’,
‘B2D20576–00B7–4519-A415–72DE29C90C34.jpeg’
]*
下一步将构建指向训练数据集(xray_cv_train)的数据帧,该数据帧应引用 134 幅图像(所有输入图像均来自 Covid,除了用于稍后验证的单独图像):
*xray_cv_train = xray_cv[~xray_cv.filename.isin(imgs_march)]
xray_cv_train.reset_index(drop=True, inplace=True)*
而最终验证(x 射线 _cv_val)有 8 幅图像:
*xray_cv_val = xray_cv[xray_cv.filename.isin(imgs_march)]
xray_cv_val.reset_index(drop=True, inplace=True)*
为 COVID 训练图像和后续验证创建文件
请务必记住,在前面的项目中,仅使用从原始文件 metada.csv 中获取的信息创建了数据帧。我们知道要将哪些图像存储在最终文件中用于训练,现在我们需要将实际图像(以数字化格式)“物理”分离到正确的子目录(文件夹)中。
为此,我们将使用 load_image_folder support()函数,该函数从一个元数据文件中将其中引用的图像从一个文件复制到另一个文件:
*def load_image_folder(df_metadata,
col_img_name,
input_dataset_path,
output_dataset_path):
img_number = 0
# loop over the rows of the COVID-19 data frame
for (i, row) in df_metadata.iterrows():
imagePath = os.path.sep.join([input_dataset_path, row[col_img_name]]) if not os.path.exists(imagePath):
print('image not found')
continue filename = row[col_img_name].split(os.path.sep)[-1]
outputPath = os.path.sep.join([f"{output_dataset_path}", filename])
shutil.copy2(imagePath, outputPath)
img_number += 1
print('{} selected Images on folder {}:'.format(img_number, output_dataset_path))*
按照下面的说明,134 幅选定的图像将被复制到文件夹中…/10_dataset/covid/。
*input_dataset_path = '../input/10_Covid_images/images'
output_dataset_path = '../dataset/covid'
dataset = xray_cv_train
col_img_name = 'filename'load_image_folder(dataset, col_img_name,
input_dataset_path, output_dataset_path)*
为普通图像创建文件夹(验证和培训)
在数据集 2(正常和肺炎图像)的情况下,不提供具有元数据的文件。因此,您只需将图像从输入文件复制到末尾。为此,我们将使用 load_image_folder_direct()支持函数,该函数将大量图像(随机选择)从一个文件夹复制到另一个文件夹:
*def load_image_folder_direct(input_dataset_path,
output_dataset_path,
img_num_select):
img_number = 0
pathlist = Path(input_dataset_path).glob('**/*.*')
nof_samples = img_num_select
rc = []
for k, path in enumerate(pathlist):
if k < nof_samples:
rc.append(str(path)) # because path is not string
shutil.copy2(path, output_dataset_path)
img_number += 1
else:
i = random.randint(0, k)
if i < nof_samples:
rc[i] = str(path) print('{} selected Images on folder {}:'.format(img_number, output_dataset_path))*
对文件夹中的图像重复相同的过程…/input/20 _ Chest _ Xray/train/NORMAL,我们将为训练随机复制与之前用于 Covid 图像相同数量的图像(len (xray_cv_train))或 134 幅图像。这样,用于训练模型的数据集就平衡了。
*input_dataset_path = '../input/20_Chest_Xray/train/NORMAL'
output_dataset_path = '../dataset/normal'
img_num_select = len(xray_cv_train)load_image_folder_direct(input_dataset_path, output_dataset_path,
img_num_select)*
以同样的方式,我们分离 20 个随机图像,供以后在模型验证中使用。
*input_dataset_path = '../input/20_Chest_Xray/train/NORMAL'
output_dataset_path = '../dataset_validation/normal_validation'img_num_select = 20
load_image_folder_direct(input_dataset_path, output_dataset_path,
img_num_select)*
虽然我们不是用显示肺炎症状的图像来训练模型(新冠肺炎除外),但看看最终的模型对它们的反应是很有趣的。因此,我们还分离了其中的 20 幅图像,以供以后验证。
*input_dataset_path = '../input/20_Chest_Xray/train/PNEUMONIA'
output_dataset_path = '../dataset_validation/non_covid_pneumonia_validation'img_num_select = 20
load_image_folder_direct(input_dataset_path, output_dataset_path,
img_num_select)*
下面的图片显示了在这一步结束时应该如何配置文件夹(反正是在我的 Mac 上)。此外,标有红色的数字表示文件夹中包含的 x 射线图像的数量。
包含模型 1 培训和验证数据集的文件夹
绘制数据集以进行快速视觉验证
由于文件夹中的图像数量不多,因此可以对它们进行目视检查。为此,使用支持函数 plots_from_files():
*def plots_from_files(imspaths,
figsize=(10, 5),
rows=1,
titles=None,
maintitle=None):
"""Plot the images in a grid"""
f = plt.figure(figsize=figsize)
if maintitle is not None:
plt.suptitle(maintitle, fontsize=10)
for i in range(len(imspaths)):
sp = f.add_subplot(rows, ceildiv(len(imspaths), rows), i + 1)
sp.axis('Off')
if titles is not None:
sp.set_title(titles[i], fontsize=16)
img = plt.imread(imspaths[i])
plt.imshow(img)def ceildiv(a, b):
return -(-a // b)*
然后,定义将在训练中使用的数据集的路径(dataset_path)以及具有要查看的图像名称的列表:
*dataset_path = '../10_dataset'normal_images = list(paths.list_images(f"{dataset_path}/normal"))
covid_images = list(paths.list_images(f"{dataset_path}/covid"))*
这样,调用可视化的支持函数,图像显示如下:
*plots_from_files(covid_images, rows=10, maintitle="Covid-19 X-ray images")*
Covid 图像可视化
*plots_from_files(normal_images, rows=10, maintitle="Normal X-ray images")*
正常图像可视化
总的来说,图像看起来不错。
预训练卷积神经网络模型的选择
使用先前定义的图像来执行模型的训练,但是在已经从 TF / Keras 库中预先训练的模型上,应用被称为“迁移学习”的技术。
迁移学习是一种机器学习方法,其中为一个任务开发的模型被重新用作第二个任务中模型的起点。有关更多信息,请参见 Jason Brownlee 的优秀文章深度学习迁移学习的温和介绍
Keras 应用程序是 Keras 的深度学习库模块,它为 VGG16、ResNet50v2、ResNet101v2、Xception、MobileNet 等几种流行的架构提供模型定义和预训练的权重。以下链接显示了这些选项: Keras 应用。
要使用的预训练模型是 VGG16,由牛津大学的视觉图形组(VGG)开发,并在论文“用于大规模图像识别的非常深的卷积网络”中描述。除了在开发公开可用权重的图像分类模型时非常流行之外,这也是 Adrian 博士在他的教程中建议的模型。
理想的情况是使用几个模型(例如,ResNet50v2、ResNet101v2)进行测试(基准测试),或者甚至创建一个特定的模型(如 Zhang 等人的论文中建议的模型,【使用基于深度学习的异常检测对胸部 X 射线图像进行筛查】)。但由于这项工作的最终目标只是概念验证,我们只是在探索 VGG16 。
VGG16 是一种卷积神经网络(CNN)架构,尽管它是在 2014 年开发的,但今天仍被认为是处理图像分类的最佳架构之一。
VGG16 架构的一个特点是,它们没有大量的超参数,而是专注于一次通过一个 3×3 滤波器(内核)的卷积层,然后是一个 2×2 最大池层。在整个架构中,此过程之后是一组一致的卷积层和最大池层。最终,该架构具有 2 个 FC(全连接层),随后是针对输出的 softmax 类型激活。
VGG16 中的 16 是指架构有 16 层,权重为(w)。这个网络是广泛的,在使用所有原始的 16 层的情况下,具有几乎 1 . 4 亿个训练参数。在我们的例子中,最后两层(FC1 和 2)是本地训练的,参数总数刚好超过 1500 万,其中大约 590,000 个参数是本地训练的(而其余的是“冻结的”)。
要注意的第一点是,VNN16 架构的第一层处理 224x224x3 像素的图像,因此我们必须确保要训练的 X 射线图像也具有这些维度,因为它们是卷积网络“第一层”的一部分。因此,当使用原始权重加载模型时(weights = "imagenet "),我们还应该忽略模型的顶层(include_top = False),它由我们的层(headModel)替换。
*baseModel = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))*
接下来,我们必须定义用于训练的超参数(在下面的评论中,将测试一些可能的值以提高模型的“准确性”):
*INIT_LR = 1e-3 # [0.0001]
EPOCHS = 10 # [20]
BS = 8 # [16, 32]
NODES_DENSE0 = 64 # [128]
DROPOUT = 0.5 # [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]
MAXPOOL_SIZE = (4, 4) # [(2,2) , (3,3)]
ROTATION_DEG = 15 # [10]
SPLIT = 0.2 # [0.1]*
然后构建我们的模型,它被添加到基本模型中:
*headModel = baseModel.output
headModel = AveragePooling2D(pool_size=MAXPOOL_SIZE)(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(NODES_DENSE0, activation="relu")(headModel)
headModel = Dropout(DROPOUT)(headModel)
headModel = Dense(2, activation="softmax")(headModel)*
头模型模型放置在基础模型之上,成为实际训练的模型的一部分(确定最佳权重)。
*model = Model(inputs=baseModel.input, outputs=headModel)*
重要的是要记住,预先训练的 CNN 模型,如 VGG16,是用成千上万的图像训练的,以对普通图像进行分类(如狗、猫、汽车和人)。我们现在要做的是根据我们的需求对其进行定制(对 x 光图像进行分类)。理论上,模型的第一层简化了图像的部分,识别出其中的形状。这些初始标签非常通用(比如直线、圆、正方形),所以我们不想再训练它们了。我们只想训练网络的最后几层,以及新加入的几层。
对基础模型中的所有层执行的以下循环“冻结”它们,使得它们在第一次训练过程中不被更新。
*for layer in baseModel.layers:
layer.trainable = False*
而此时,模型已经可以接受训练了,但首先,我们必须为模型的训练准备好数据(图像)。
数据预处理
让我们首先创建一个包含存储图像的名称(和路径)的列表:
*imagePaths = list(paths.list_images(dataset_path))*
然后,对于列表中的每个图像,我们必须:
- 提取图像标签(在本例中,是 covid 或 normal)
- 将图像通道从 BGR (CV2 默认)设置为 RGB
- 将图像大小调整为 224 x 224(默认为 VGG16)
*data = []
labels = []for imagePath in imagePaths:
label = imagePath.split(os.path.sep)[-2]
image = cv2.imread(imagePath)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (224, 224)) data.append(image)
labels.append(label)*
数据和标签被转换为数组,即每个像素的强度值,范围从 0 到 255,从 0 到 1 缩放,便于训练。
*data = np.array(data) / 255.0
labels = np.array(labels)*
标签将使用一键编码技术进行数字编码。
*lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels)*
此时,训练数据集分为训练和测试(80%用于训练,20%用于测试):
*(trainX, testX, trainY, testY) = train_test_split(data,
labels,
test_size=SPLIT,
stratify=labels,
random_state=42)*
最后但同样重要的是,我们应该应用“上升”数据或“增强”技术。
增大
正如 Chowdhury 等人在他们的论文中所建议的,三种增强策略(旋转、调度和平移)可用于为新冠肺炎生成额外的训练图像,有助于防止“过拟合”。
原始胸部 x 光图像(A),逆时针旋转 45 度后的图像(B),顺时针旋转 45 度后的图像,水平和垂直平移 20%后的图像(D),以及缩放 10%后的图像(E)。
使用 TS/Keras 图像预处理库(ImageDataGenerator),可以更改几个图像参数,例如:
*trainAug = ImageDataGenerator(
rotation_range=15,
width_shift_range=0.2,
height_shift_range=0.2,
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')*
最初,仅应用 15 度的图像最大旋转来评估结果。
据观察,X 射线图像通常在旋转变化很小的情况下对齐。
*trainAug = ImageDataGenerator(rotation_range=ROTATION_DEG, fill_mode="nearest")*
此时,我们已经定义了模型和数据,并准备好进行编译和训练。
模型构建和培训
编译允许实际构建我们之前实现的模型,但是增加了一些额外的特性,比如损失率函数、优化器和指标。
对于网络训练,我们使用损失函数来计算网络预测值和训练数据实际值之间的差异。伴随着优化算法(例如 Adam)的损失值促进了对网络内的权重进行的改变的数量。这些超参数有助于网络训练的收敛,获得尽可能接近零的损失值。
我们还指定了优化器的学习率(lr)。在这种情况下,lr 被定义为 1e-3(大约。0.05).如果在训练期间,注意到“跳动”的增加,这意味着模型不能收敛,我们应该降低学习速率,以便我们可以达到全局最小值。
*opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"])*
让我们训练模型:
*H = model.fit(
trainAug.flow(trainX, trainY, batch_size=BS),
steps_per_epoch=len(trainX) // BS,
validation_data=(testX, testY),
validation_steps=len(testX) // BS,
epochs=EPOCHS)*
结果看起来已经很有趣了,在验证数据中达到了 92%的精确度!让我们绘制精确图表:
评估已训练的模型:
看看混淆矩阵:
*[[27 0]
[ 4 23]]
acc: 0.9259
sensitivity: 1.0000
specificity: 0.8519*
根据用最初选择的超参数训练的模型,我们获得:
- 100%的灵敏度,这意味着对于患有新冠肺炎(即真阳性)的患者,我们可以在 100%的时间内准确地将他们识别为“新冠肺炎阳性”。
- 85%的特异性意味着,对于没有新冠肺炎(即真正阴性)的患者,我们只能在 85%的时间内准确地将他们识别为“新冠肺炎阴性”。
结果并不令人满意,因为 15%没有 Covid 的患者会被误诊。让我们首先尝试微调模型,更改一些超参数:
*INIT_LR = 0.0001 # was 1e-3
EPOCHS = 20 # was 10
BS = 16 # was 8
NODES_DENSE0 = 128 # was 64
DROPOUT = 0.5
MAXPOOL_SIZE = (2, 2) # was (4, 4)
ROTATION_DEG = 15
SPLIT = 0.2*
因此,我们有:
*precision recall f1-score support covid 0.93 1.00 0.96 27
normal 1.00 0.93 0.96 27 accuracy 0.96 54
macro avg 0.97 0.96 0.96 54
weighted avg 0.97 0.96 0.96 54*
和混淆矩阵:
*[[27 0]
[ 2 25]]acc: 0.9630
sensitivity: 1.0000
specificity: 0.9259*
好得多的结果!现在有了 93%的特异性,这意味着在没有新冠肺炎(即真阴性)的患者中,我们可以在 93%的时间内准确地将他们识别为“新冠肺炎阴性”,而在识别真阳性时为 100%。
目前,结果看起来很有希望。让我们保存该模式,对那些在验证训练中遗漏的图像进行测试(2020 年 3 月新冠肺炎的 8 幅图像和从输入数据集中随机选择的 20 幅图像)。
*model.save("../model/covid_normal_model.h5")*
在真实图像中测试模型(验证)
首先,让我们检索模型并展示最终的架构,以检查一切是否正常:
*new_model = load_model('../model/covid_normal_model.h5')# Show the model architecture
new_model.summary()*
模型看起来不错,是 VGG16 的 16 层结构。注意可训练参数为 590,210,是最后两层(dense_2 和 dense_3)的和,加入到预训练模型中,参数为 14.7M。
让我们验证测试数据集中加载的模型:
*[INFO] evaluating network...
precision recall f1-score support covid 0.93 1.00 0.96 27
normal 1.00 0.93 0.96 27 accuracy 0.96 54
macro avg 0.97 0.96 0.96 54
weighted avg 0.97 0.96 0.96 54*
完美,我们得到了和以前一样的结果,这意味着训练好的模型被正确地保存和加载。现在让我们用之前保存的 8 幅 Covid 图像来验证模型。为此,我们使用另一个为单独图像测试开发的支持函数 test_rx_image_for_Covid19():
*def test_rx_image_for_Covid19(imagePath):
img = cv2.imread(imagePath)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224))
img = np.expand_dims(img, axis=0) img = np.array(img) / 255.0 pred = new_model.predict(img)
pred_neg = round(pred[0][1]*100)
pred_pos = round(pred[0][0]*100) print('\n X-Ray Covid-19 Detection using AI - MJRovai')
print(' [WARNING] - Only for didactic purposes')
if np.argmax(pred, axis=1)[0] == 1:
plt.title('\nPrediction: [NEGATIVE] with prob: {}% \nNo Covid-19\n'.format(
pred_neg), fontsize=12)
else:
plt.title('\nPrediction: [POSITIVE] with prob: {}% \nPneumonia by Covid-19 Detected\n'.format(
pred_pos), fontsize=12) img_out = plt.imread(imagePath)
plt.imshow(img_out)
plt.savefig('../Image_Prediction/Image_Prediction.png')
return pred_pos*
在笔记本电脑上,该功能将显示以下结果:
通过更改剩余 7 个图像的 imagePath 值,我们获得了以下结果:
所有图像都呈阳性,证实了 100%的灵敏度。
现在让我们测试标记为正常的 20 个单独的验证图像。笔记本上的第一个应该是这样的:
逐个测试,有可能证实预测,但由于我们有更多的图像,让我们使用另一个函数来测试一组图像,一次完成:test _ rx _ image _ for _ covid 19 _ batch(img _ lst)。
批量测试图像
让我们创建包含在验证文件夹中的图像列表:
*validation_path = '../dataset_validation'normal_val_images = list(paths.list_images(
f"{validation_path}/normal_validation"))
non_covid_pneumonia_validation_images = list(paths.list_images(
f"{validation_path}/non_covid_pneumonia_validation"))
covid_val_images = list(paths.list_images(
f"{validation_path}/covid_validation"))*
test _ rx _ image _ for _ covid 19 _ batch(img _ lst)函数如下所示:
*def test_rx_image_for_Covid19_batch(img_lst):
neg_cnt = 0
pos_cnt = 0
predictions_score = []
for img in img_lst:
pred, neg_cnt, pos_cnt = test_rx_image_for_Covid19_2(img, neg_cnt, pos_cnt)
predictions_score.append(pred)
print ('{} positive detected in a total of {} images'.format(pos_cnt, (pos_cnt+neg_cnt)))
return predictions_score, neg_cnt, pos_cnt*
将该函数应用于我们之前分离的 20 幅图像:
*img_lst = normal_val_images
normal_predictions_score, normal_neg_cnt, normal_pos_cnt = test_rx_image_for_Covid19_batch(img_lst)
normal_predictions_score*
我们观察到,所有 20 人都被诊断为阴性,得分如下(记住,模型将返回接近“1”的“阳性”):
*0.25851375,
0.025379542,
0.005824779,
0.0047603976,
0.042225637,
0.025087152,
0.035508618,
0.009078974,
0.014746706,
0.06489486,
0.003134642,
0.004970203,
0.15801577,
0.006775451,
0.0032735346,
0.007105667,
0.001369465,
0.005155371,
0.029973848,
0.014993184*
仅在 2 个案例中,图像的 a 值(1-精度)低于 90% (0.26 和 0.16)。
由于我们有一个函数来批量应用模型,请记住输入数据集/input /20_Chest_Xray/有两个组/train 和/test。只有包含在/train 中的图像组的一部分用于训练,并且所有/test 图像从未被模型看到:
*input -
|_ 10_Covid_Imagens _
| |_ *metadata.csv*
| |_ images [used train model 1]
|_ 20_Chest_Xray -
|_ test _
|_ NORMAL
|_ PNEUMONIA
|_ train _
|_ NORMAL [used train model 1]
|_ PNEUMONIA*
然后,我们可以利用并测试该文件夹中的所有新图像。首先,我们创建了图像列表:
*validation_path = '../input/20_Chest_Xray/test'normal_test_val_images = list(paths.list_images(f"{validation_path}/NORMAL"))
print("Normal Xray Images: ", len(normal_test_val_images))pneumo_test_val_images = list(paths.list_images(f"{validation_path}/PNEUMONIA"))
print("Pneumo Xray Images: ", len(pneumo_test_val_images))*
我们观察了 234 张被诊断为正常的“未发表的”图像(还有 390 多张被诊断为非新冠肺炎引起的肺炎)。应用批量测试的功能,我们观察到在总共 234 个图像中有 24 个图像呈现假阳性(大约 10%)。让我们看看模型输出值是如何分布的,记住函数返回的值是这样计算的:
*pred = new_model.predict(image)
pred_pos = round(pred[0][0] * 100)*
我们观察到预测的精确谷值的平均值为 0.15,并且非常集中在接近于零的值中(中值仅为 0.043)。有趣的是,大多数假阳性接近 0.5,少数异常值在 0.6 以上。
除了改进模型之外,研究产生假阳性的图像也是值得的,因为这可能是获取数据的方式的技术特征。
肺炎的图像检测
因为输入数据集也有肺炎患者的 X 射线图像,但不是由 Covid 引起的,所以让我们应用模型 1 (Covid / Normal)来看看结果是什么:
结果非常糟糕,因为在 390 张图像中,有 185 张是假阳性。而观察结果的分布,观察到有一个接近 80%的峰值,就是错得很离谱!
回想一下,这个结果在技术上并不令人惊讶,因为该模型没有用肺炎患者的图像进行训练。
无论如何,这是一个大问题,因为我想象一个专家可以用肉眼区分一个病人是否患有肺炎。尽管如此,要区分这场肺炎是由新冠肺炎病毒(新型冠状病毒)、任何其他病毒,甚至是细菌引起的,可能会更加困难。
该模型应该更有用,能够区分由新冠肺炎病毒引起的肺炎患者和其他类型的病毒或细菌。为此,训练了另一个模型,现在有了感染新冠肺炎病毒的病人和感染肺炎但不是由新冠肺炎病毒引起的病人的图像。
第 3 部分—模型 2 — Covid/Pneumo
数据准备
- 从我的 GitHub 下载笔记本:20 _ Xray _ pno _ covid 19 _ Model _ 2 _ Training _ tests . ipynb保存在子目录/notebooks 中。
- 导入使用的库并运行支持函数。
模型 2 中使用的 Covid 图像数据集与模型 1 中使用的相同,只是现在它存储在不同的文件夹中。
*dataset_path = '../20_dataset'*
肺炎图像将从文件夹/input/20 _ Chest _ x ray/train/Pneumonia/下载,并存储在/20 _ dataset/pneumono/中。要使用的功能与之前相同:
*input_dataset_path = '../input/20_Chest_Xray/train/PNEUMONIA'
output_dataset_path = '../20_dataset/pneumo'img_num_select = len(xray_cv_train) # Same number of samples as Covid data*
这样,我们调用可视化的支持函数,检查获得的结果:
*pneumo_images = list(paths.list_images(f"{dataset_path}/pneumo"))
covid_images = list(paths.list_images(f"{dataset_path}/covid"))plots_from_files(covid_images, rows=10, maintitle="Covid-19 X-ray images")*
Covid 图像可视化
*plots_from_files(pneumo_images, rows=10, maintitle="Pneumony X-ray images"*
总的来说,图像看起来不错。
预训练 CNN 模型及其超参数的选择
要使用的预训练模型是 VGG16,与用于模型 1 训练的模型相同
*baseModel = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))*
接下来,我们必须定义用于训练的超参数。我们从模型 1 的最终训练调整后使用的相同参数开始:
*INIT_LR = 0.0001
EPOCHS = 20
BS = 16
NODES_DENSE0 = 128
DROPOUT = 0.5
MAXPOOL_SIZE = (2, 2)
ROTATION_DEG = 15
SPLIT = 0.2*
然后,构建我们的模型,该模型将被添加到基本模型中:
*headModel = baseModel.output
headModel = AveragePooling2D(pool_size=MAXPOOL_SIZE)(headModel)
headModel = Flatten(name="flatten")(headModel)
headModel = Dense(NODES_DENSE0, activation="relu")(headModel)
headModel = Dropout(DROPOUT)(headModel)
headModel = Dense(2, activation="softmax")(headModel)*
headModel 模型被放置在基本模型之上,成为用于训练的真实模型。
*model = Model(inputs=baseModel.input, outputs=headModel)*
对基础模型中的所有层执行的以下循环将“冻结”它们,使得它们在第一次训练过程中不被更新。
*for layer in baseModel.layers:
layer.trainable = False*
此时,模型已经可以进行训练了,但是我们首先要准备好模型的数据(图像)。
数据预处理
让我们首先创建一个包含存储图像的名称(和路径)的列表,并执行与模型 1 相同的预处理:
*imagePaths = list(paths.list_images(dataset_path))data = []
labels = []for imagePath in imagePaths:
label = imagePath.split(os.path.sep)[-2]
image = cv2.imread(imagePath)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = cv2.resize(image, (224, 224)) data.append(image)
labels.append(label)data = np.array(data) / 255.0
labels = np.array(labels)*
标签使用一键编码技术进行数字编码。
*lb = LabelBinarizer()
labels = lb.fit_transform(labels)
labels = to_categorical(labels)*
此时,我们将把训练数据集分为训练数据集和测试数据集(80%用于训练,20%用于测试):
*(trainX, testX, trainY, testY) = train_test_split(data,
labels,
test_size=SPLIT,
stratify=labels,
random_state=42)*
最后但同样重要的是,我们将应用数据扩充技术。
*trainAug = ImageDataGenerator(rotation_range=ROTATION_DEG, fill_mode="nearest")*
此时,我们已经定义了模型和数据,并准备好进行编译和训练。
模型 2 的编译和训练
编译:
*opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"])*
培训:
*H = model.fit(
trainAug.flow(trainX, trainY, batch_size=BS),
steps_per_epoch=len(trainX) // BS,
validation_data=(testX, testY),
validation_steps=len(testX) // BS,
epochs=EPOCHS)*
通过 20 个时期和初始参数,结果看起来非常有趣,在验证数据中达到 100%的精度!让我们绘制精度图表,评估训练好的模型,并查看混淆矩阵:
*precision recall f1-score support covid 0.96 1.00 0.98 27
pneumo 1.00 0.96 0.98 27 accuracy 0.98 54
macro avg 0.98 0.98 0.98 54
weighted avg 0.98 0.98 0.98 54*
混淆矩阵:
*[[27 0]
[ 1 26]]
acc: 0.9815
sensitivity: 1.0000
specificity: 0.9630*
利用训练的模型(利用最初选择的超参数),我们获得:
- 100%的灵敏度,这意味着对于患有新冠肺炎(即,真阳性)的患者,我们可以在 100%的时间内准确地将他们识别为“新冠肺炎阳性”。
- 96%的特异性,这意味着对于没有新冠肺炎(即,真阴性)的患者,我们可以在 96%的时间内准确地将他们识别为“新冠肺炎阴性”。
结果完全令人满意,因为只有 4%没有 Covid 的患者会被误诊。但在这种情况下,肺炎患者和新冠肺炎患者之间的正确分类是最有益的;我们至少应该对超参数进行一些调整,重新进行训练。
首先,我试图降低初始 lr 一点,这是一场灾难。我回到了原来的值。
我还减少了数据的分割,增加了一点 Covid 图像,并将最大旋转角度更改为 10 度,这是与原始数据集相关的论文中建议的:
*INIT_LR = 0.0001
EPOCHS = 20
BS = 16
NODES_DENSE0 = 128
DROPOUT = 0.5
MAXPOOL_SIZE = (2, 2)
ROTATION_DEG = 10
SPLIT = 0.1*
因此,我们有:
*precision recall f1-score support covid 1.00 1.00 1.00 13
pneumo 1.00 1.00 1.00 14 accuracy 1.00 27
macro avg 1.00 1.00 1.00 27
weighted avg 1.00 1.00 1.00 27*
和混淆矩阵:
*[[13 0]
[ 0 14]]acc: 1.0000
sensitivity: 1.0000
specificity: 1.0000*
结果看起来比他们以前更好,但我们使用的测试数据很少!让我们保存这个模型,像以前一样用大量的图片进行测试。
*model.save("../model/covid_pneumo_model.h5")*
我们观察到有 390 张图片被标记为非新冠肺炎病毒引起的肺炎。应用批量测试功能,我们观察到在总共 390 个图像中只有 3 个图像呈现假阳性(大约 0.8%)。此外,预测精度值的平均值为 0.04,并且非常集中在接近于零的值中(中值仅为 0.02)。
总体结果甚至比以前的模型观察到的更好。有趣的是,几乎所有结果都在前 3 个四分位数内,只有极少数异常值的误差超过 20%。
在这种情况下,也值得研究产生假阳性(只有 3 个)的图像,因为它们也可能是捕获数据的方式的技术特征。
使用被认为正常(健康)的患者图像进行测试
由于输入数据集也有正常患者(未训练)的 X 射线图像,让我们应用模型 2 (Covid/Pneumo)来看看结果是什么
在这种情况下,结果并不像在模型 1 测试中看到的那样糟糕,因为在 234 幅图像中,有 45 幅呈现假阳性(19%)。
理想的情况是对每种情况使用正确的模型,但是如果只使用一种,模型 2 是正确的选择。
注意:在最后一次测试备选方案的尝试中,做了一次基准测试,我试图改变增强参数,正如 Chowdhury 等人所建议的那样,但令我惊讶的是,结果并没有更好(结果在笔记本的末尾)。
第 4 部分—用于 X 射线图像中新冠肺炎检测的 Web 应用程序
测试 Python 独立脚本
对于 web-app 的开发,我们使用 Flask,这是一个用 Python 编写的 web 微框架。它被归类为微结构,因为它不需要特定的工具或库来运行。
此外,我们只需要几个库和与单独测试图像相关的函数。因此,让我们首先在一个“干净”的笔记本上工作,在那里使用已经训练和保存的模型 2 进行测试。
- 从我的 GitHub 加载,笔记本:30 _ AI _ Xray _ covid 19 _ pno _ Detection _ application . ipynb
- 现在只导入测试在前一个笔记本中创建的模型所需的库。
*import numpy as np
import cv2
from tensorflow.keras.models import load_model*
- 然后执行加载和测试映像的支持功能:
*def test_rx_image_for_Covid19_2(model, imagePath):
img = cv2.imread(imagePath)
img_out = img
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224))
img = np.expand_dims(img, axis=0) img = np.array(img) / 255.0 pred = model.predict(img)
pred_neg = round(pred[0][1]*100)
pred_pos = round(pred[0][0]*100)
if np.argmax(pred, axis=1)[0] == 1:
prediction = 'NEGATIVE'
prob = pred_neg
else:
prediction = 'POSITIVE'
prob = pred_pos cv2.imwrite('../Image_Prediction/Image_Prediction.png', img_out)
return prediction, prob*
- 下载训练好的模型
*covid_pneumo_model = load_model('../model/covid_pneumo_model.h5')*
- 然后,从验证子目录上传一些图像,并确认一切正常:
*imagePath = '../dataset_validation/covid_validation/6C94A287-C059-46A0-8600-AFB95F4727B7.jpeg'
test_rx_image_for_Covid19_2(covid_pneumo_model, imagePath)*
结果应该是:(‘阳性’,96.0)
*imagePath = ‘../dataset_validation/normal_validation/IM-0177–0001.jpeg’
test_rx_image_for_Covid19_2(covid_pneumo_model, imagePath)*
结果应该是:(‘负’,99.0)
*imagePath = '../dataset_validation/non_covid_pneumonia_validation/person63_bacteria_306.jpeg'
test_rx_image_for_Covid19_2(covid_pneumo_model, imagePath)*
结果应该是:(‘负’,98.0)
到目前为止,所有的开发都是在 Jupyter 笔记本上完成的,我们应该做一个最终测试,让代码作为 python 脚本运行在最初创建的开发目录中,例如,使用名称:covidXrayApp_test.py。
*# Import Libraries and Setupimport numpy as np
import cv2
from tensorflow.keras.models import load_model# Turn-off Info and warnings
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'# Support Functionsdef test_rx_image_for_Covid19_2(model, imagePath):
img = cv2.imread(imagePath)
img_out = img
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (224, 224))
img = np.expand_dims(img, axis=0) img = np.array(img) / 255.0 pred = model.predict(img)
pred_neg = round(pred[0][1]*100)
pred_pos = round(pred[0][0]*100)
if np.argmax(pred, axis=1)[0] == 1:
prediction = 'NEGATIVE'
prob = pred_neg
else:
prediction = 'POSITIVE'
prob = pred_pos cv2.imwrite('./Image_Prediction/Image_Prediction.png', img_out)
return prediction, prob# load model
covid_pneumo_model = load_model('./model/covid_pneumo_model.h5')# ---------------------------------------------------------------
# Execute testimagePath = './dataset_validation/covid_validation/6C94A287-C059-46A0-8600-AFB95F4727B7.jpeg'prediction, prob = test_rx_image_for_Covid19_2(covid_pneumo_model, imagePath)print (prediction, prob)*
让我们直接在终端上测试这个脚本:
完美一切工作完美和“独立”,在笔记本之外。
在 Flask 中创建运行应用程序的环境
第一步是从新的 Python 环境开始。为此,使用终端定义一个工作目录(例如 covid19XrayWebApp ),然后在那里用 Python 创建一个环境(例如:
*mkdir covid19XrayWebApp
cd covid19XrayWebApp
conda create --name covid19xraywebapp python=3.7.6 -y
conda activate covid19xraywebapp*
进入环境后,安装 Flask 和运行应用程序所需的所有库:
*conda install -c anaconda flask
conda install -c anaconda requests
conda install -c anaconda numpy
conda install -c conda-forge matplotlib
conda install -c anaconda pillow
conda install -c conda-forge opencv
pip install --upgrade pip
pip install tensorflow
pip install gunicorn*
创建必要的子目录:
*[here the app.py]
model [here the trained and saved model]
templates [here the .html file]
static _ [here the .css file and static images]
|_ xray_analysis [here the output image after analysis]
|_ xray_img [here the input x-ray image]*
从我的 GitHub 中复制文件,并存储在新创建的目录中,如下所示:
- 服务器上负责“后端”执行的 python 应用程序称为 app.py,必须位于主目录的根目录下
- 在/template 中,应该存储 index.html 文件,它将是应用程序的“面孔”,或者说是“前端”
- 在/static 中将是 style.css 文件,负责格式化前端(template.html)以及静态图片如 logo,icon 等。
- 在/static 下还有子目录,这些子目录将接收要分析的图像以及分析结果(实际上,相同的图像以新名称保存,其中包含:其原始名称加上诊断和准确率)。
一旦所有文件都安装到了正确的位置,工作目录看起来就像这样:
在本地网络上启动 Web 应用程序
一旦你将文件安装到你的文件夹中,运行 app.py,它是我们 web 应用程序的“引擎”,负责接收存储在用户计算机某处的图像(无论在哪里)。
*python app.py*
在终端,我们可以观察到:
在您的浏览器上,输入方向:
该应用将在您的本地网络中运行:
用真实图像测试网络应用
我们可以选择开始显示 Covid 的 X 射线图像之一,它已经在开发过程中用于验证。
- 按下应用程序中的[浏览]按钮,打开您电脑的文件管理器
- 选择图像,然后选择[打开](在我的 Mac 的 Finder 窗口中)
- 文件名显示为在应用程序中选择的文件名。
- 在 app 中按【提交查询】。
- 图像显示在应用程序的底部,同时显示图像诊断及其准确度值。
- 图像存储在文件夹:/static/Xray _ Analysys 中,结构如下:[Result]_ Prob [XX] Name _[FILENAME]。png
以下是一系列步骤:
对有肺炎但没有新冠肺炎的图像之一重复测试:
后续步骤
正如导言中所讨论的,该项目是一个概念验证,以证明在 X 射线图像中检测导致新冠肺炎的病毒的可行性。对于要在实际案例中使用的项目,还必须完成几个步骤。以下是一些建议:
- 与卫生领域的专业人员一起验证整个项目
- 开发一个基准来寻找最佳的预训练模型
- 使用从患者处获得的图像来训练该模型,最好是来自将使用该应用的相同区域。
- 使用新冠肺炎获得更广泛的患者图像
- 改变模型的模型超参数
- 测试用 3 个类别(正常、Covid 和肺炎)训练模型的可行性
- 对应用程序要测试的图像应用与训练图像相同的捕获和数字化程序
- 更改应用程序,允许选择更适合使用的型号(型号 1 或 2)
- 在 Heroku.com 或 pythonanywhere.com 等平台上将网络应用投入生产
结论
一如既往,我希望这篇文章能够帮助其他人在数据科学的美好世界中找到自己的路!我比以往任何时候都更希望这篇文章能够激励深度学习和健康领域的专业人士共同努力,投入生产模型,帮助抗击疫情。
本文使用的所有代码都可以在我的 GitHub 上下载: covid19Xray 。
来自世界南方的问候!
我的下一篇文章再见!
谢谢你
马塞洛