通过手套快速学习编码,无需参考
你需要知道的 10 件事,用 Python 和 R

作者图片
两个书呆子的故事
想象两个数据科学家。你给他们每个人一个数据集,给他们一个问题。第一个人听你说,做笔记,并说他们会“继续做这件事,回头再和你联系”。
第二位数据科学家拿出他们的笔记本电脑,坐在你旁边(或分享他们的屏幕),说“让我们现在就解决这个问题”。只要你们两个能尽快地交流想法,他们就能实时编码并绘制出结果。20 分钟内,你就有了答案、图表和对数据的新理解。
你想和哪个书呆子一起工作?你想雇佣哪个书呆子?你想让哪个书呆子成为?
为什么学习如何在没有参考的情况下快速编码很重要。
你为什么要学习如何快速编码?因为速度往往胜过质量。现在有一个像样的答案通常比下周有一个很好的答案要好。
速度也需要一定水平的能力。在谷歌上搜索“如何在 Pandas 中选择一列”的每一行代码后停下来,是打断你思路的一个绝妙方法。如果您可以立即将您的想法转化为代码,您就可以快速迭代并开发解决问题的更好方法。
当然,你也可以很容易地写出快速、糟糕的代码,产生不准确的结果。但是让我们现实一点,如果你要失败,最好也快点!更快的失败意味着你有更多的时间去成功!
事实上,失败正是导致人们害怕在他人面前编码的原因。我们都讨厌我们的同行看到我们的缺点,我们手指上的代码看起来像是你的想法的小代表。如果代码失败了,感觉就像是我们智慧的失败。
我来这里是为了宣传让你尽快从自我中解脱出来,在其他人面前编码的想法。你的代码不是你。就像你现在正在阅读的文字一样,你的代码只是屏幕上的文字。我有一个大秘密要和你分享!数据科学的编码很容易。
数据科学的编码很简单
嘘…
无论你做什么,不要让人力资源部的人知道我们的秘密!目前数据科学的薪水很高,我不想破坏大家的兴致。
但是,数据科学的编码真的没有那么难。
是不是神经网络或者支持向量机模型某某只是做复杂了?当然可以。但是有时实际的模型只有 3-10 行代码。让我们不要忘记模型上面的 700 行代码!这是以原始格式获取数据,然后进行清理、编码、组合、聚合等操作的代码。
这是数据科学中 99%的工作。每花一分钟建立一个模型并感觉自己很聪明,你就有两个小时的时间来获取丑陋的数据并将其转化为稍微不那么丑陋的数据。
那么我们需要知道的 10 件事是什么呢?
这 10 件事会帮你度过大多数情况。即使是看起来非常复杂的数据科学脚本,通常也可以通过以下项目的组合来实现:
- 基本选择(选择和重命名列,不同)
- 过滤数据
- 用运算符(and、or 等)过滤。)或通过其他方式(顶、头等。)
- 通过串联(如名字+姓氏)和聚合(如价格*数量)来组合列
- 连接和追加数据
- 汇总数据(总和、平均值、中间值、标准偏差等。)
- 分组和聚合数据
- 在不同的分组级别聚合(例如,解组或窗口类型功能)
- if 语句在数据中设置标志或布尔值
- 制作一些简单的图表(条形图、折线图、散点图)
没有谷歌,你如何快速学会做这 10 件事?
解决方案:手套!
护手是我多年来一直在做的小练习,现在我将与你分享它们。下面是它们的工作原理。
您从您选择的编程语言/ IDE 开始,有一个类似如下的空白模板:
这个模板涵盖了我之前列出的 10 件事情中的大部分。你需要做的就是:
- 引入数据集,我们将使用来自 R 的免费和流行的 MPG 数据集(对于 Python 和 R 模板)
- 就在模板中每个注释行的下面,凭记忆试一试。试着一路穿过铁手套。
- 如果你能想出一个,看一看你的语言的填充模板。然后输入它。
就是这样。
周一到周五,当你第一次开始工作的时候,你就这样做。你在查看邮件或参加会议之前做这件事。
第一次做这些的时候,你可能需要查看每个部分的填写模板,这就可以了!但我向你保证,两周内你会记住每一部分。如果你能凭记忆做这 10 件事,那么你可以把它们结合起来做任何事。
代码
这里是用 python 和 r 填写的模板。对于 Python,您需要在这里下载 mpg 数据集。对于 R,数据集内置在 Tidyverse 包中,所以不需要下载它。
Python 代码
R 代码
包装它
不要让我的挑战模板阻碍你!一旦你确定了这 10 件事,你就可以继续扩大你每天要做的事情的清单。
即使你不是为数据科学编程,而是做传统编程,你也可以设计类似的手套。我可以很容易地想象出任何一个程序员在学习一门新语言时可能想要添加的东西。一些例子:
- 运算符-与、或、等于、赋值、迭代
- 循环- for,while,do while
- 开关
- 功能
- 类——创建一个类,覆盖参数,获取/设置实例中的值,等等。
- 基本递归(调用自身的函数)
祝你在挑战中幸存!顺便说一句,你知道你可以为一篇文章点击 50 次鼓掌按钮吗?说到你手指的护手!!
从头开始学习实现编辑距离

我最近在 Coursera 上完成了 deeplearning.ai 的使用概率模型进行自然语言处理的课程。本课程涵盖了广泛的主题,包括拼写纠正、词性标注、语言建模和单词到向量。所有主题都进行了深入探讨,并附有详细的实践练习。
但是,我们都知道,如果我们不练习所学的概念,我们肯定会很快忘记它们。因此,我想到写这篇博客,内容是关于课程中涉及的一个非常重要的指标——“编辑距离或 Levenshtein 距离”。
本文将涵盖以下主题:
- 编辑距离简介
- 使用递归实现它
- 理解动态编程并实现它
- 利用学到的技能解决问题
什么是编辑距离,如何实现?
编辑距离或 Levenstein 距离(最常见)是计算一对序列之间相似性的度量。两个序列之间的距离以将一个序列转换为另一个序列所需的编辑次数(插入、删除或替换)来衡量。
在本节中,我们将学习如何实现编辑距离。
距离度量
Levenstein 距离的计算公式如下:

图片来自 Wikipedia.com
其中 tail 表示序列中除第一个字符之外的其余部分,在 Python 行话中是a[1:]。
对这些条件的解释如下:
- 如果 b 是一个空序列(
|b|=0),那么 cost 就是 a 的长度(|a|)。 - 如果 a 是一个空序列(
|a|=0,那么 cost 就是 b 的长度(|b|)。 - 如果 a 和 b 的第一个字符相同(
a[0] = b[0]),那么代价就是子序列尾(a) (a[1:])和尾(b) (b[1:])的代价。 - 最后,成本是插入、删除或替换操作的最小值,定义如下:
lev(tail(a), b)表示从中删除一个字符lev(a, tail(b)表示一个字符被插入到lev(tail(a), tail(b))表示替代
注意:在上面的公式中,插入、删除或替换的成本保持不变,即 **1** 。但是,替换成本通常被认为是 **2** ,我们将在实现中使用。
使用递归编辑距离
我们可以直接将上述公式转换成递归函数来计算两个序列之间的编辑距离,但这种解决方案的时间复杂度是𝑂(3(𝑚+𝑛)).
因此,一旦我们弄清楚了编辑距离是如何工作的,我们将使用时间复杂度为𝑂(𝑚∗𝑛).的动态规划来编写一个更优化的解决方案
下面是递归函数。我还将添加一些叙述,即打印出它正在执行的操作(插入、删除或替换)的功能。
*# Below are the costs of different operations.*
ins_cost = 1
del_cost = 1
sub_cost = 2# Below function will take the two sequence and will return the distance between them.def edit_distance_recurse(seq1, seq2, operations=[]):
*"""Returns the Edit Distance between the provided two sequences."""*
if len(seq2) == 0:
operations = operations + ([f"Delete `**{**seq1**}**` from sequence1."] if len(seq1) else [])
return len(seq1), operations
if len(seq1) == 0:
operations = operations + ([f"Insert `**{**seq2**}**` into sequence1."] if len(seq2) else [])
return len(seq2), operations
if seq1[0] == seq2[0]:
operations = operations + [f"Make no change for character `**{**seq1[0]**}**`."]
return edit_distance_recurse(seq1[1: ], seq2[1: ], operations)
*# calculate cost if insertion was made*
ins_operations = operations + [f"Insert `**{**seq2[0]**}**` in sequence1."]
insertion, ins_operations = edit_distance_recurse(seq1, seq2[1: ], ins_operations)
*# calculate cost if deletion was done*
del_operations = operations + [f"Delete `**{**seq1[0]**}**` from sequence1."]
deletion, del_operations = edit_distance_recurse(seq1[1: ], seq2, del_operations)
*# calculate cost if substitution was done*
sub_operations = operations + [f"Replace `**{**seq1[0]**}**` in sequence1 with `**{**seq2[0]**}**`."]
substitution, sub_operations = edit_distance_recurse(seq1[1: ], seq2[1: ], sub_operations)
*# calculate minimum cost*
min_cost = min(insertion + ins_cost, deletion + del_cost, substitution + sub_cost)
if min_cost == (substitution + sub_cost):
return min_cost, sub_operations
elif min_cost == deletion + del_cost:
return min_cost, del_operations
else:
return min_cost, ins_operations
让我们举几个例子来测试这个函数
seq1 = "numpy"
seq2 = "numexpr"score, operations = edit_distance_recurse(seq1, seq2)
print(f"Edit Distance between `**{**seq1**}**` & `**{**seq2**}**` is: **{**score**}**")
print("**\n**Operations performed are:**\n**")
for operation **in** operations:
print(operation)
输出:
Edit Distance between `numpy` & `numexpr` is: 4Operations performed are:Make no change for character `n`.
Make no change for character `u`.
Make no change for character `m`.
Insert `e` in sequence1.
Insert `x` in sequence1.
Make no change for character `p`.
Replace `y` in sequence1 with `r`.
编辑距离为 **4** **的原因是:**字符n,u,m保持不变(因此 0 成本),然后插入e & x导致到目前为止2的总成本。然后,p没有变化,所以成本没有变化,最后,y is replaced with r,导致额外成本为 2。
因此,总成本为4。
使用动态编程编辑距离
对于有 重叠子问题 的问题,可以应用动态规划。就像在我们的例子中,为了得到numpy & numexpr之间的编辑距离,我们首先对子序列nump & nume进行相同的计算,然后对numpy & numex进行计算,以此类推…
一旦我们解决了一个特定的子问题,我们就存储它的结果,以后用它来解决整个问题。
想了解更多关于动态编程的知识可以参考我的短教程— 动态编程入门 。
现在让我们了解如何将问题分解成子问题,存储结果,然后解决整体问题。
在下图中——跨行的是我们想要以最小的转换成本转换成sequence2(跨列)的sequence1。
两个序列前的字符#表示空字符串或字符串的开头。

现在,我们将用不同子序列的成本填充这个矩阵,以获得整体解决方案。但是,首先,让我们看看基本情况:
- 当
sequence1为空时,那么获得sequence2的成本就是添加sequence2中出现的角色的成本。矩阵中的第一行表示sequence1为空。

- 如果两个序列都是空的,那么代价就是
0。

- 如果我们将字符
n添加到sequence1中,我们将得到1的成本。

- 同样,我们将填充我们的第一行,其中每一列中的值是
1 + previous column value,即添加多 1 个字符的成本。

- **注意:**最后一列的值 7 表示如果
sequence1为空,那么将sequence1转换为sequence2的成本为7。同样,将空序列转换为子序列'num'的成本是3。 - 与此相反,我们有一种情况,当
sequence2为空,但sequence1不为空。然后,跨行的值表示删除字符以获得空序列的成本。

- **注:**此处成本
5代表删除sequence1所有角色获得一个空sequence2的总成本。
现在填充了基础案例成本的矩阵如下:

求解子问题并填充矩阵。
- (’ n ‘,’ n ')下的值是
***0***,因为这两个字符是相同的,因此没有转换成本。

- 下面的矩阵显示了将
#n转换为#nu的成本是1,由于子串#n&#n的成本是0,我们只将u加到sub-sequence1的成本相加。

- 与上面类似,将
#nu转换为#n的成本是1,由于子字符串#n&#n的成本是0,我们只增加从sub-sequence1中删除u的成本。

- 经过几次迭代后,矩阵将如下所示。**注:**成本用户子序列
#num&#num是0,因为它们是相同的。

- 到目前为止,我们只看了插入和删除操作,但是现在我们也将考虑一个替换的例子。为了求解子序列
**#nump**&**#nume**,我们将首先计算子序列**#num**&**#num**(也就是我们上面提到的**0**),因此总成本为 0+2=20+2=2 ,这是将**p**代入**e**的成本

- 完整的矩阵如下,总成本列在最后一行的最后一列,即
**4**。

此外,通过从最后一行的最后一列到第一行的第一列追踪最小成本,我们可以得到为达到该最小成本而执行的操作。

下面的函数获取为获得最小成本而执行的操作。
def min_cost_path(cost, operations):
*# operation at the last cell*
path = [operations[cost.shape[0]-1][cost.shape[1]-1]]
*# cost at the last cell*
min_cost = cost[cost.shape[0]-1][cost.shape[1]-1]
row = cost.shape[0]-1
col = cost.shape[1]-1
while row >0 **and** col > 0:
if cost[row-1][col-1] <= cost[row-1][col] **and** cost[row-1][col-1] <= cost[row][col-1]:
path.append(operations[row-1][col-1])
row -= 1
col -= 1 elif cost[row-1][col] <= cost[row-1][col-1] **and** cost[row-1][col] <= cost[row][col-1]:
path.append(operations[row-1][col])
row -= 1 else:
path.append(operations[row][col-1])
col -= 1
return "".join(path[::-1][1:])
下面的函数使用动态编程计算编辑距离
def edit_distance_dp(seq1, seq2):
*# create an empty 2D matrix to store cost*
cost = np.zeros((len(seq1)+1, len(seq2)+1))
*# fill the first row*
cost[0] = [i for i **in** range(len(seq2)+1)]
*# fill the first column*
cost[:, 0] = [i for i **in** range(len(seq1)+1)]
*# to store the operations made*
operations = np.asarray([['-' for j **in** range(len(seq2)+1)] \
for i **in** range(len(seq1)+1)])
*# fill the first row by insertion*
operations[0] = ['I' for i **in** range(len(seq2)+1)]
*# fill the first column by insertion operation (D)*
operations[:, 0] = ['D' for i **in** range(len(seq1)+1)]
operations[0, 0] = '-'
*# now, iterate over earch row and column*
for row **in** range(1, len(seq1)+1):
for col **in** range(1, len(seq2)+1):
*# if both the characters are same then the cost will be same as*
*# the cost of the previous sub-sequence*
if seq1[row-1] == seq2[col-1]:
cost[row][col] = cost[row-1][col-1]
else:
insertion_cost = cost[row][col-1] + ins_cost
deletion_cost = cost[row-1][col] + del_cost
substitution_cost = cost[row-1][col-1] + sub_cost
*# calculate the minimum cost*
cost[row][col] = min(insertion_cost, deletion_cost, substitution_cost)
*# get the operation*
if cost[row][col] == substitution_cost:
operations[row][col] = 'S'
elif cost[row][col] == ins_cost:
operations[row][col] = 'I'
else:
operations[row][col] = 'D'
return cost[len(seq1), len(seq2)], min_cost_path(cost, operations)
对样本序列执行上述功能。
seq1 = "numpy"
seq2 = "numexpr"score, operations = edit_distance_dp("numpy", "numexpr")print(f"Edit Distance between `**{**seq1**}**` & `**{**seq2**}**` is: **{**score**}**")
print("**\n**Operations performed are:**\n**")
for operation **in** operations:
if operation == '-':
print('No Change.')
elif operation == 'I':
print('Insertion')
elif operation == 'D':
print('Deletion')
else:
print('Substitution')
输出:
Edit Distance between `numpy` & `numexpr` is: 4.0Operations performed are:No Change.
No Change.
No Change.
Insertion
Deletion
No Change.
Substitution
用编辑距离解决问题。
我们将要使用的数据集包含一些文件,这些文件包含为 Python 语言的两个版本(3.6 和 3.9)安装的包及其版本的列表。
两个档案中关于熊猫套餐的记录是:
pandaspandas==1.2.1
在这个练习中,对于一个文件中提到的每个包,我们将从第二个文件中找到最合适的一个。适用性将基于 Levenstein 距离或编辑距离度量。
加载数据
def preprocessor(package):
*"""*
*This takes a input package and applies preprocessing steps like converting to lowercase,*
*strip the `\n` and `space` from the ends.*
*"""*
return package.lower().strip()
加载 Python 3.6 的需求
*# Open the file and read the list of packages*
with open('/kaggle/input/pip-requirement-files/Python_ver36.txt', 'r') as f:
py36 = f.readlines()
*# clean the data*
py36 = list(map(preprocessor, py36))
print("Number of packages for Python 3.6 are: ", len(py36))
print(f"**\n**Few of the records are:**\n{**py36[:5]**}**")
输出:
Number of packages for Python 3.6 are: 276
Few of the records are:
['absl-py==0.11.0', 'alabaster==0.7.12', 'anaconda-client==1.7.2', 'anaconda-project==0.8.3', 'appdirs']
加载 Python 3.9 的需求
with open('/kaggle/input/pip-requirement-files/Python_ver39.txt', 'r') as f:
py39 = f.readlines()
*# clean the data*
py39 = list(map(preprocessor, py39))
print("Number of packages for Python 3.9 are: ", len(py39))
print(f"**\n**Few of the records are:**\n{**py39[:5]**}**")
输出:
Number of packages for Python 3.9 are: 146
Few of the records are:
['alabaster==0.7.12', 'anyio==2.0.2', 'appdirs==1.4.4', 'argon2-cffi==20.1.0', 'astroid==2.4.2']
获取需求文件之间的成对距离
现在,我们已经构建了一个函数来计算两个序列之间的编辑距离,我们将使用它来计算来自两个不同需求文件的两个包之间的得分。
然后,对于 Python 3.6 版本的需求文件中提到的每个包,我们都会从 Python 3.9 版本文件中找到最匹配的包。
*# to store the best matching package for py36 found in py39*
p36_best_match = {}*# for each package in py36 get the score*
for pack36 **in** py36:
best_score = float('inf')
best_package = None
*# match with each package in py39*
for pack39 **in** py39:
*# get the edit distance between pack36 and pack39*
score, _ = edit_distance_dp(pack36, pack39)
*# if the score is less than best score so far*
*# store the new score and package name*
if score < best_score:
best_score = score
best_package = pack39
*# append the details of best package found for pack36*
p36_best_match[pack36] = (best_package, best_score)*# print the results*
for pack36, (pack39, score) **in** p36_best_match.items():
print(f"Best matching package for `**{**pack36**}**` with distance of **{**score**}** is `**{**pack39**}**`")
部分输出记录:
Best matching package for `absl-py==0.11.0` with distance of 9.0 is `py==1.10.0`Best matching package for `alabaster==0.7.12` with distance of 0.0 is `alabaster==0.7.12`Best matching package for `anaconda-client==1.7.2` with distance of 15.0 is `nbclient==0.5.1`Best matching package for `anaconda-project==0.8.3` with distance of 17.0 is `odo==0.5.0`Best matching package for `appdirs` with distance of 7.0 is `appdirs==1.4.4`Best matching package for `argh` with distance of 10.0 is `rsa==4.7`
检查上述解决方案的准确性
为此,我们将简单地从 py36 和 py39 中去掉包名==x.x.x的版本部分,然后检查它们是否相同。
*# this function will trim the versions and return of they are same or not*
def is_same(pack1, pack2):
return pack1.split('==')[0] == pack2.split('==')[0]print(f"Are packages `pandas` and `pandas==1.1.1` same? **{**is_same('pandas', 'pandas==1.1.1')**}**") **Are packages `pandas` and `pandas==1.1.1` same? True**
获得准确性
*# get total number of packages in py36*
total_packs_in_py36 = len(py36)*# get the count of records where match was found*
total_matched_records = sum([is_same(pack36, pack39) for pack36, (pack39, _) **in** p36_best_match.items()])*# get the accuracy*
accuracy = total_matched_records * 1.0 / total_packs_in_py36print(f"The total number of correct matches are: **{**total_matched_records**}** out of **{**total_packs_in_py36**}** and the accuracy is: **{**accuracy**:**.2f**}**")
输出:
The total number of correct matches are: 138 out of 276 and the accuracy is: 0.50
让我们看看下面的例子,了解为什么我们的准确度如此之低。
距离为 10.0 的
*xlrd*最佳匹配包是*rsa==4.7*
*# find the actual corresponding record of 'xlrd' in py39 list*
for pack39 **in** py39:
if pack39.startswith('xlrd'):
print(pack39)
break
输出:
py39 列表中没有匹配的“xlrd”记录,因为 Python 3.9 版本中从未安装过它。
py36 中的记录数是 276 ,而 py39 中只有 146 ,因此我们只能找到 py36 列表中记录的 53% ( 146/276 )的匹配名称。
此外,所使用的数据被上传到 Kaggle 上,可以使用https://www . ka ggle . com/pikkupr/implement-edit-distance-from-sratch访问工作笔记本
希望解释清楚了,你从这个笔记本中学到了什么,如果你有任何问题,请在评论中告诉我。
学习复制论文:初学者指南
思想和理论
如何理解深度学习论文并实现所描述的方法的分步指导。举个例子:今天我们要复制一篇关于图像超分辨率的基础论文。

来源:https://arxiv.org/abs/1608.00367
对于数据科学家来说,能够复制最新的科学论文是一项极具竞争力的技能。因为没多少人能做到。
如果你想成为一名思想家,了解黑匣子里正在发生的事情,激发你的创造力,或者成为第一个将最新科学研究引入商业的开发者——这篇文章就是为你准备的。
今天我们将讨论如何选择一篇“好”的论文,这对初学者来说相对容易;我们将概述典型的论文结构和重要信息的位置;我会给你一步一步的指导,告诉你如何实现纸质实现,并分享一些链接,当你遇到困难时,这些链接会对你有所帮助。
这个帖子也有一个“实践部分”,所以今天我们要复制一篇关于图像超分辨率的基础论文。我不指望你有超分辨率的经验,但我假设你已经与卷积神经网络。这次的深度学习框架是 Tensorflow 2。
内容
—从哪里开始?
—论文结构:跳过什么,读什么
—举例。理解论文
—哪里可以找到帮助?
—举例。我们来编码一下
—祝你好运!
从哪里开始?
如果你希望你的学习顺利,没有压力,你应该找到一个“好”的论文。作为一个起点,我真的推荐你选择 一篇老的高被引论文 来描述你所熟悉的概念。
- 老的高被引论文通常解释非常基本的概念,成为最近研究的基础。你知道基本原理——你也会更好地理解最近的论文。对于深度学习来说,2016 年之前的论文被认为已经很老了。
- 高被引论文可复制。这意味着许多其他科学家能够理解和实施这种方法。要想知道某篇论文被引用的次数,在谷歌学术谷歌一下。引用次数超过 1000 次的论文被认为是高被引论文。
- 通常,较老的论文描述的是较简单的概念,这对于初学的你来说是一大加分。
这几周我一直在看关于超分辨率的论文,所以我选择了这个 2016 年的研究来和你一起重现——加速超分辨率卷积神经网络。它描述了用于超分辨率任务的第一个基于 CNN 的模型之一——fsr CNN(快速超分辨率 CNN)。
超分辨率任务非常简单:取一张低分辨率(小,质量差)的图像,然后把它变成高分辨率(大,质量好)。正如我所说的,你不需要任何超分辨率的经验就能理解这篇论文,然而,CNN 是一个你必须熟悉的概念。

超分辨率任务:高级可视化。作者图片
论文结构:跳过什么,阅读什么
典型的深度学习论文具有以下结构:
1.摘要
2。简介
3。相关工作
4。详细介绍
5。实验
6。结论
7。参考

典型深度学习论文的结构。作者图片
1。摘要是“营销”的总结。它很短,重点是为什么这种方法比以前的方法更好,以及它的新颖之处。摘要发表在会议日程和在线档案中(如 Arxiv ),它们唯一的目标就是说服你阅读这篇特定的论文。你已经选择了一篇要阅读(和复制)的论文,所以可以随意跳过摘要。
2。简介是一个重要的章节,也是必读的。它给出了该方法的高级概述。通常情况下,它并不太专业,而且非常“人性化”,所以先阅读介绍部分,在深入研究算法细节之前,先预热一下大脑。
3。相关工作。所有科学论文(以及深度学习)都是相关的:每一项发现都是建立在数十名研究人员之前的工作基础上的。相关工作概述是每篇论文的必修部分。作者必须确保他们的工作是相关的,解决重要的问题,并且不重复其他研究人员以前做过的工作。这对于科学界来说是一个重要的部分——但对于我们(从业者)来说不是,所以跳过它!
(好吧。有时你可能需要它——但只是在你寻找该领域其他基本论文/概念的情况下。)
4。走近细节。有趣的事情开始了。这是论文中最复杂和最具挑战性的部分,也是最重要的部分(一定要读!).不要期望太高,也不要期望从一次阅读中理解所有的东西。这是你在编码时会一次又一次回来的部分。
不要害怕复杂的公式,大多数情况下,它们解释的是基本概念。我相信研究人员就是这样开玩笑的。过一会儿,你会习惯的。
在阅读论文时,捕捉你可能需要的所有信息——数据预处理技术、详细的神经网络架构、损失函数、训练技巧和后处理。尽你所能去得到它。如果你试了几次还是不明白,没关系,以后我会告诉你怎么做。
5。实验。这个部分充满了图表、表格和图像。通常,它包含有关数据集、训练和评估的详细信息,以及对该模型在各种超参数下的表现以及与其他论文中最先进方法的比较的综述。如果论文是关于计算机视觉的,也会有模型预测的可视化。我会说这一部分是你唯一感兴趣的部分。
6。结论是论文的总结,有时包含作者对未来研究的想法。你应该跳过它。
7。参考文献。科学界(不仅仅是科学界)有一条严格的规则:如果研究人员使用了属于他人的观点,他/她需要添加对原始作品的引用(引用)。当这些参考文献中的概念已经在论文中解释过,或者不重要时,你可能会跳过大部分这样的参考文献。然而,有时作者可能会说:“我们使用了论文[2]中描述的模型架构,只修改了最终层中的激活”。在这种情况下,你需要找到并阅读文章[2]来完全理解这种方法。
现在——该读报了。关掉音乐,把手机调到飞行模式,喝杯茶。在接下来的 30 分钟里,你应该高度集中注意力,因为你正在潜入一个新的世界——令人兴奋,但相当具有挑战性。
在这一点上,我建议您暂停阅读论文加速超分辨率卷积神经网络,我们接下来将复制该论文。注意数据预处理、模型架构、损失函数和训练细节。
举例。理解论文
完成了吗?太好了。现在,让我们回顾一下我们从论文中获得的所有重要细节,以再现快速超分辨率 CNN (FSRCNN)。
FSRCNN:一般信息
- 所提出的方法是一种卷积神经网络,它采用低分辨率(LR)图像,“巧妙地”以某种因子放大它,并返回高分辨率(HR)图像。所以输出图像比输入大 N 倍。
- 放大因子 N 由用户定义,并且是像 2、3、4 等这样的数字。放大因子越大,恢复质量越差。
- 特定的放大因子需要单独的神经网络来训练。这些网络仅在最后(去卷积)层不同,并且可以共享所有其他层的权重。
FSRCNN:模型架构
- 模型由几个连续的卷积层和一个最终的反卷积层组成。下面是一个详细的流程:
—内核大小= 5×5、滤波器个数= d
的卷积层—参数化 ReLU 激活
—内核大小= 1×1、滤波器个数= s 的卷积层
—参数化 ReLU 激活
—内核大小= 3×3、滤波器个数= s
的 m 个卷积层—参数化 ReLU 激活(不清楚这 m 个卷积层之间是否使用了激活函数。可能,他们是。)
—卷积层,内核大小= 1×1,滤波器数量= d
—参数 ReLU 激活
—去卷积层,内核大小= 9×9,步幅=放大因子,滤波器数量=图像中的通道数量(由于某种原因,作者使用 1 作为通道数量,但对于彩色图像,它应该是 3。还是我错过了什么?)
—最后一层无激活功能 - 零填充用于所有层。
- d、s、m 是超参数。作者推荐使用 d=32,s=5,m=1 进行实时预测,使用 d=56,s=12,m=4 获得更好的恢复质量。

FSRCNN 架构。来源: 加速超分辨率卷积神经网络
FSRCNN:数据
- 模型在 T91 数据集上进行训练,并在 General-100 上进行微调。
- 这些数据集只有高分辨率图像。低分辨率图像是通过缩小高分辨率图像来创建的。
- 数据扩充是 90 度旋转和作物。每张图像都以各种可能的方式旋转了 90 度,并通过滑动窗口裁剪成小块。看起来这些扩充是在训练之前完成的(但不是随机进行的),所以最终的训练集是预定义和固定的。
FSRCNN:培训详情
- 损失是 MSE(均方误差)。
- 优化器是随机梯度下降。
- 卷积层训练期间的学习率是 0.001,去卷积层是 0.0001;微调学习率低两倍。
- 去卷积层的权重通过从具有零均值和标准偏差= 0.001 的高斯分布中随机抽取来初始化。
- 卷积层的权重用[23]中为 PReLU 设计的方法初始化。这是对另一篇论文的引用,那篇论文解释了正规的初始化式。
我们现在对 FSRCNN 有了相当多的了解,可以转到编码和训练。
去哪里寻求帮助?
对许多人来说,“复制论文”意味着“快速阅读论文,然后在互联网上寻找现成的实现”。这是最简单的方法,但不是有益的方法。我真的建议你从头开始,不要马上寻找现成的解决方案。至少自己做些事情——那是你学习的时候。
即使你完全是复印纸张的初学者,你也总有办法做到:
- 下载数据集,探索它,编写一个数据加载器。
简单易行的任务,但一旦完成,它会给你信心并帮助你继续前进:
- 开始写模型架构,简化或者跳过不理解的部分。有一个奇怪的权重初始值设定项——现在跳过它,使用默认的。您以前从未使用过 PReLU 激活,请改用 ReLU。你现在的目标是创建一个可训练的模型,不是纸上谈兵的模型或者性能好的模型,只是可训练的。它有输入,有输出,所以你可以运行培训。
- 论文中有一个自定义丢失——用深度学习库中实现的类似的替换掉。
- 对优化器、数据扩充、后处理做同样的事情——简化或跳过。
你最终会被征召入伍。你甚至可以训练一下草稿,看看效果如何——也许结果不会那么糟糕🙂
然后填补空白,修复工作不佳的部分。首先,自己进行实验——测试你在写草稿时想到的想法,再读一遍论文,希望能抓住你之前漏掉的概念。如果你很快就卡住了,不要沮丧。你写了一份草稿,这是一个很大的进步,你已经学到了很多。所以下一次,下一篇论文你会写得更好。这是一个学习的过程。
感觉完全卡住了?搜索的最佳时机。
记住,我建议你选择一篇高被引论文。现在你会感受到好处。流行的报纸在互联网和博客上有许多描述复杂部分的实现。尽情享受吧!
第一个要检查的地方是代码为的论文,这是一个很大的库,可能包含了所有流行论文的代码实现。这些实现要么是官方的,要么来自像你我这样的研究人员。例如,在 PyTorch 和 Tensorflow 中,FSRCNN 在代码为的论文上实现了 7。(好了,现在是 8,我也添加了我的实现。)
你可以复制粘贴,但是要花时间去理解这些代码。这是最后一条建议。
举例。我们来编码吧!
现在我将向您展示如何用代码实现 FSRCNN。深度学习库这次是 Tensorflow 2。
当你在实现论文中的方法时,没有必要 100%准确地复制它。所以关掉完美主义模式,开心就好!使用不同的数据集,试验模型架构,添加数据扩充,改变损失函数,…
数据
- 让我们使用 DIV2K 来代替 T91 和 General-100 数据集。这是一个更新、更大的数据集,是专门为超分辨率任务创建的。
- 我们只从 DIV2K 获取高分辨率(HR)图像,包括训练和验证部分,总共 900 张图像。然后将训练和验证部分合并到一个文件夹中,并根据图像 id 创建自定义的训练-验证-测试分割:训练的 id 为 1–700,验证的 id 为 701–800,测试的 id 为 801–900。低分辨率(LR)图像是通过双三次下采样从高分辨率图像生成的。
- 对于训练和验证数据扩充,让我们使用随机裁剪成 648×648 小块、水平翻转以及亮度、对比度、饱和度和色调的轻微变化。对于测试集,我们只对 648×648 的小块进行随机裁剪。在 HR 图像上执行数据增强,并且从增强的 HR 图像创建 LR 图像。
- 选择这种随机裁剪大小,以便它甚至可以应用于 DIV2K 数据集中最小的图像。648 可以被 4 整除,这是我们模型中的比例因子。
- 因此,这里是我们得到的 Tensorflow 数据加载器。

数据准备流程。作者图片
型号
- 我们创建一个上采样因子为 4 的模型,因此输入是大小为 162×162 的 LR 图像(因为 648/4 = 162),输出是大小为 648×648 的 HR 图像。
- 模型层、过滤器大小和数量、激活、填充和初始化器与论文中描述的相同。
- PReLU 激活有点棘手,因为它有一个可学习的参数— alpha。当在 Tensorflow 中使用默认参数初始化 PReLU 时,每次激活都有数千个这样的 alphas。然而,根据论文,这个数字应该很小。我在 Tensorflow PReLU 文档中找到一个建议,像这样跨维度共享 alpha】,我也这么做了。它大大减少了激活中的参数数量。
- 这里是完整的 Tensorflow 模型代码。超参数 d、s、m 是在模型初始化期间指定的。我们使用 d=56、s=12 和 m=4,这应该给出最佳的恢复质量。
训练详情
- 初始学习率为 0.001。对所有层使用相同的学习速率更简单,并且该模型也训练得相当好。让我们使用 ReduceLROnPlateau 回调来降低每次列车损失停止下降时的学习率。
- RMSprop 被用来代替 SGD,因为它可以确保更快更流畅的训练。
- 我用 batch_size=30 和 steps_per_epoch=20 进行训练。使用 batch_size=20,steps_per_epoch=4 进行验证。您可以更改这些数字,但是请注意,batch_size*steps_per_epoch 不能超过数据集大小。
- 最大历元数为 500。当验证损失停止下降时,我们使用提前停止回调来完成训练。当我训练模型时,它在大约 300 个时期内完成。
- 我在单个 GPU 上花了大约 5 个小时来训练这个模型。
- 这里是用于训练的代码和带有训练配置的文件。
评估
- 超分辨率模型用度量— 峰值信噪比 (PSNR)进行评估。这里是它的 Tensorflow 实现。我们的模型 PSNR 在 DIV2K 测试集上是 26.625。
- 更有意思的是看结果是什么样的。通常,模型恢复质量是根据双三次上采样进行视觉评估的。
- 虽然用双三次插值上采样的图像看起来有点模糊,但用 FSRCNN 上采样的图像具有更好的纹理。
- 如果你想看更多的模型预测,这里有一个笔记本供你参考。

FSRCNN 在 DIV2K 测试集上的性能。左—输入图像,右 FSRCNN 的输出。

由 FSRCNN 恢复的图像比向上采样的图像具有更多的纹理。

FRCNN 恢复质量仍然远非完美,即使它是在 2K 分辨率图像上训练的 s。
祝你好运!
再一次:
- 选择一篇旧的高被引论文。
- 通读一遍,尽量抓住——数据准备、模型架构、损失函数、训练细节。
- 什么都不懂也不要难过。
- 通过跳过和简化您不理解的概念来创建一个实现草案。如果你的草稿与论文中的方法相差甚远,也没关系。
- 试着自己去完善草稿。
- 当你遇到困难的时候——在互联网上寻找文章和用纸实现的代码。复制粘贴,但要阅读理解。
- 把你的工作包装成 Github 项目(为什么不呢?).看,我是怎么做到的。
- 用一篇新论文重复。感受一下第二次有多顺利🙂
真正的学习发生在步骤 2-5,所以你在这里花的时间越多,你学得越快。祝你好运!
原载于 2021 年 8 月 10 日https://notrocketseconomy . blog。
如果你想阅读更多类似的教程,请订阅我的博客“不是火箭科学”——电报 和 推特 。
用图形卷积神经网络学习嗅觉(分子)
结合化学和图形深度学习的端到端项目

在这里,我们要完成以下任务:
- 构建一个定制的图形数据集,其格式适合在 DGL 工作(这是本文的主题😎)
- 随机准备训练和测试数据集(了解这一点很好👍)
- 定义 Conv 网络图(小菜一碟🍰)
- 训练和评估准确性(像往常一样🧠)
1.构建适用于 DGL 的自定义图表数据集格式
我们要处理的数据集来自于AIcrowd Learning to smear Challenge,它由一个列和另一个列组成,其中一个列是识别特定分子的微笑字符串,另一个列是这些分子的气味名称。
https://www.aicrowd.com/challenges/learning-to-smell
例如,下表中的第二个分子,碳酸二甲酯-13C3,其微笑是 COC(=O)OC,其气味被定义为“清新、飘渺、果味”,这当然与人们对这种物质的了解相对应[1]。对于所有这些 4316 个分子,有 100 多种不同的气味形成无序的组合。
然后,我们希望 a)将每个分子的微笑转换成 DGL 图,b)标记它是否有水果味,c)去除任何有问题的分子。以下代码块处理每个请求:
A)必须为每个分子定义 DGL 图形对象。我们可以使用 RDKit 首先从它的微笑中形成一个 mol RDKit 对象(第 2 行)来实现这一点。由于我们想识别节点及其连接,我们可以得到邻接矩阵(第 3 行和第 4 行)。非零值的索引标识连接的节点(第 5 行)并给出双向图的源节点和目的节点(第 6 行和第 7 行)。
我们使用来自 ogb 库【2】的atom_to_feature_vector来生成原子的特征向量
例如,当我们对字符串 COC(=O)CO 应用feat_vec 时,我们得到:
注意,每一行对应于一个具有 9 个特征的原子。这些特征是原子的物理化学性质,例如,原子序数、氢的数目,或者原子是否在环中,等等。
c)现在我们有了带有特征的图表,是时候定义标签了。正如我们所见,每个分子都与一种以上的气味相关联。这里为了简单起见,问题将是一个二元分类来确定分子是否有水果气味。下面的代码块执行该任务,如果有水果香味,则分配标签 a 1 ,如果没有,则分配标签 0 。
在这个数据集中,我注意到有一小部分分子没有正确地转换成 DGL 图,所以我决定去掉它们。我通过简单地忽略如下所示的异常来做到这一点:
2.随机准备训练和测试数据集
完成所有这些步骤后,数据集就准备好了,但我们将进一步将其转换为 DGL 数据集,以便顺利地进行预处理并形成训练和测试子集。这里我将引用 DGL 团队的“制作自己的数据集”官方教程中的概述[3]:
您的自定义图形数据集应该继承
dgl.data.DGLDataset类并实现以下方法:
__getitem__(self, i):检索数据集的第i个例子。一个例子通常包含一个 DGL 图,偶尔还包含它的标签。
__len__(self):数据集中的样本数。
process(self):从磁盘加载并处理原始数据。
过程方法是我们给图形加标签的地方。从一个文件中得到它是可能的,但是在我们的例子中,只有图表列表和标签列表被转换成 torch 张量。因此这是一个非常简单的类:
然后,我们继续构建列车并测试随机抽样。这样做的好处是可以设置批量大小。在这里,我们将其设置为每批五个图形:
**3。**定义 Conv 网络图
我们正在定义 GCNN 的路上。我已经在之前的一篇文章中解释了 GCN 类是如何构建的。每个节点都有一个输出特征张量,因此为了进行二元分类,我们可以将输出特征的长度设置为类的数量(此处为两个),然后使用dgl.mean_nodes对所有特征节点进行平均,以获得每个图的平均(二维)张量:
**4。**训练和评估准确性
最后,我们建立模型,每个原子接受 9 个原子特征,并返回一个二维张量,用于定义是否有水果香味。历元在批次上运行,损失用交叉熵计算。最后一部分只是一个循环,对正确的预测进行计数,以评估准确性:
我们得到的精度大约是 0.78,这已经很不错了。现在,你可以尝试预测其他气味,甚至更好地制作你自己的定制数据集,与分子或任何你想要的 DGL 一起工作。
如果你想试代码,打开这个 Colab 笔记本。如果你有任何问题,我将非常乐意回答。最后,考虑订阅邮件列表:
https://jnapoles.medium.com/subscribe
并查看我以前的帖子:
参考资料:
https://doi.org/10.1039/C7GC01764B
https://github.com/snap-stanford/ogb
学习使用数据科学中最重要的七个 python 库
作为一名数据科学家,这些库将在实现 ML/DL 算法的同时拯救你的生命。

马库斯·斯皮斯克在 Unsplash 上的照片
嗯,说我作为一名数据科学家在工作中不使用图书馆,就像说我拥有一辆自行车,但只能通过步行从一个地方到另一个地方。这在理论上是可能的,但并不是对所有的情况都切实可行或有效。类似于不同的交通方式,我们在 python 中有多个库,这让我们的工作变得更加简单快捷。了解这些库将帮助您在从头实现算法时节省精力、时间和脑力。
目前,当数据科学蓬勃发展时,有多个用于实现一个算法的库,因为所有这些选项而感到不知所措完全没关系。在本文中,我将列出一些基本的库及其用例,帮助您找到适合您的用例的库。
NumPy
好吧,我在这里陈述明显的事实。NumPy 是我们社区中最重要和最常用的库之一。它是处理数组、结构化数据、科学计算、统计分析(如均值、中值、线性代数)等的最佳库。NumPy 库在计算速度上是非常高效的。
你可以在这里了解更多关于 NumPy 的信息。
尝试一下这种实践体验:
- 生成两个大小为(10,10)的数组,分别命名为 array1 和 array2,并用随机整数填充。
- 找出数组 1 中值大于 10 的位置,并将它们设为 0
- 找出数组 2 中值小于 5 的位置,并将它们设为 10
- 将这两个数组按元素相乘
- 将结果数组保存在一个。npy”文件
试着用尽可能少的代码行来实现这些,以体验 NumPy 的效率。
熊猫
Pandas 主要用于读取、分析、操作和保存表格数据。Pandas 本质上提供了两种数据结构。
- 系列——熊猫系列是一维数据结构,由一个键值对组成。它类似于 python 字典。
- 数据框-熊猫数据框是一种二维数据结构。它是两个或两个以上熊猫系列的组合。
每当我得到 CSV 文件中的数据时,我想到的第一件事就是用熊猫来分析。这是一个用于数据分析、操作和填充缺失值等的基本库。
你可以在这里了解更多关于熊猫的信息。
尝试一下这种实践体验:
- 从这里下载 csv,并用于所有实验。
- 读取 csv 文件并删除重复的行
- 对于具有整数/浮点值的列,获取统计参数,如平均值、中值、方差等。
- 将数据帧写入 csv 文件
Matplotlib
Matplotlib 是一个数据可视化的常用库。从为了我们的理解而可视化数据到为演示文稿制作漂亮的可视化效果,matplotlib 全都做了。我想你可以理解 matplotlib 的作用在一个数据科学家的生活中是多么重要。
你可以在这里了解更多关于 matplotlib 的信息。
尝试这些方法来获得实践经验:
- 使用两个系列数据绘制标准图表。
- 向图表、x 轴和 y 轴添加标题
- 为图表添加图例
- 保存图表
sci kit-学习
Scikit learn 是一个有价值的库,用于实现各种传统的机器学习算法,包括监督和非监督算法。您可以实现各种算法,如决策树、随机森林、KNN、K-means 等。,可在 Scikit 中获得。该库还提供了各种数据预处理和后处理算法的实现,如标准化、将标签转换为一键编码等。您会发现这个库出现在许多课程和书籍中,因为它的实现范围很广。因此,每当您必须实现任何基本的机器学习算法时,您应该首先尝试看看 scikit learn 是否可以使用。
你可以在这里了解更多关于 Scikit 的知识。
尝试这些方法来获得实践经验:
- 从这里下载住房数据,并阅读使用熊猫
- 使用 pandas 填充缺少的值,使用 matplotlib 可视化数据
- 使用 sklearn 的 scaler 模块归一化数据,然后使用 sklearn 拟合线性回归模型。
上面的练习展示了如何使用多个库来解决一个基本的机器学习问题。
OpenCV
如果您正在处理图像或视频,几乎不可能找到可以与 OpenCV 的功能范围相匹配的库。它提供了广泛的传统图像处理算法,如 canny 边缘检测,SIFT,SURF,hough 变换等。它还提供了基于深度学习的算法的实现,用于图像分类、对象检测、分割、图像中的文本检测等。我在图像和视频方面做了很多工作,我可以告诉你,对于任何任务,我都必须至少使用一次 OpenCV。
你可以在这里了解更多关于 OpenCV 的信息。
尝试一下这种实践体验:
- 下载任何图像,然后使用 OpenCV 读取图像
- 将图像转换为灰度
- 使用双边滤波器减少图像中的噪声,然后应用腐蚀和膨胀滤波器。
- 使用 canny 边缘检测器在图像中查找边缘
- 保存新图像。
NLTK
就像 OpenCV 是图像和视频的基本库一样,NLTK 是文本的必要库。对于所有任务,如词干化、词汇化、生成嵌入、标记化、可视化等。,可以使用 NLTK 库。NLTK 库中也实现了一些必要的深度学习算法。
你可以在这里了解更多关于 NLTK 的信息。
尝试一下这种实践体验:
- 使用本文集。将整个语料库转换为小写
- 对语料库进行分词,然后对给定数据进行词干提取。
PyTorch
虽然我是最后写这篇文章,但我对 PyTorch 的开发者感激不尽。这是我实现任何自定义神经网络或基于深度学习的方法的首选库。无论是音频、文本、图像、文本还是表格数据,都可以使用 PyTorch 编写一个神经网络,在给定的数据上训练一个模型。PyTorch 还在 GPU 上部署基于深度学习的方法方面发挥了重要作用,通过使用并行化减少了推理时间。
你可以在这里了解更多关于 PyTorch 的信息。
尝试一下这种实践体验:
- 下载 MNIST 数据集
- 为数据和优化器编写数据加载器
- 编写自定义的全连接神经网络
- 为 MNIST 数据集训练神经网络
- 评估验证数据集上的模型
- 保存模型。
结论
我已经包含了我在数据科学例程中使用的所有库。并不是只有这些库。这里提到的每个库都有一个可供选择的库。但总的来说,我认为这七个库提供的功能范围是竞争对手中最好的。如果你觉得更多的库需要包含在这个列表中,请在评论中告诉我。
关注我们的 medium 了解更多此类内容。
成为 媒介会员 解锁阅读媒介上的无尽故事。
了解什么是深度图以及如何用 Python 创建深度图

使用币安的 API 获取订单数据
如果你曾经冒险进入任何一个加密货币交易所,我敢肯定你已经看到了一个深度图,就像上图中的那个。在本文中,我想快速讨论深度图实际上是什么,我们可以从中推断出什么样的信息,然后展示如何使用 Python 创建深度图。
请记住,这是一篇专注于获取订单簿数据和创建适当的可视化的文章。这不是一条投资建议!
深度图——是什么?
深度图是一种可视化,它告诉我们特定资产(股票、商品、密码等)的需求和供给。)价格不同。它基于订单簿数据,即未结买卖订单的数量,包括资产的数量。此类订单的数量越大,该资产的市场流动性就越强。
交易员利用实时供求来评估资产价格的可能走向。此外,它还用于估计在不导致价格上涨的情况下可以购买的资产单位数量。举个例子,一个流动性很强的资产(有大量买家和卖家)的价格在一个大订单完成后不太可能有太大变化。缺乏流动性的资产就不一样了。
Python 中的示例
和往常一样,我们从导入所需的库开始。
为了创建深度图,我们需要访问订单簿数据。我们从币安 ( 免责声明:附属链接)获得数据,这是最受欢迎的加密交易所之一。我们可以通过多种方式访问数据:
- 通过 Python 的
requests库使用币安的 API, - 使用非官方的
python-binance库, - 使用
binance-connector图书馆。
我们将采用最后一种选择。我们从实例化币安客户端开始。对于这个特定的端点,我们不需要帐户和 API 密钥。然而,如果你计划更广泛地使用他们的 API,你可能想要设置它。然后,我们使用depth方法为ETHUSDT对下载订单簿数据。
返回的数据存储在一个带有以下关键字的字典中:[‘lastUpdateId’, ‘bids’, ‘asks’]。出价和要价被存储为列表的列表,所以我们需要使用下一个代码片段将它们转换成一个pandas数据帧。
数据帧如下所示:

作者图片
我们也可以使用describe方法来检查数据。
df.groupby("side").price.describe()

作者图片
我们可以看到每边包含 100 个观察值。我们可以要求每边多达 5000 次观察。更多详情,请参见文档。
作为探索订单簿数据的第一步,我们可以使用散点图将其可视化。

作者图片
虽然我们已经可以看到更多的数据细节,但很难根据图表做出任何决定。这就是为什么我们需要更多的聚合。作为探索这些数据的第二步,让我们绘制一个直方图。

作者图片
直方图显示了具体价格的出价和要价数量,但是它掩盖了交易量。这意味着价格为 3300 美元、数量为 0.1 个硬币的数据点实际上与价格为 3301 美元、数量为 100 个硬币的数据点价值相同。
该图中所有条形的总和将是 200,因为我们有那么多数据点。
我们可以通过创建一个加权直方图将关于数量的信息合并到分析中,这只需要对代码做一点修改。

作者图片
这个情节已经传达了一个更准确的关于供求的故事。但很难据此做出决定。假设您想要购买 50 个 ETH。使用加权直方图,您无法判断您需要以什么价格出价来确保您的购买订单将被匹配引擎满足。这就是深度图发挥作用的地方。
为了回答上面的问题,我们需要以升序排列的数量和价格信息的累积和。同样,对于与上面相同的问题,但重点是要价,我们需要降序排列的类比信息。
我们可以通过使用经验累积分布函数 ( ECDF )得到上述信息。seaborn附带了一个方便的函数(sns.ecdfplot),我们可以用它来获取图表。为了得到我们确切需要的,我们必须指定一些参数:
*weights*=”quantity”—确保 ECDF 按数量加权,就像我们对加权直方图所做的那样,*stat*=”count”—因此我们使用计数,并且该图没有标准化到范围[0,1],*complementary*=True—当我们想要颠倒累计和的顺序时。我们只在出价的情况下使用这个。

作者图片
利用这个图,我们可以回答前面提出的问题。为了相对确定我们 50 ETH 的订单将被完成,我们应该提供大约 3392.5 美元每 ETH。
外卖食品
- 深度图是一种显示特定资产在不同价格下的需求和供给的可视化形式。
- 我们可以基于订单簿数据构建深度图表,即特定价格的买卖订单列表。
- 查看深度图,我们可以估计购买/出售一定数量资产的目标价格,以确保交易所的匹配引擎将履行订单。
您可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特上或者评论里联系我。
喜欢这篇文章吗?成为一个媒介成员,通过无限制的阅读继续学习。如果你使用这个链接成为会员,你将支持我,不需要你额外付费。提前感谢,再见!
您可能还会对以下内容感兴趣:
[## 用 Python 创建交互式烛台图表的最简单方法
towardsdatascience.com](/the-simplest-way-to-create-an-interactive-candlestick-chart-in-python-ee9c1cde50d8)
参考
跟我学:图像字幕
让我们一起学习并创建一个神经网络模型,它以一幅图像作为输入,并返回一个描述性文本作为输出。

k .米奇·霍奇在 Unsplash 上拍摄的照片
介绍
不久前,我开始尝试“图像字幕”的问题。这里,目的是为给定的图像生成文本描述。类似于一个人如何向他的同伴描述一幅画。正如在实验中经常发生的那样,你不会直接得到最佳解决方案——你会尝试、犯错、改进自己,然后最终得到一个不错的解决方案。这正是我对这个项目的探索。在本文中,我想介绍我是如何开始解决这个问题的,偶然发现一个不太好的解决方案,但最终达到了“足够好”的状态。所以,让我们开始吧!
问题定义
如前所述,任务是为图像生成自然语言描述或标题。这个问题非常有趣,因为它是两个领域的结合——计算机视觉(CV)和自然语言处理(NLP)。因此,要想出一个手写的高级解决方案,我们需要这样做——将图像作为输入,用 CV 做一些魔术,用一个做一些 NLP 魔术的块修补它,并期望文本描述作为输出。听起来很简单,对吗?让我们试试这个。😃
资料组
在深入研究技术细节之前,让我们花一些时间来理解我们的数据集——“Flickr 8k”。它由 8091 个图像(大小不同)组成,每个图像有 5 个不同的标题,因此标题总数为 8091*5=40455。我们有一个图像文件夹(包含所有的图像),和一个标题文本文件(CSV 格式),将每张图像映射到它的 5 个标题。首先,让我们看看字幕文件是什么样子的,

标题 CSV(按作者)
让我们也来看一些图片和它们各自的标题,

带标题的示例图像(由作者提供)

带标题的示例图像(由作者提供)
模型架构——第一次尝试
拐弯抹角说够了,让我们来形式化我们将用来解决这个问题的神经网络模型的架构。正如我们已经讨论过的,整个流程看起来会像这样,

我们将在本文中创建的解决方案的高级流程(按作者)
现在选择第一部分,也就是说,首先,我们要用计算机视觉来处理图像。这种“处理”通俗的解释就是把一个图像作为输入,转换成矢量表示。在这样做的同时,希望网络将学习到字幕所需的重要信息,而忘记不相关的信息。所以我们希望图像作为输入,向量作为输出。在 CV 中最常见的方法是使用卷积神经网络。详细讨论 CNN 超出了本文的范围,但是为了简单的细节,我将建议这个。首先,为了测试 waters,我们可以创建简单的 CNN 图层。代码如下所示,

CNN 部分的代码(按作者)
理解代码,
- **第 6 行:**初始化顺序 Keras 模型
- **第 9–21 行:**你可以看到一对多次使用的
Conv2D和MaxPooling2D层。这是定义 CNN 模型最常见的方式之一。 - 第 23 行:我们展平最后一层,创建一个矢量作为图像表示。
- **第 24 行:**这是最终的 CNN 图层,我们已经将图像表示缩减为 256D 大小的矢量。
接下来,我们希望将这个向量表示输入到 NLP 模块中,该模块将生成输出文本描述。为此,我们可以使用 LSTM,这是一个递归层类型的神经网络。它可以很好地处理任何序列数据,其中它处理序列的每个元素并生成各自的向量表示。更多细节,我会建议这篇和这篇文章。所以如果你看到,我们的描述,也就是文本,遵循连续的顺序,因此非常适合递归型 NN。所以我们需要文本作为输出,因此 LSTM 将图像向量作为输入,并给出向量表示,我们将使用 softmax 函数将其转换为单词。这将使字幕写作模型成为一个分类模型,在每一步中,我们将预测每个单词的概率,并选择具有最高值的一个。这将在所有步骤中重复(LSTM 模型的大小,通常是固定文本描述的大小)。NLP 解码器模块可以被编码为,

NLP 部分的代码(按作者)
理解代码,
- **第 2 行:**由于 LSTM 层需要输入到它的所有步骤,我们将重复图像向量并将其传递到 LSTM 的所有步骤作为输入。这里的步长是
config['max_len'](=39)。 - **第三行:**LSTM 层。
return_sequence为真,因为我们希望返回所有步骤的输出。 - **第 4–5 行:**对于每一步,我们将把向量表示传递给一个密集层,该层充当分类器部分,并挑选一个
config['max_vocab'](=10k)单词。在所有的步骤中这样做,我们将得到我们的标题!
如果你对max_vocab和max_len感到困惑,不要担心,在下一节中它会变得清晰。
数据准备和数据生成器
现在我们已经修复了我们的架构,让我们看看如何处理数据加载并使用它来训练模型。首先要做的是转换文本数据。代码如下所示,

清理、标记和填充标题文本(按作者)
理解代码,
- **第 6 行:**为我们的每个标题添加前缀<开始>和后缀<结束>。这将使我们的递归模块更容易了解标题的边界。
- **第 8–12 行:**我们在这里做了很多事情。总的来说,我们希望将文本从单词序列转换为数字序列,因为数字是神经网络所能理解的。在此之前,我们还(1)删除非字母字符,(2)仅考虑
config['max_vocab'](=10k)唯一的单词,以及(3)将任何其他单词表示为 0。 - **第 14–15 行:**我们想让每个序列(标题用数字符号表示)长度相同,为此我们填充较小的序列来匹配最大的序列
config['max_len'](=39)。这会用 0 填充较小序列的右侧。
预处理完成后,我们就可以创建数据生成器了,它将加载数据并将其传递给模型进行训练。

数据生成器(按作者)
理解代码,
- **第 1 行:**我们的函数接受以下输入,(1)
pick_from_caption_indices:我们可以从中随机采样的标题的索引,(2)batch_size:一次返回的(图像,标题)对的数量,以及(3)reproduce:设置随机种子的标志,以便我们返回相同顺序的(图像,标题)对。 - **第 2 行:**因为这是一个数据生成器,所以函数会不断迭代。因此这里出现了无限循环。另外,请注意第 25 行的
yield使这成为可能。 - **第 8–10 行:**从字幕 CSV 中随机抽取字幕及其相应图像的路径。
- **第 12 行:**我们重复下面的过程,直到(图像,标题)对等于
batch_size(=32)。 - **第 14–16 行:**从驱动器加载图像,并将其调整为(229,229,3)形状。这将确保每个图像的大小相同。此外,我们通过保留所有 3 个通道来保留颜色信息。接下来,我们还将图像像素值归一化到 0 和 1 之间。
- **第 18–19 行:**将序列数据(来自预处理)转换为一键编码,以便进行分类。它接受一个长度为 39 的数字序列,并返回一个大小为(39,10000)的矩阵。这是因为我们的最大词汇大小是 10k,所以对于序列的每一步,我们创建一个 10k 大小的向量,除了该步的数字之外,其他地方都是 0。
- **第 28–29 行:**创建两个数据生成器,一个用于训练,另一个用于测试。注:对于测试,我们有
reproduce=True,因为无论是模型还是试验,我们都希望测试相同的数据。此外,train_indices和test_indices可以通过从标题 CSV 中抽取 80%的索引来轻松创建(更多细节见代码
培训和结果— v1
现在我们已经准备好了模型和数据生成器,让我们来训练模型。在这里,我们所要做的就是定义一些回调函数并编写训练程序。代码如下所示,

培训脚本(作者)
理解代码,
- **第 2–4 行:**检查点回调,保存过去 10 个时期的最佳模型。
- **第 5 行:**提前停止回调,如果我们在 10 个时期内没有看到任何显著的进步,则停止训练。
- **第 8 行:**通过定义优化器和损失函数来编译模型。
- **第 11–16 行:**使用
fit功能训练模型。它接受以下输入,(1)训练数据生成器,(2)要训练的最大时期(这里是 100),(3)每个时期的步骤(这里是 1000),(4)进度详细级别,以及(5)定义的回调。
训练会花一些时间,但是对于支持 GPU 的系统来说,会快很多。对我来说,训练过程在 25 个纪元后停止,损失约为 1.65。这个完整的过程大约需要 2 小时 30 分钟。

v2(按作者)的历元(x 轴)上的训练损失(y 轴)
现在我的期望很低,但我仍然很好奇,想看看结果。退一步说,结果并不太好😅。

v1 的样本测试图像结果(由作者提供)
似乎我们的模型学习的只是一个单一的模式,所有的图像都预测到了同样的模式。这很糟糕,但是你注意到描述总是以一个标记开始吗!至少模型那东西没错。😃
丰富
现在的问题是——为了改善结果,我们接下来应该修改什么,CV 部分还是 NLP 部分?经过一番阅读,我得出了这个结论——为什么不两者都要呢?这是我接下来做的,
- 计算机视觉 — 使用已经在大型图像数据集上训练过的预训练模型。这种将在一项任务中训练的模型用于另一项任务的过程被称为“迁移学习”。这里的主要思想是,预先训练的模型为新任务提供了推动力,因为它已经学会了从图像中提取重要的特征。把这想象成创建一个网络,而不是用随机数初始化权重,我们使用以前工作过的预训练权重。Keras 包在其应用部分提供了几个这样的预训练模型。我们使用“exception”预训练模型,它很小,但具有相当好的准确性。

来自 Keras 应用网站的前 5 个预培训应用。(作者)
- 自然语言处理 — 使用双向 LSTM 被证明可以改善序列数据编码。双向 LSTM(或 biLSTM)基本上是一个堆叠在另一个之上的 LSTM,但有一个扭曲。一个 LSTM 从左到右处理序列,而另一个以相反的方向处理。因此,我们得到了一个方向不可知的嵌入。我会建议这篇文章(自私的自我推销😃),它比较了一个简单分类任务的不同重现图层。
在 Keras 中执行这些修改非常容易,新的模型定义脚本如下所示(适用于 CV 和 NLP)

修改后的型号代码(作者)
理解代码,
- 第 8–16 行:我们加载异常应用程序,并将其附加到模型上。我也使这一层不可训练。最后,我添加了一个 256D 的密集层,以获得最终的翻译图像。
- **第 19–21 行:**一切都和以前一样,除了第 20 行,我在那里添加了双向 LSTM。
培训和结果— v2
训练代码和以前一样。这次模型训练了超过 75 个纪元,用了~7 个小时!损失值也突破了 1 大关。

v2(按作者)的历元(x 轴)上的训练损失(y 轴)
这一次我真的支持这个模型,让我们看看同样的测试图片的标题是什么样子的。

v2 的样本测试图像结果(由作者提供)
这个比上一个好多了!想想我们的模型只有 15 行代码!我认为我们可以在这里停止,至少现在。
下一步是什么?
即使结果很好,也不是完美的。如果你仔细观察,标题不是以符号结束的。此外,虽然字幕的开头很好,但在字幕的过程中,它变得有点没有意义。因此,有很大的改进空间。我有以下想法,我想接下来尝试一下,
- CV: (1)从 Keras 应用列表中尝试更好的预训练模型。(2)使预训练的模型可训练(将增加参数和时间,但是也应该增加精度),(3)在应用层之后添加更多可训练的 FC 层,等等。
- NLP: (1)使用多个 biLSTM 栈,(2)使用 attention 或 transformers 或 BERT
结论
学习是一个持续的过程,只有当你真的生病了,或者像我一样,周末即将结束时,你才应该停下来😅。这篇文章背后的想法不是展示最好的图像字幕解决方案,而是通过人工智能/人工智能解决问题的过程。目的是向读者介绍实验的想法,并推动他们不只是复制解决方案,而是尝试创造自己的解决方案。对我来说也是如此,因为我认为试图在一个系统的流程中处理问题确实有助于人们将问题内在化。
无论如何,我选择了这个问题,因为它是两个不同领域的结合——CV 和 NLP。因此,它有可能帮助我同时应用这两个领域的知识。这就像是一石二鸟。希望这有所帮助!
本文中使用的代码可从这里获得。随意发挥,随意修改。
你可以在 LinkedIn 上和我联系。
干杯。
学你一个凯卓*
编写可复制、可维护和模块化的数据科学代码
拿杯咖啡坐下。这是一个很长的帖子!

https://flic.kr/p/d9KiHk,段丽阳·本田在 Flickr 上的拿铁艺术(CC BY-SA 2.0)
在本文中,我将介绍 Kedro,这是一个开源的 Python 框架,用于创建可复制、可维护和模块化的数据科学代码。在简要描述了它是什么以及为什么它可能成为每个数据科学家工具链的标准部分之后,我描述了一些技术性的 Kedro 概念,并通过一个教程说明了如何使用它们。
总的来说,你应该能够在 30 分钟内阅读并消化这篇文章。但是使用 Kedro 的好处将会持续你的职业生涯。
假设你是一名数据科学家,为一名为公司做出关键财务决策的高管工作。她请你提供一个特别的分析,当你这样做时,她感谢你为她的计划提供了有用的见解。太好了!
三个月后,新晋升的主管,现在是你的首席执行官,要求你在下一次计划会议上重新运行分析…而你不能。代码被破坏是因为您覆盖了文件的一些关键部分,并且您不记得当时使用的确切环境。或者,代码可能是好的,但它在一个大的 Jupyter 笔记本中,所有文件路径都是硬编码的,这意味着您必须费力地检查和更改每一个新数据输入。哎呀!那不太好!
它发生了。可能比应该的更频繁。当它发生时,通常的说法是最初的项目没有被规划到一个高标准,因为它不是为生产系统设计的。
但是……任何支持业务决策过程的代码都应该被认为是生产代码!
当然,如果你是一名数据科学家,你可能不认为你工作的主要产出是代码。但是你的项目仍然使用代码,为什么不利用软件工程师来之不易的经验呢?希望您的项目至少具备以下特征:
- 它应该被版本化——使用 git 或类似的工具定期保存您的更改,无论您是独自工作还是在团队中工作。
- 它应该是可复制的——你应该能够将一个项目转移到另一台计算机上,然后毫不费力地运行它。
- 它应该遵循标准——坚持通用的项目结构、标准的编码约定和工具,以便未来的协作和更好的团队合作。
- 它应该被记录 —使用自动化文档来保持你的文档与你的代码保持同步。
- 它应该是模块化的——代码可以很容易地执行和测试。
关于这些原则的更多细节,请看 Thomas Huijskens 的一篇有用的博客文章。
介绍 Kedro
Kedro 帮助您创建可复制、可维护和模块化的数据科学代码。它从软件工程中借用概念,并将它们应用到机器学习代码中;应用的概念包括模块化、关注点分离和版本控制。
Kedro 概念
首先,让我们用一个传统的“Hello World”例子来研究 Kedro 的最基本的元素,这个例子被分成几个部分。你可以在 Kedro 词汇表中找到更多关于这些概念的信息。
节点
节点是 Python 函数的包装器,用于命名该函数的输入和输出。节点是管道的构建块,您可以链接它们,这样一个节点的输出就是另一个节点的输入。
这里,一个名为return_greeting_node的节点没有输入,只有一个输出(my_salutation)。它封装了函数(return_greeting):
*# Prepare first node
def return_greeting():
return “Hello”return_greeting_node = node(func=return_greeting, inputs=None, outputs=”my_salutation”)*
这里,名为join_statements_node的第二个节点命名为单输入(my_salutation)和单输出(my_message)。它封装了函数(join_statements):
*# Prepare second node
def join_statements(greeting):
return f”{greeting} Kedro!”join_statements_node = node(join_statements, inputs=”my_salutation”, outputs=”my_message”)*
注意my_salutation是return_greeting_node的 输出 ,也是join_statements_node的 输入 。
管道
Kedro 管道组织了一组节点的依赖关系和执行顺序。在这个例子中,流水线在执行join_statements_node之前执行return_greeting_node:
*# Assemble nodes into a pipeline
pipeline = Pipeline([return_greeting_node, join_statements_node])*
数据目录
Kedro DataCatalog是项目可以使用的所有数据源的注册表。它将节点输入和输出的名称映射为一个DataSet中的键,这是一个 Kedro 类,可以专门用于不同类型的数据存储。Kedro 为简单存储在内存中的数据使用了一个MemoryDataSet,它还为不同的文件类型和文件系统提供了不同的内置数据集,因此您不必编写读/写数据的逻辑:
*# Prepare a data catalog
data_catalog = DataCatalog({“my_salutation”: MemoryDataSet()})*
转轮
Runner 是运行管道的对象。Kedro 解析执行节点的顺序:
- Kedro 首先执行
return_greeting_node。这将运行return_greeting,它不接受任何输入,但输出字符串“Hello”。 - Kedro 将输出字符串存储在名为
my_salutation的MemoryDataSet中。 - Kedro 然后执行第二个节点
join_statements_node。这会加载my_salutation数据集并将其注入到join_statements函数中。 - 该函数用“Kedro!”加入输入的问候语以形成输出字符串“Hello Kedro!”
- Kedro 在字典中返回管道的输出,关键字为
my_message。
你好,凯卓!
现在是时候把所有东西缝合在一起了。以下是完整的示例:
如果您将这个示例放入一个文件,例如hello_kedro.py,并在终端(python hello_kedro.py)中运行它,您应该看到{‘my_message’: ‘Hello Kedro!’}被打印到控制台。
开始吧!
现在你对这些概念有了一个基本的理解,为什么不安装 Kedro 并试用一下呢?大多数人从 Kedro spaceflights 教程开始,你可以在文档中找到,但为了简化它,我在下面创建了一个简短的版本。
参考 Kedro 文档中的安装先决条件。准备好之后,运行以下命令从 Python 包索引(PyPI)安装:pip install kedro
检查是否安装了 Kedro:kedro info
您应该会看到一个 ASCII 艺术图形和 Kedro 版本号。

如果您没有看到显示的图形,或者您的安装有任何问题,请参见常见问题或 Kedro 社区对 Discord 的支持。更多信息,请查看关于安装 Kedro 的文档。
Kedro spaceflights 教程
在本教程中,您将通过一个示例了解 Kedro 项目开发工作流的每个步骤,该示例为以下价格预测场景构建节点和管道:
现在是 2160 年,太空旅游业正在蓬勃发展。在全球范围内,有数千家航天飞机公司将游客送上月球并返回。你已经能够找到每架航天飞机提供的便利设施、顾客评论和公司信息。
您想要构建一个模型来预测每次登月旅行以及相应的返程航班的价格。
Y 您将需要大约 20 分钟来完成本教程,它使用 Kedro starter 为您创建 spaceflights 项目,然后遍历最重要的代码部分,将它们与您在上面学到的概念联系起来。
设置项目
我们假设您已经安装了 Kedro,如上所述。首先,使用Kedro starter for the space flights 教程 : kedro new --starter=spaceflights在您喜欢的工作目录中创建您的项目
当您使用它时,您将拥有一个完整的工作项目,所有的代码和数据都已设置好并准备好运行。
你可以随意命名你的项目,但是这里我们假设它叫做 Kedro 教程。
出现提示时,保留 repo_name ( kedro-tutorial)和 python_package ( kedro_tutorial)的默认名称。
接下来,使用 Kedro 安装特定于项目的依赖项。导航到项目的根目录并运行:kedro install
Kedro 管理您的项目的依赖项,使其他人更容易运行该项目。它避免了版本冲突:Kedro 确保你们都使用相同的 Python 包和版本。你可以在 Kedro 文档中找到更多关于如何处理项目依赖关系的信息。
此时,您可以运行项目,看看会发生什么。因此,如果您想向前跳,请向下滚动到“测试管道”部分。
设置数据
spaceflights 教程使用了公司的虚拟数据集,将客户往返于月球。您将使用这些数据训练一个模型来预测班车租赁的价格。但是,在开始训练模型之前,您需要为模型构建准备数据。
航天教程有三个文件,使用两种数据格式:.csv和.xlsx。你会在你的项目目录的data/01_raw/文件夹中找到原始数据:
[reviews.csv](https://quantumblacklabs.github.io/kedro/reviews.csv)[companies.csv](https://quantumblacklabs.github.io/kedro/companies.csv)[shuttles.xlsx](https://quantumblacklabs.github.io/kedro/shuttles.xlsx)
数据集需要注册,以便 Kedro 可以加载它们。所有 Kedro 项目都有一个conf/base/catalog.yml文件,在示例中,您将看到 starter 在该文件中添加的每个数据集:
- 文件位置(路径)
- 给定数据集的参数
- 数据类型
- 版本控制
对于csv数据集:
*companies:
type: pandas.CSVDataSet
filepath: data/01_raw/companies.csvreviews:
type: pandas.CSVDataSet
filepath: data/01_raw/reviews.csv*
对于 xlsx 数据集:
*shuttles:
type: pandas.ExcelDataSet
filepath: data/01_raw/shuttles.xlsx*
要确认 Kedro 可以正确加载数据,请打开一个 Kedro iPython 会话(kedro ipython)并运行以下命令:
*companies = catalog.load(“companies”)
companies.head()
shuttles = catalog.load(“shuttles”)
shuttles.head()*
该命令加载每个数据集。pandas 的 head 方法显示数据帧的前五行。
完成后,关闭 iPython 会话:exit()
接下来,我们将为项目设置两条模块化管道:
data_processing_pipeline预处理数据data_science_pipeline创建特征,训练和评估模型。
数据处理模块流水线
让我们看一下用于预处理三个输入数据集以创建主表并为建模准备数据的示例节点。
在src/kedro_tutorial/pipelines/data_processing/nodes.py中,您将看到两个函数:(preprocess_companies和preprocess_shuttles),每个函数输入一个原始数据帧并输出一个包含预处理数据的数据帧:
您将在src/kedro_tutorial/pipelines/data_processing/pipeline.py内的create_pipeline()中找到两种功能的节点,以及用于数据处理的模块化管道:
注:公司和班车指的是conf/base/catalog.yml中定义的数据集。这些是preprocess_companies和preprocess_shuttles功能的输入。Kedro 管道使用命名的节点输入(和输出)来确定节点之间的相互依赖关系,从而确定它们的执行顺序。
每个节点输出一个新的数据集(preprocessed_companies和preprocessed_shuttles)。Kedro 的DataCatalog将自动保存数据集(在本例中为csv数据)。
在上面的管道中,您将看到另一个节点create_master_table(),它在src/kedro_tutorial/pipelines/data_processing/nodes.py中将三个数据帧连接成一个主表:
Kedro 使用从数据集preprocessed_shuttles、preprocessed_companies和reviews加载的数据调用create_master_table(),并将输出保存到dataset master_table。
面向数据科学的模块化管道
现在让我们看看用于价格预测的数据科学管道,它使用来自 scikit-learn 库的 LinearRegression 实现。
您将在src/kedro_tutorial/pipelines/data_science/nodes.py中看到三个数据科学功能:
输入参数在配置文件conf/base/parameters.yml中:
*test_size: 0.2
random_state: 3
features:
- engines
- passenger_capacity
- crew
- d_check_complete
- moon_clearance_complete
- iata_approved
- company_rating
- review_scores_rating*
这些是管道执行时输入到DataCatalog的参数。参数test_size和random_state被用作训练测试分割的一部分,而 features 给出了主表中用作特性的列的名称。
训练好的模型被保存为数据集(见conf/base/catalog.yml):
*regressor:
type: pickle.PickleDataSet
filepath: data/06_models/regressor.pickle
versioned: true*
数据科学的模块化管道在src/kedro_tutorial/pipelines/data_science/pipeline.py中创建:
合并管道
数据处理和数据科学管道被添加到register_pipelines within src/kedro_tutorial/pipeline_registry的项目中:
在“__default__”: data_processing_pipeline + data_science_pipeline中使用的__default__ key将两个模块化管道合并成一个项目默认管道。
**注意:将管道添加在一起的顺序并不重要,并且data_science_pipeline + data_processing_pipeline将产生相同的管道,因为 Kedro 自动检测结果管道中所有节点的正确执行顺序。
测试管道
运行管道:kedro run
您应该会看到类似下面的输出(可能会有一些警告):

总结
在本教程中,我们展示了一个标准的 Kedro 开发工作流程:
1。 项目模板
我们用 kedro new 创建了一个新项目,用kedro install安装了项目依赖项(完整教程也谈到了配置)
2。 数据
我们将数据添加到data/文件夹,并在conf/base/catalog.yml中引用项目的输入数据集
3。 管道
我们将数据转换步骤创建为 Python 函数(节点),构建模块化管道并将它们合并到一个项目管道中。为了简洁起见,我们没有介绍如何可视化你的管道。
哇,那是一些长的教程!
抱歉,是的,就是它!在 Kedro 文档中有更多的细节,如果你想更深入地了解正在发生的事情,或者如果你在运行这个例子时有任何问题,你会发现它很有用:
承认
Spaceflights 的例子是基于 2019 年 QuantumBlack Labs 的 Kedro 团队编写的教程。没有他们我什么都做不了。非常感谢 QB 实验室的 Yetunde Dada 、 Ivan Danov 、 Dmitrii Deriabin 、 Lorena Balan 、 Kiyohito Kunii 、 Merel Theisen 以及其他加入团队的人。
边做边学—成为高效的数据科学家
我听见了,我忘记了。我看见了,我记得。我知道,我也理解。

课程是学习的好方法,但是参与项目可以提高你的技能。你将被迫对这个问题进行批判性的思考,并自己提出解决方案。实践积累了无法教授的知识和技能,因为看着别人做比自己学着做要容易得多。
我喜欢保罗·格拉厄姆在的文章中的描述:
想到所有的高中生都放弃建造树屋,坐在课堂上尽职尽责地学习达尔文或牛顿以通过考试,这有点令人难过,而让达尔文和牛顿出名的工作实际上在精神上更接近于建造树屋,而不是为考试而学习。
个人项目允许你在更深的层次上探索和应用你所学到的东西。从头到尾做一个项目会让你面临各种各样的问题。你将知道如何提出正确的问题,特别是如何搜索正确的问题来找到解决方案。我们想获得更多的实践经验来磨练我们的技能。
高效数据科学家
边做边学通过端到端的方式让您成为一名高效的数据科学家,知道如何从项目的开始(识别问题)到结束(解决问题并提供价值)进行工作。他们能用数据识别和解决问题,为公司提供价值;这提高了你产生有意义影响的能力。
以下是成为有效的端到端数据科学家的技能列表(既不是强制性的,也不是详尽的):
- 范围 —定义问题,确定成功标准
- 沟通 —促进团队合作,获得认同,分享成果
- 数据工程 —获取、清理和准备数据,建立数据管道
- 数据分析 —理解数据,衡量绩效
- 构建产品 —无论是应用机器学习来执行预测还是数据分析来提取答案
- 开发运营 —代码结构、单元测试、自动化工具、部署
例如,让我们构建一个项目,它提取历史股票数据,并使用机器学习模型来预测第二天的价格(范围)。我们发现我们可以从 Alpha Vantage 获取金融市场数据,因此我们构建了一个脚本来提取股票数据(数据工程)。有了原始数据,我们在训练模型之前准备数据,归一化原始数据,并将数据拆分成训练和验证数据集(数据分析+数据工程)。然后,我们开发并训练一个简单的 LSTM 模型,学习使用过去 50 天的数据预测第二天的价格(构建产品)。为了确定我们的模型是否做得很好,我们通过用均方差(数据分析)测量来评估模型的性能。我们建立一个网络界面,然后部署它来展示这项工作,这样任何人都可以尝试(开发-运营)。最后,写下关于建筑和思想的过程,这样其他人可以从中学习来建造他们自己的(沟通)。
建立你的投资组合
拥有个人项目还能让你建立一个投资组合,并向潜在雇主展示。在线作品集向招聘经理展示了技术和软技能。
技术技能——你如何组织你的文件和代码,你如何获取和准备数据,你如何通过视觉分析和理解你的数据,你如何训练和评估你的机器学习模型。这向他们表明你能把事情做好。
软技能 —写下你的思维过程,解释分析和结果,显示你的沟通能力,这对于一个高效的数据科学家来说是必不可少的。
特质——从事个人项目表现出除了完成课程和领取证书之外的自学能力。拥有投资组合也展示了好奇心和激情等特质。当你利用空闲时间学习时,这表明你比其他可能参加同一份工作面试的人更有动力和激情。你要表明你是自愿做这件事的(拉),而不是仅仅因为有人告诉你这样做(被推)。
作品集有助于你的简历在简历的海洋中脱颖而出,获得第一轮面试。你从这些项目中获得的技能和特质将引导你胜任这个角色。
它对我有什么作用?
2017 年,我在阿里巴巴集团面试了一个数据科学家的角色。像大多数面试一样,我的招聘经理开始问了我几个机器学习问题。气氛很严肃,问题一个接一个。
然后,我们继续描述我以前做过什么。我分享了一个我制作的自然语言处理应用程序,用户可以上传一个包含调查问题答案的 Excel 文件。该应用程序将提取每个响应的情绪,并根据主题对它们进行动态分组。我向我的招聘经理展示了该应用程序的外观,以及从用户角度看它是如何工作的。
在分享了它的易用性以及它如何让用户受益之后,他的态度和采访氛围都变了。这不再像是一次采访,而更像是与朋友分享我做了什么,我是如何做的,以及它如何极大地帮助了用户。描述以前做过的事情比重述每个数据科学和机器学习概念要容易得多。谈话变得更加活跃和友好;这是一次愉快的面试经历。是的,我得到了这份工作。
在收盘时……
当决定做一个个人项目时,最困难的事情之一就是找时间开始。因为我们大多数人都有一份全职工作(或学习),剩下的空闲时间都可以用来看《网飞》。但是你从个人项目中获得的学习和成长是金子。
不要专注于建立投资组合;关注通过实践获得技能的过程。投资组合是我们学习的成果,是我们发展的技能,是我们拥有的特质。在试图建立我们的投资组合时,我们应该找到本质上有回报的项目。它们应该是有趣的,有个人意义的,并能拓展我们的能力;这使得它们更具可持续性。随着时间的推移,一个接一个的项目,你会有一个投资组合。
我听见了,我忘记了。我看见了,我记得。我知道,我也理解。
读也:
https://eugeneyan.com/writing/data-science-portfolio-how-why-what/
通过实现来理解:高斯朴素贝叶斯
建立你自己的模型
了解高斯朴素贝叶斯的工作原理,并在 Python 中实现它

高斯朴素贝叶斯分类器的决策区域。图片由作者提供。
我认为这是每个数据科学职业生涯开始时的经典之作:朴素贝叶斯分类器。或者我应该说是朴素贝叶斯分类器的家族,因为它们有很多种风格。例如,有一个多项式朴素贝叶斯,一个伯努利朴素贝叶斯,还有一个高斯朴素贝叶斯分类器,每个分类器只有一个小细节不同,我们会发现。朴素贝叶斯算法在设计上非常简单,但在许多复杂的现实情况中证明是有用的。
在本文中,您可以了解到
- 朴素贝叶斯分类器如何工作,
- 为什么以他们的方式定义他们是有意义的
- 如何使用 NumPy 在 Python 中实现它们。
你可以在 my Github 上找到代码。
检查一下我的贝叶斯统计初级读本可能会有所帮助,这是对贝叶斯推理的温和介绍以习惯贝叶斯公式。因为我们将以 scikit learn-conform 的方式实现分类器,所以也值得看看我的文章构建您自己的定制 scikit-learn 回归。然而,scikit-learn 的开销很小,无论如何您都应该能够跟上。
我们将开始探索朴素贝叶斯分类的惊人简单的理论,然后转向实现。
该理论
分类时我们真正感兴趣的是什么?我们实际上在做什么,输入和输出是什么?答案很简单:
给定一个数据点 x,x 属于某类 c 的概率是多少?
这就是我们想要用任何分类来回答的所有问题。你可以直接把这个语句建模成条件概率:p(c|x)。
例如,如果有
- 3 班 c ₁、 c ₂、 c ₃,以及
- x 由两个特征组成 x ₁, x ₂,
分类器的结果可能类似于 p ( c ₁| x ₁, x ₂)=0.3,
p(c₂|x₁, x ₂)=0.5 和p(c₃|x₁,x如果我们关心单个标签作为输出,我们将选择概率最高的一个,即 c ₂,这里概率为 50%。**
朴素贝叶斯分类器试图直接计算这些概率。
朴素贝叶斯
好,那么给定一个数据点 x ,我们要计算所有类 c 的p(c|x),然后输出概率最高的 c 。在公式中,您通常会看到这种情况

图片由作者提供。
**注:**maxp(c|x)返回最大概率,arg maxp(c|x)返回概率最大的 c 。
但是在我们能够优化p(c|x)之前,我们必须能够计算它。为此,我们使用贝叶斯定理:

贝叶斯定理。图片由作者提供。
这是朴素贝叶斯的贝叶斯部分。但是现在,我们有了以下问题:什么是p(x|c)和 p ( c )?
这就是朴素贝叶斯分类器的训练。
培训
为了说明一切,下面让我们用一个有两个真实特征 x ₁、 x ₂、三个类 c ₁、 c ₂、 c ₃的玩具数据集。

可视化的数据。图片由作者提供。
您可以通过以下方式创建精确的数据集
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=20, centers=[(0,0), (5,5), (-5, 5)], random_state=0)
让我们从类概率 p ( c )开始,在标记的数据集中观察到某个类 c 的概率。估计这一点的最简单的方法是只计算类的相对频率,并使用它们作为概率。我们可以用我们的数据集来看看这到底意味着什么。
在数据集中,20 个点中有 7 个被标记为类别 c ₁(蓝色),因此我们称之为p(c₁)=7/20.我们也有 7 点给职业 c ₂(红色),因此我们设定p(c₂)=7/20.最后一班 c ₃(黄)只有 6 分,于是p(c₃)=6/20.
这种简单的类别概率计算类似于最大似然法。但是,如果您愿意,也可以使用另一个previous分布。例如,如果您知道这个数据集不代表真实的总体,因为类 c ₃应该出现在 50%的情况下,那么您设置 p ( c ₁)=0.25, p ( c ₂)=0.25 和 p ( c ₃)=0.5.任何有助于提高测试集性能的东西。
我们现在转向可能性p(x|c)=p(x₁, x ₂| c )。计算这种可能性的一种方法是过滤标签为 c 的样本的数据集,然后尝试找到捕获特征 x ₁、 x ₂.的分布(例如,二维高斯分布)
不幸的是,通常情况下,我们没有足够的样本对每一类进行适当的可能性估计。
为了能够建立一个更健壮的模型,我们做了一个天真的假设假设特征 x ₁, x ₂是随机独立的,给定 c 。这只是通过一种奇特的方式使数学变得简单

图片由作者提供。
为每一类c。这就是朴素贝叶斯的朴素部分的来源,因为这个等式一般不成立。尽管如此,即便如此,朴素贝叶斯理论在实践中也能产生良好的、有时是杰出的结果。特别是对于具有词袋特征的 NLP 问题,多项式朴素贝叶斯大放异彩。
上面给出的参数对于你能找到的任何朴素贝叶斯分类器都是一样的。现在就看你怎么造型了p(x₁|c₁】,p(x₂|c₁】,p(x₁|c₂】,p()
如果你的特征只有 0 和 1,你可以使用一个伯努利分布。如果它们是整数,一个多项式分布。然而,我们有真实的特征值,并决定为一个高斯分布,因此得名高斯朴素贝叶斯。我们假设以下形式

图片由作者提供。
其中, μᵢ,ⱼ 是平均值, σᵢ,ⱼ 是我们必须从数据中估计的标准偏差。这意味着我们为每个特征得到一个平均值 i 和一个类 c ⱼ *,在我们的例子中是 23=6 个平均值。标准差也是如此。这需要一个例子。
让我们试着估计一下₂,₁和 ₂,₁.因为 j =1,我们只对类别 c ₁感兴趣,让我们只保留带有这个标签的样品。以下样本仍然存在:
# samples with label = c_1
array([[ 0.14404357, 1.45427351],
[ 0.97873798, 2.2408932 ],
[ 1.86755799, -0.97727788],
[ 1.76405235, 0.40015721],
[ 0.76103773, 0.12167502],
[-0.10321885, 0.4105985 ],
[ 0.95008842, -0.15135721]])
现在,因为 i =2,我们只需要考虑第二列。 μ ₂,₁是该列的平均值, σ ₂,₁是该列的标准差,即 μ ₂,₁ = 0.49985176, σ ₂,₁ = 0.9789976。
如果你再次从上面看散点图,这些数字是有意义的。从图片中可以看到,₁c级样品的特征 x ₂在 0.5 左右。
我们现在为其他五个组合计算这个,我们完成了!😃
在 Python 中,可以这样做:
from sklearn.datasets import make_blobs
import numpy as np
# Create the data. The classes are c_1=0, c_2=1 and c_3=2.
X, y = make_blobs(n_samples=20, centers=[(0,0), (5,5), (-5, 5)], random_state=0)
# The class probabilities.
# np.bincounts counts the occurence of each label.
prior = np.bincount(y) / len(y)
# np.where(y==i) returns all indices where the y==i.
# This is the filtering step.
means = np.array([X[np.where(y==i)].mean(axis=0) for i in range(3)])
stds = np.array([X[np.where(y==i)].std(axis=0) for i in range(3)])
我们收到
# priors
array([0.35, 0.35, 0.3 ])# means
array([[ 0.90889988, 0.49985176],
[ 5.4111385 , 4.6491892 ],
[-4.7841679 , 5.15385848]])# stds
array([[0.6853714 , 0.9789976 ],
[1.40218915, 0.67078568],
[0.88192625, 1.12879666]])
这是高斯朴素贝叶斯分类器的训练结果。
做预测
完整的预测公式是

图片由作者提供。
让我们假设一个新的数据点 x=* (-2,5)进来。

图片由作者提供。
为了查看它属于哪个类,让我们计算所有类的p(c|*x **)。从图片上看,它应该属于类 c ₃ = 2,但让我们看看。让我们暂且忽略分母 p ( x )。使用以下循环计算出 j = 1,2,3 的命名数。
x_new = np.array([-2, 5])
for j in range(3):
print(f'Probability for class {j}: {(1/np.sqrt(2*np.pi*stds[j]**2)*np.exp(-0.5*((x_new-means[j])/stds[j])**2)).prod()*p[j]:.12f}')
我们收到
Probability for class 0: 0.000000000263
Probability for class 1: 0.000000044359
Probability for class 2: 0.000325643718
当然,这些概率(我们不应该这样称呼它们)并不等于 1,因为我们忽略了分母。然而,这没什么问题,因为我们可以把这些未标准化的概率除以它们的和,然后它们会加起来等于 1。因此,将这三个值除以它们的总和约为 0.00032569,我们得到

图片由作者提供。
正如我们所预料的,一个明显的赢家。现在,让我们实施它吧!
完整的实现
这种实现方式效率很低,在数值上也不稳定,它只用于教育目的。我们已经讨论了大部分事情,所以现在应该很容易理解了。你可以忽略所有的check函数,或者阅读我的文章构建你自己的定制 scikit-learn ,如果你对它们到底做什么感兴趣的话。
请注意,我首先实现了一个predict_proba方法来计算概率。方法predict只是调用这个方法,并使用 argmax 函数返回概率最高的索引(=类)(又来了!).该类等待从 0 到 k -1 的类,其中 k 是类的数量。
import numpy as np
from sklearn.base import BaseEstimator, ClassifierMixin
from sklearn.utils.validation import check_X_y, check_array, check_is_fitted
class GaussianNaiveBayesClassifier(BaseEstimator, ClassifierMixin):
def fit(self, X, y):
X, y = check_X_y(X, y)
self.priors_ = np.bincount(y) / len(y)
self.n_classes_ = np.max(y) + 1
self.means_ = np.array([X[np.where(y==i)].mean(axis=0) for i in range(self.n_classes_)])
self.stds_ = np.array([X[np.where(y==i)].std(axis=0) for i in range(self.n_classes_)])
return self
def predict_proba(self, X):
check_is_fitted(self)
X = check_array(X)
res = []
for i in range(len(X)):
probas = []
for j in range(self.n_classes_):
probas.append((1/np.sqrt(2*np.pi*self.stds_[j]**2)*np.exp(-0.5*((X[i]-self.means_[j])/self.stds_[j])**2)).prod()*self.priors_[j])
probas = np.array(probas)
res.append(probas / probas.sum())
return np.array(res)
def predict(self, X):
check_is_fitted(self)
X = check_array(X)
res = self.predict_proba(X)
return res.argmax(axis=1)
测试实现
虽然代码很短,但仍然太长,无法完全确定我们没有犯任何错误。因此,让我们检查一下它与 scikit-learn GaussianNB 分类器的对比情况。
my_gauss = GaussianNaiveBayesClassifier()
my_gauss.fit(X, y)
my_gauss.predict_proba([[-2, 5], [0,0], [6, -0.3]])
输出
array([[8.06313823e-07, 1.36201957e-04, 9.99862992e-01],
[1.00000000e+00, 4.23258691e-14, 1.92051255e-11],
[4.30879705e-01, 5.69120295e-01, 9.66618838e-27]])
使用predict方法的预测是
# my_gauss.predict([[-2, 5], [0,0], [6, -0.3]])
array([2, 0, 1])
现在,让我们使用 scikit-learn。扔进一些代码
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
gnb.fit(X, y)
gnb.predict_proba([[-2, 5], [0,0], [6, -0.3]])
生产
array([[8.06314158e-07, 1.36201959e-04, 9.99862992e-01],
[1.00000000e+00, 4.23259111e-14, 1.92051343e-11],
[4.30879698e-01, 5.69120302e-01, 9.66619630e-27]])
这些数字看起来有点类似于我们的分类器,但它们在最后几个显示的数字中有点偏离。我们做错什么了吗?否sci kit-learn 版本只是使用了另一个超参数var_smoothing=1e-09。如果我们把这个设为 0,我们就能得到准确的数字。完美!
看看我们的分类器的决策区域。我还标记了我们用于测试的三个点。靠近边界的那个点只有 56.9%的机会属于红色类,正如您从predict_proba输出中看到的。另外两点被归类为具有高得多的置信度。

具有 3 个新点的决策区域。图片由作者提供。
结论
在本文中,我们已经了解了高斯朴素贝叶斯分类器的工作原理,并直观地解释了为什么要这样设计——这是一种对感兴趣的概率进行建模的直接方法。与逻辑回归比较:在逻辑回归中,概率是用一个线性函数来模拟的,在这个线性函数上应用了一个 sigmoid 函数。这仍然是一个简单的模型,但感觉不如朴素贝叶斯分类器自然。
我们继续计算了一些例子,并收集了一些有用的代码。最后,我们实现了一个完整的高斯朴素贝叶斯分类器,它与 scikit-learn 配合得很好。例如,这意味着您可以在管道或网格搜索中使用它。
最后,我们通过导入 scikit-learn 自己的高斯朴素贝叶斯分类器进行了一个小的健全性检查,并测试我们和 scikit-learn 的分类器是否产生相同的结果。这次测试是成功的。😎
我希望你今天学到了新的、有趣的、有用的东西。感谢阅读!
作为最后一点,如果你
- 想支持我多写点机器学习和
- 无论如何,计划获得一个中等订阅,
为什么不做 通过这个环节 ?这将对我帮助很大!😊
说白了,给你的价格不变,但大约一半的订阅费直接归我。
非常感谢,如果你考虑支持我的话!
有问题就在LinkedIn上写我!
学习曲线图第 1 部分:对抗数据需求诅咒
为你的下一个 ML 项目避免基于试错的数据集大小估计。

克里斯·利维拉尼在 Unsplash 上的照片
广义地说,大多数机器学习算法属于两类之一:线性模型或非线性模型。线性模型易于解释,训练和部署速度更快,并且不需要过多的计算资源。线性模型学习并产生输入的加权和,加上偏差(截距)项,从而将单个输入特征 X 映射到单个目标 f(X)。

作者图片
线性与非线性
然而,现实世界的挑战是复杂的,很少有线性的投入产出关系。因此,虽然线性模型简单且易于实现和集成,但它们通常无法充分模拟真实世界的系统。因此,这一缺点要求我们将注意力转向非线性模型。虽然许多非线性机器学习模型用于解决复杂的现实世界问题,但神经网络及其变体在广泛的应用中解决现实世界问题的能力越来越强,并迅速受到欢迎。神经网络(包含非线性激活函数)更具表现力,可以学习数据中的复杂模式和相关性,并且可以比线性模型更好地进行概括,但神经网络的这种高鲁棒性和高性能,像其他非线性模型一样,也有一个代价:数据需求诅咒。
大多数算法,尤其是神经网络及其变体,被设计成对它们被训练的数据集的底层分布进行建模。这些算法有数百万个可训练的参数,一旦学习,将识别训练数据集中的模式和趋势。不管训练数据集本身有多大,它仍然只是所有可能实例的子集——总体。随着总体复杂性和/或算法复杂性的增加,我们需要越来越多的数据点来可靠地估计潜在的分布。考虑两个例子:1 .一个模型被训练来区分生产装配线上的彩色盒子,比如红色、绿色和蓝色盒子。模型被训练来区分人体中的组织以辅助手术。我们可以做出一个有根据的猜测,第二种情况与第一种情况相比,需要更多的数据点来可靠地估计潜在的分布,这仅仅是因为数据中可能的变化和波动。一个小的数据集对于潜在的趋势可能是误导性的或者不具有代表性的。
数据集大小
由于研究社区和对机器学习解决方案日益增长的兴趣,我们看到了高质量基准数据集的数量、数据质量和注释质量的显著增长,但这些基准数据集中的数据点数量从几千到数百万个数据点不等。此外,随着迁移学习和数据扩充等强大技术的引入,对巨大数据集的需求正在下降。然而,问题仍然存在:我们需要多少数据来训练一个健壮的机器学习解决方案?
你可能会出于多种原因问自己这个问题:
- 数据收集:你可能还没有收集数据,需要知道收集足够的数据来训练一个高性能的 ML 模型所需的价格和时间。
- 数据扩充:您可能已经收集了一些数据,并且需要知道需要扩充多少数据集。
- 历史数据:您可能已经有了一个大型数据集,并且需要知道最佳的数据集大小,以减少您的计算和存储成本。
- 迁移学习:你可能已经有了一个训练好的模型,并且想把这个模型应用到一个“类似的”问题上,只需要尽可能少的再训练。
在所有这四种情况下,知道所需的数据集大小成为一个瓶颈。从一个问题到下一个问题,所需的数据集大小是变化的,并且与问题的复杂性和所选择的训练算法相关。坏消息是,目前没有办法 100%准确地确定这一点。真实世界的数据有很多噪音和变化,这使得很难完美地对训练数据集进行采样。除此之外,环境的变化、数据收集传感器的波动、日志记录错误、数据损坏和存储错误,都使得了解确切的所需数据集大小变得不可能。这是否意味着我们应该继续增加数据集的大小,希望它能提高模型的性能和健壮性?幸运的是,有更聪明、更简单的方法来处理这个瓶颈。一种这样的方法是使用学习曲线图。
学习曲线图
粗略定义的学习曲线图是相对于受控参数的模型性能随经验或时间的曲线图。学习曲线图通常被用作诊断工具,以评估模型在受控参数变化时的增量性能。学习曲线图的应用非常广泛,因为它们也可以用来估计所需的数据集大小。在这种情况下,受控参数将是数据集大小。下图显示了在这样的学习曲线图中,你通常可以期望看到什么。

作者图片
模型性能
ML 模型的性能最初通常会随着数据集的大小而增加。换句话说,随着数据集大小的增加,模型会学习并更新其对潜在趋势的估计。在某些时候,模型的性能会达到饱和,添加更多的数据并不会导致性能的显著提高。当模型性能饱和时,我们可以潜在地假设普通人群和训练数据集现在具有非常相似的基础分布。因此,进一步计算和存储的成本回报递减。我们的目标是使用学习曲线图和插值技术来估计目标性能值所需的数据集大小,或者找到最大性能的饱和点。在第 2 部分中,我们将看到这种方法在 MNIST 时装数据集和学习曲线图实验中的应用。
学习曲线图第二部分:实验
在第 1 部分中,我们讨论了非线性机器学习模型的数据需求诅咒。我们看到,我们可以使用学习曲线图来估计目标性能的数据集大小。在第 2 部分中,我们将使用一个基准数据集来设计这个实验:Fashion-MNIST。时尚-MNIST 数据集包含来自 10 个班级的 60,000 幅时尚和服装项目的训练图像(和 10,000 幅测试图像)。每个图像都是标准化的灰度图像,28×28 像素(总共 784 个像素)。这是一个比 MNIST 数字更具挑战性的分类问题,顶级结果是通过深度学习卷积神经网络实现的,在测试数据集上的分类精度约为 90%至 95%。每个训练和测试示例都被分配到以下标签之一:

作者图片
下图显示了我们将在实验中使用的时尚 MNIST 数据点的一些例子。

作者图片
我们的目标是看看我们是否可以复制一个图表来验证我们的学习曲线假设,并估计可接受的模型性能所需的最小数据集大小(尽可能接近最高结果)。
投入到实验中
我们将使用 Google Colab (python 3)来设计我们的实验,并使用 keras API 来访问时尚-MNIST 数据集并定义我们的 CNN 架构。首先,让我们看看这个实验需要的导入。

作者图片
我们使用 matplotlib 库来满足我们的显示需求,使用 keras 来访问时尚 MNIST 数据集和创建我们的 CNN 架构。接下来,让我们定义 3 个函数调用,使我们的代码模块化,让我们的生活更轻松。
- 准备用于训练和评估的数据集:

作者图片
首先,我们改变数据点的形状,使它们具有单一的颜色通道,然后我们将标签转换为用于训练的一键编码。最后,数据集中的每个像素的值都在 0-255 之间。我们需要将这些值从无符号 int 转换成 float32,并将这些值规范化为 0–1。
2 。创建 CNN 架构:

作者图片
在这个实验中,我们将使用一个非常简单的序列模型。该模型将具有 32 个 3×3 卷积滤波器,具有 RELU 激活。卷积图层之后是 2x2 maxpooling 图层,其输出将被展平以提供分类器的要素。然后,我们将使用具有 100 个节点的密集层来解释特征。最后,我们将使用另一个具有 10 个节点的密集层来表示 10 个类,并将 softmax 激活作为分类器。
所有层将使用权重初始化方案来播种权重。我们将使用保守学习率为 0.01、动量为 0.9 的随机梯度下降作为优化器,类别交叉熵作为损失函数。请记住,所有这些参数都是可配置的,并且为了有一个好的模型,首先需要这些参数。像自动驾驶和语音识别这样更复杂的问题将需要非常复杂的模型,但因为我们的问题陈述相对简单,所以我们使用的是相对简单的网络。
3.训练并评估模型:

作者图片
我们的最后一个功能将训练和评估模型。这一步是旅程中最重要的部分,但也是最容易理解的。我们首先使用模型定义来创建我们的 CNN 架构,然后使用 model.fit 来训练它,最后使用 model.evaluate 来评估训练的模型。在这个实验中,我们选择使用 32 的批量大小,并训练模型 10 个时期。
就是这样。我们有了运行学习曲线图实验的所有构件。让我们首先使用整个 60,000 张图像作为训练数据,以了解模型在最大数据集大小下的基准性能。我们将使用它来对我们的模型进行基准测试,并运行实验来查看在保持可比性能的同时我们可以减少多少数据利用率。
要运行这个实验,我们需要做的就是使用 keras 数据集访问时尚 MNIST 数据集,然后准备我们的数据进行训练,最后训练和评估模型,如下所示。

作者图片
一旦我们完成培训和评估,我们应该会看到类似如下的结果:

作者图片
在我们的运行中,我们观察到每个纪元运行大约需要 34 秒。这意味着我们在 60,000 张图像上训练这个模型的总时间大约是 340 秒。该训练在 10,000 个图像测试集上产生大约 91%的分类准确度。不算太糟吧?现在,让我们看看我们可以消除多少数据来获得相当的性能。让我们从 5000 个训练图像开始,每次迭代再增加 5000 个。虽然有更好的方法来处理这个问题,但为了简单起见,我们将为每次迭代手动更改训练数据集的大小,如下所示。

作者图片
当使用这样的实验设置时,建议交叉检查类别不平衡,但是,我们不会在这个实验中包括这样的策略。当我们从 keras 加载数据集时,它已经被打乱了。在这个实验中,由于数据集的简单性,我们将依赖于初始混洗和使用类别交叉熵损失来处理由采样引起的类别不平衡。
现在,让我们来看看在仅使用 5000 个训练图像的情况下,我们的模型性能是什么样的。

作者图片
我们观察到,在大约 30 秒的训练时间内,分类准确率为 86%——训练时间减少 11 倍,准确率降低 5%。在任何一天,这都将是一个很好的权衡,但是,我们的目标是看看在减少训练数据的情况下,我们可以在多大程度上接近我们模型的最大性能。下表和相应的曲线图显示了训练示例、训练时间和模型性能之间的映射。

作者图片

作者图片
从上表中,我们可以说 35,000 个训练图像是一个很好的价值权衡。对于 0.91%准确度的损失,这提供了训练数据需求的大约 42%的减少和训练时间的 41%的减少。您的用例的适当权衡是主观的,应该基于项目管理目标。
现在,这一切都很棒,但是如果我们一开始就没有 60,000 张图片呢?我们能估计数据集大小和性能之间的映射吗?是啊!这就是推断的由来。假设您只有 30,000 张图像,并且想要了解理论上的权衡,以了解还需要收集或扩充多少数据。这意味着您只有上表中前 6 个条目的数据(您总是可以获得更细粒度的数据,以便更好地播种插值算法)。随着样本数量的增加,从现有值外推学习曲线图将给出模型性能的适当估计。因此,我们可以估计目标性能的近似数据集大小要求。在下面的例子中,使用 scipy 的 interpolate 库,我们可以估计模型在不久的将来的性能,具有相当的准确性(90.16%的估计值对 90.23%的实际值)。

作者图片
那么坏处是什么呢?好吧,有许多外推法。我们假设学习曲线图遵循二次曲线,但我们可能会看到一个放大的快照。此外,你想估计的距离越远,你的预测就越不准确;外推只是一个简单的估计,可以给你一个大概,但不能保证 100%的准确性。
学习曲线图极大地帮助我们根据目标性能、所需资源和项目编译时间来估计所需的数据集大小,但它们仍然只是估计。研究人员还使用类似于统计学习理论、幂律函数估计和类比估计的技术来计算目标模型性能所需的粗略数据集大小。然而,学习曲线图仍然是帮助开发人员理解和确定项目范围的一种强大且相对简单的方法,因此他们可以更仔细地研究项目。
识别机器学习中过拟合和欠拟合的学习曲线
本文讨论了机器学习中的过拟合和欠拟合,以及使用学习曲线来有效地识别机器学习模型中的过拟合和欠拟合。

过度拟合和欠拟合
过度拟合(又名方差):
如果一个模型对数据进行了过度训练,以至于它甚至可以从中学习噪声,那么这个模型就被称为过度拟合。过度拟合模型完美地学习了每一个例子,以至于它错误地分类了一个看不见的/新的例子。对于过度拟合的模型,我们有完美/接近完美的训练集分数,而测试/验证分数很差。
过度拟合背后的原因:
- 使用复杂模型解决简单问题,从数据中提取噪音。示例:将神经网络拟合到 Iris 数据集。
- 小数据集,因为训练集可能不是宇宙的正确表示。
欠拟合(又名偏差):
如果一个模型不能正确地学习数据中的模式,那么它就被认为是不合适的。欠拟合模型不会完全了解数据集中的每个示例。在这种情况下,我们看到训练集和测试/验证集的得分都很低。
不合身背后的原因:
- 用一个简单的模型来解决一个复杂的问题,这个模型不需要学习数据中的所有模式。示例:使用逻辑回归进行图像分类
- 底层数据没有固有的模式。比如,用一个学生父亲的体重来预测他的分数。
学习曲线介绍
学习曲线通过递增地添加新的训练样本来绘制训练样本的训练和验证损失。学习曲线有助于我们确定添加额外的训练示例是否会提高验证分数(在看不见的数据上的分数)。如果模型过度拟合,则添加额外的训练示例可能会提高模型在看不见的数据上的性能。类似地,如果一个模型不合适,那么添加训练样本也没有帮助。“learning_curve”方法可以从 Scikit-Learn 的“model_selection”模块导入,如下所示。
在本文中,我们将使用逻辑回归来预测“虹膜数据”的“种类”。我们将创建一个名为“learn _ curve”的函数,该函数的将逻辑回归模型拟合到 Iris 数据,并返回交叉验证分数、训练分数和学习曲线数据。
良好拟合模型的学习曲线
我们将使用“learn_curve”函数,通过将逆正则化变量/参数“c”设置为 1 来获得良好的拟合模型(即,我们不执行任何正则化)。

作者图片
在上述结果中,交叉验证准确率和训练准确率接近。

作者图片
解读培训损失
良好拟合模型的学习曲线在开始时具有适度高的训练损失,随着训练样本的增加,该损失逐渐减少,并且逐渐变平,这表明增加更多的训练样本不会改善模型在训练数据上的性能。
解读验证损失
良好拟合模型的学习曲线在开始时具有较高的验证损失,随着训练样本的增加,验证损失逐渐减少,并且逐渐变平,这表明增加更多的训练样本不会提高模型在看不见的数据上的性能。
我们还可以看到,在添加了合理数量的训练样本后,训练和验证损失彼此接近。
良好拟合模型的学习曲线的典型特征
- 训练损失和验证损失非常接近,验证损失略大于训练损失。
- 最初减少训练和验证损失,在某个时间点之后直到结束,训练和验证损失相当平稳。
过拟合模型的学习曲线
我们将使用“learn_curve”函数,通过将逆正则化变量/参数“c”设置为 10000(高值“c”会导致过度拟合)来获得过度拟合模型。

作者图片
与欠拟合和良好拟合模型相比,交叉验证准确度的标准偏差较高。训练精度高于交叉验证精度,这是过度拟合模型的典型特征,但不会高到检测不到过度拟合。但是过度拟合可以从学习曲线中检测出来。

作者图片
解读培训损失
过拟合模型的学习曲线在开始时具有非常低的训练损失,随着训练样本的增加,训练损失逐渐略微增加,并且不会变平。
解读验证损失
过度拟合模型的学习曲线在开始时具有较高的验证损失,随着训练样本的增加,该损失逐渐减少,并且不会变平,这表明增加更多的训练样本可以提高模型在未看到的数据上的性能。
我们还可以看到,训练和验证损失彼此远离,在添加额外的训练数据后,它们可能彼此接近。
过拟合模型学习曲线的典型特征
- 训练损失和验证损失相距甚远。
- 在添加训练样本时逐渐减少验证损失(没有拉平)。
- 非常低的培训损失,在添加培训示例后略有增加。
欠拟合模型的学习曲线
我们将使用“learn_curve”函数,通过将逆正则化变量/参数“c”设置为 1/10000 来获得一个欠拟合模型(“c”的低值导致欠拟合)。

作者图片
与过度拟合和良好拟合模型相比,交叉验证准确度的标准偏差较低。然而,欠拟合可以从学习曲线中检测出来。

作者图片
解读培训损失
欠拟合模型的学习曲线在开始时具有较低的训练损失,该损失随着训练样本的增加而逐渐增加,并在结束时突然下降到任意的最小点(最小并不意味着零损失)。这种结尾的突然下跌可能不会一直发生。下图也显示了欠拟合。

作者图片
解读验证损失
欠拟合模型的学习曲线在开始时具有较高的验证损失,该损失随着训练样本的增加而逐渐降低,并在结束时突然下降到任意最小值(这种在结束时的突然下降可能不总是发生,但它可能保持平坦),这表明增加更多的训练样本不能提高模型在看不见的数据上的性能。
欠拟合模型学习曲线的典型特征
- 增加训练样本会增加训练损失。
- 训练损失和验证损失在最后是接近的。
- 培训损失和最终确认损失的突然下降(并非总是如此)。
上图清楚地表明,学习曲线是识别过拟合和欠拟合问题的有效方法,即使交叉验证指标可能无法识别它们。
用可逆的(基于流的)解释网络学习解纠缠的表示
什么是解开的表征?我们如何使用基于流的生成模型来学习任何任意模型的不纠缠的表示?

图 1:IIN 网络可以应用于任意的现有模型。IIN 采用由任意模型学习的表示 z,并将其分解成更小的因子,使得每个因子学习表示一个生成概念。图片来源:[1]。
解开的表示在处理许多下游任务时会很有用,并有助于提高模型的健壮性和通用性。在本帖中,我们将探讨如何从使用基于流的生成模型的任意预训练模型所学习到的表示中学习解开的表示。具体来说,我们将研究埃塞等人在论文《用于解释潜在表征的解开可逆解释网络》中提出的可逆解释网络(IIN)。艾尔。[1].我们将看到 IIN 背后的想法,它们是如何工作的,它们的用途是什么。我们还将简要了解一下该文件所取得的成果。
解开的表象
一个不纠缠的表征是这样的,其中单个潜在单位的变化对一个生成因素的变化敏感,而对其他因素的变化保持不变[2]。换句话说,给定一个解开的表征,潜在单位的变化将导致一个生成因素的变化,反之亦然。
解开的表征在多种任务中是有用的,例如新样本生成、新颖性检测、学习压缩的表征等。良好的表示有助于模型的健壮性和通用性。除此之外,在需要知识转移的任务中,在学习的表示可以帮助模型快速收敛的情况下,如转移学习或领域适应,解开的表示也有帮助。
基于流程的生成模型
当我们观察 VAEs 和 GAN 这样的生成模型时,他们都没有明确地了解真实的数据分布 p( x ),因为 p(x)=∫p(|z)p(z)dz通常是难以处理的,因为我们不可能对 z ~ p(z) 的所有值进行积分。另一方面,基于流的生成模型能够通过使用标准化流来克服这个问题。
标准化流程:标准化流程通过应用一系列双射变换,一个在另一个之上,将简单的分布变换为更复杂的分布。双射函数也有一个反函数,这意味着我们可以计算正向和反向。
基于流的生成模型只是一系列标准化的流,一个堆叠在另一个之上。因为变换函数是可逆的,所以基于流的模型也是可逆的( x → z 和 z →x) 。

情商。1: A 流程
这里,z0是初始分布, x = z_k 是我们要学习的最终分布而 f_i(。)是一系列双射变换函数。
基于流量的模型允许我们直接优化数据的对数似然性,如下所示:

情商。2:对数似然计算。
这里π_ 0(z0)是初始分布。通常,选择变换使得对数行列式易于计算。
要了解更多关于基于流程的生成模型及其工作原理,请查看这篇令人惊叹的博客帖子!
用于学习非纠缠表示的可逆解释网络
论文[1]背后的主要思想是学习非线性映射,该非线性映射将来自任意预训练模型的学习到的表示转换到一个空间,在该空间中,新的表示可以分解成因子,使得每个因子的表示对应于一个人类可理解的语义概念。为此,作者提出了一种基于流的可逆网络 T ,该网络学习从已学习的 larent 空间到新的、不纠缠的空间的映射(图 1 ,即:

并且由于 T 是可逆的,所以反过来也是可能的:

为了获得一个清晰且可解释的空间,作者建议将 **Z~(读作 Z 颚化符)**分解为 K+1 个因子,其中每个因子代表一个可解释的概念。

z 的因式分解。z被分解成 k 个因子,其中每个 z ~ k 是 N_k 维的。所有 k 的 N_k 总和为 n。
这里使用基于流的可逆网络是有意义的,因为我们能够从 T: z →z~ 以及 z~ → z 学习映射。这意味着,可逆模型 T 也应该允许我们通过修改解开空间中的单个因素 z~_k 来有意义地修改原始潜在表示 z 。
实现因子 z~_k 的解纠缠意味着对于所有 k,每个 z~_k 的分布彼此独立,并且所有 z~_k 的联合分布可以写成

情商。2:p(z ~)的因式分解。
每个因子 z ~ k 被模拟为一个单位高斯,因此联合分布成为

情商。3:联合分布 p(z~)
为了有解纠缠的因素,我们需要满足两个条件:
**【I)**每个 z~_k 应该只对一个可解释的概念敏感
ii) z~_k 应该对它不代表的所有其他概念不变。
这是通过查看成对的图像( x _a, x_b )来实现的。每个语义概念 F ∈ {1,…,K} 都用 z~_F 来表示。使用从 p(xa,xb | F)中提取的图像对(xa,xb)来训练每个 z~_F 。除了 **F ∈ {1,…,K},**之外的所有其他语义概念的表示都是通过剩余因子 z~_0 来学习的。
给定共享相同概念的一对图像 F 和它们的表示 z~^a 和 z~^b (来自可逆模型的图像的表示),我们需要确保两个图像的 f 因子的表示是相似的。为此,将图像 b 的 F 因子作为以图像 a 的 F 因子为中心的高斯:

情商。4
正相关因子σ_ab ∈ (0,1)控制 z~^a_F 和 z~^b_F 有多接近/相似。
ii) 所有其他因素的表示是不变的(无相关性),并被建模为单位高斯分布:

情商。5
为了训练流动模型,我们最大化图像对( z _a, z _b)的原始表示的可能性。该对的可能性计算如下

情商。6
记录日志并应用 Eqs。2、4 和 5 到等式 6,我们得到损失函数:

情商。7:一个图像对的丢失
在哪里,
红框中的项对应于 p(z^a 的所有因子的对数似然),
蓝框中的项对应于除 p(z^b 之外的所有因子的对数似然),
绿框中的项对应于图像 b 的因子 f 的对数似然,
T( z ^j_k) = z~_k
总损失是图像对在所有因子 F 上的损失:

情商。8:全损耗功能
估计每个因素的维度
在 IIN 模型中,我们将潜在的 z~ 分解为 K+1 个因子(残差+ K 个因子),其中 K 个因子中的每一个都可以具有不同的维度,条件是所有维度的总和等于 z~ 的总和。
通过计算每个因素的分数来估计每个因素的维度。因子 f 的分数被计算为所有图像对之间的原始表示的相关性的总和( z ^a, z ^b) ~ p( z ^a, z ^b|F),即,

情商。9:每个因素的得分。
剩余因子被赋予分数 N (尺寸 z )。那么每个因素的维数估计为:

情商。10:每个因子的估计维度。
结果
交换解开的因素

图 2:将目标图像(最左边一列)的残差( z~ _0)与目标图像(最上面一行)的动物类别因子( z~ _1)相结合。图片来源:[1]。
在图 2 中,将目标图像(最左边的列)的残差( z~ _0)与目标图像(最上面的行)的动物类别因子( z~ _1)相结合,导致在结果图像中动物类型的转移,同时保持源图像的姿态。

图 3:沿着语义轴 F → F~沿着微笑因子插值。图像来源:[1]
在 CelebA 数据集上沿着微笑的语义轴进行插值时,可以看到该模型能够控制微笑的数量,同时保持其他因素相对恒定。关于如何执行插值的更多信息可以在[1]中找到。
密码
论文的代码可以在这里找到。
结论
在本文中,我们讨论了什么是无纠缠表示及其用途,然后简要地研究了基于流的生成模型是如何工作的。我们还深入研究了可逆解释网络。IIN 是一个强大的网络,可以在任何预训练的网络上使用,以学习从原始表示到解开的表示的映射。利用基于流的模型的可逆性,该模型还可以用于任意修改解开的因子 z~ _k,以实现原始表示中语义上有意义的改变。
页(page 的缩写)s:如果您发现任何错误/问题,请留下评论,我将很乐意修复它们!😃
参考
[1] Esser,Patrick,Robin Rombach 和 Bjorn Ommer。"一个用于解释潜在表征的解开的可逆解释网络."IEEE/CVF 计算机视觉和模式识别会议文集。2020.
[2]本吉奥、库维尔和文森特。表征学习:回顾与新观点。在 IEEE 模式分析汇刊&机器智能,2013。
从音频中学习:音高和色谱图
为音乐信息检索解释音高变化
介绍
既然已经完全理解了声谱图的概念,我们想更深入地研究频率以外的各种结构。当研究 Mel 标度上的声波时,我们体会到了这一点——特别是使用 MFCCs。虽然可视化 MFCCs 在技术上不是光谱图,但粗略的想法仍然成立。
然而,这篇文章将更侧重于音乐信息检索(MIR ),因为我们将研究音高随时间的变化。为了做到这一点,我们需要了解什么是音高,它是如何表示的,以及我们如何使用傅立叶变换来确定音高的变化。
相关文章:
一如既往,如果你想查看 Jupyter 笔记本中的代码,你可以在我的 GitHub 上找到一切。
什么是音高?
音高可以理解为声音的相对高低。声音越高,音调越高,声音越低,音调越低。很简单,对吧?为了完全理解音高,我们需要理解音高类别和八度音阶。
音高类别是与每个声音相关联的字母。所有的音高都属于 7 个字母中的一个:A、B、C、D、E、F 和 g。让我们假设我们正在弹钢琴,我们从 A 开始。我们将一直上升一个白键,直到我们到达 g 键。当我们随着每个白键上升时,我们不可避免地一遍又一遍地循环这些字母。然而,当我们按下 G 后的第二个 A 键时,重要的是要注意,它不是我们最初开始时的那个音。音高类是一样的;这是一把钥匙。然而,声音比以前更高,表明我们在下一个(更高的)八度。
在潜入八度之前,我们先快速覆盖一下黑键。如果我们从 C 开始,上升一个黑键,我们就达到了所谓的 C#(读作 C 调。)如果我们再看一下这幅图,我们还会发现它也被称为 D♭(pronounced 降 d 调。)这是因为黑键也在 d 之前,简单来说,如果我们上一个黑键,音符就“升”了,如果我们下一个黑键,音符就“降”了。就人类听到的而言,它们是等价的,所以我们称这些音符为等音。至于两个白键之间没有黑键的情况,你不必为这篇文章担心,因为这涉及到更多的音乐理论。
一个八度音程是一个数字,它指明了我们所处的音高组。如果我们重复我们的例子,知道我们在 A3,下一个 A 键是 A4。同样,这应该不难理解。键盘的中间键是 C4,它通常被用作你所在八度的参照。
值得注意的是,该数字不是在每个 A 值之后增加,而是在每个 C 值之后增加。这意味着,如果我们从中间的 C,或 C4 开始,它后面的 B 键是 B3,B 键在 B4 之后。
关于色谱图
既然我们了解了音乐中的音高,我们就可以深入到色度滤波器中去,它是我们色度图的基础。
色度滤波器可以从色度滤波器组中导出。滤波器组旨在将录制声音的所有能量投射到 12 个箱中,即我们看到的所有音符,加上小调/大调(也是钢琴的黑键),而不管它在哪个八度音阶中。通过忽略八度音阶,我们可以创建一个音高如何随时间变化的热图,这是 MIR 的一个重要方面。例如,如果你决定教 LSTM 人如何演奏音乐,这些功能将非常有用,因为它们会告诉神经网络音高可能如何随时间变化。
让我们想象一下不同频率下的色度滤波器组。

作者照片
通过取我们基于傅立叶的声谱图(通过取 STFT)和这个滤波器组的点积,我们可以将所讨论的歌曲映射到我们之前讨论过的一组音高上。幸运的是,多亏了librosa,创建色谱图的功能已经为我们创建好了。请注意,我们不必使用音频上的 STFT 作为我们的基础,但这超出了本文的范围。
记住这一点,让我们研究我们的各种体裁片段的色谱图。

作者照片
现在我们可以看到音高是如何随时间变化的,我们可以在每种体裁中看到一些有趣的观察结果。
对于 R&B 来说,很明显艺术家决定让歌曲围绕 e 音符,对于 Rap 来说,它是高度分散和分布的,这是有意义的,因为这种类型利用了类似于打击乐的声音节奏,而对于 Rock 来说,它围绕 C#或 D♭.音符
结论
到目前为止,您应该已经很好地理解了什么是音高,我们如何对每个音高进行分类,色度滤镜的目的是什么,以及我们如何可视化色度图。
如果你有任何问题,请在下面留下。
从音频中学习:频谱图
将音频结构可视化到毫秒级。

到本文结束时,你将能够创建像这样的图形。图片作者。
简介:
当涉及到机器学习,甚至深度学习时,如何处理数据是模型训练和测试性能的基础。当在音频领域工作时,在到达这个阶段之前有几个步骤需要理解,但是一旦你到达那里,从音频中学习就成为一个相当容易的任务。在阅读本文之前,请务必理解下面链接的概念。
相关文章:
在这篇文章中,我的目标是分解什么是频谱图,它是如何在机器学习领域使用的,以及你如何使用它们来解决你试图解决的任何问题。
和往常一样,如果你想查看代码,以及需要跟进的文件,你可以在我的GitHub上找到一切。
什么是声谱图?
你可以把光谱图想象成声音的图片。我知道这有点奇怪,但你应该尽可能加强这种直觉。光谱图中的 spec 部分来自光谱,你在图右侧看到的色带就是这个。的光谱是什么?音频的频率。
记住所有这些信息,让我正式定义。
声谱图是表示一段时间内记录的音频的频谱的图形。
这意味着,当我们在图中颜色变亮时,声音严重集中在这些特定频率周围,而当我们颜色变暗时,声音接近空/死声。这使得我们甚至不用听就能很好地理解音频的形状和结构!这就是光谱图在各种 ML/DL 模型中发挥作用的地方。
如何创建光谱图:
现在出现了一个问题,我们如何计算光谱图?这个问题的答案比预想的要简单很多。
- 将音频分割成重叠的块或窗口。
- 在每个窗口上执行短时傅立叶变换。记得取其绝对值!
- 每个结果窗口都有一条垂直线代表幅度与频率的关系。
- 取结果窗口并转换为分贝。这给了我们声音结构的丰富图像。
- 最后,我们将这些窗口重新布置成原始歌曲的长度,并显示输出。
现在我们已经对频谱图有了一个很好的理解,让我们学习如何用 Python 从声音中检索它们!使用librosa中的函数,我们可以不费吹灰之力就完成这项工作。
首先,让我们导入所需的包并加载音频。
第二,我要定义两个函数;一个将执行所有必要的步骤并输出处理后的信号,另一个将绘制频谱图。请务必通读注释和行,以了解完成此操作的过程。
现在,定义好函数后,我们可以简单地使用plot_spec来绘制结果!
plot_spec(to_decibles(guitar), sr, 'Guitar')

作者图。
plot_spec(to_decibles(kick), sr, 'Kick')

作者图。
plot_spec(to_decibles(snare), sr, 'Snare')

作者图。
结论:
至此,您应该能够理解如何使用短时傅立叶变换创建光谱图,以及如何用 Python 创建光谱图。音频的这些表示允许各种深度学习架构比波形甚至傅立叶表示更容易地提取特征。
请继续关注更多音频声谱图。
感谢您的阅读。

被折叠的 条评论
为什么被折叠?



