TowardsDataScience 博客中文翻译 2016~2018(六十六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用具有交互代码的深度神经网络将 DNA 序列转换为蛋白质序列[带 TF 的手动 Back Prop

原文:https://towardsdatascience.com/converting-dna-sequence-to-protein-sequence-using-deep-neural-network-with-interactive-code-manual-16d41e1304a7?source=collection_archive---------3-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image from pixabay

所以今天,我将继续我的机器学习生物信息学之旅。我将尝试完成生物信息学中最基本的任务,即将 DNA 序列转换成蛋白质。同样,这也使任务复杂化了,我们可以建立一个字典来映射这些值,就像帖子中的Vijini mallawarachchi所做的那样。

另外,请注意,我们将把 DNA /蛋白质序列预处理成载体,如果你不知道如何去做,请见这个帖子

最后,我将执行扩张反向传播来训练我们的网络。

网络架构和前馈操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

黑色向量→ 编码的 DNA 序列数据
红色向量 →我们的网络中每一层都有 4 层(50 个神经元)
蓝色向量 →软 Max 层进行多类分类
粉粉?箭头 →标准前馈操作

如上所述,前馈操作没有什么特别的,非常简单的全连接神经网络。此外,我们将有 50 个神经元在每一层。

反向传播操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

黄色箭头 →标准梯度流
黑色弯箭头反向传播的扩张连接

如上所述,训练过程也非常简单,只是标准的反向传播与每隔一层的一些扩张连接,以形成密集连接。

培训结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

左图 →一段时间内的平均精度
右图 →一段时间内的成本

因此,对于 1201 epoch,我们将跟踪我们的网络运行情况,如上所述,最终它能够达到 100%的准确性。

将 DNA 序列转换成蛋白质

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

红框 →模型预测 DNA 序列 CTT/TTA/CTA 属于第 9 类或蛋白质“L”

训练完成后,我们将把每个 DNA 序列交给模型,告诉它预测它属于哪个类别,如上所述,它正在正确地预测每个类别。我们可以通过下面的图表来验证结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Genetic Code Chart for DNA (http://www.geneinfinity.org/sp/sp_gencode.html)

互动码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我搬到了谷歌 Colab 寻找交互代码!所以你需要一个谷歌帐户来查看代码,你也不能在谷歌实验室运行只读脚本,所以在你的操场上做一个副本。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!

要访问代码,请点击此处。

遗言

将 DNA 转换成蛋白质可以通过使用字典来简单地完成,然而我只是想尝试一下。

如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你想看我所有写作的列表,请在这里查看我的网站。

与此同时,请在我的 twitter 这里关注我,并访问我的网站或我的 Youtube 频道了解更多内容。如果你感兴趣的话,我还做了解耦神经网络的比较。

参考

  1. numpy 中的字符 Int 转换。(2018).要点。检索于 2018 年 3 月 6 日,来自https://gist.github.com/tkf/2276773
  2. 印刷,第 2018 页。python:水平打印,而不是当前的默认打印。Stackoverflow.com。检索于 2018 年 3 月 6 日,来自https://stack overflow . com/questions/8437964/python-printing-horizontally-而非-current-default-printing
  3. 从生物信息学开始——将 DNA 序列转化为蛋白质序列。(2017).走向数据科学。检索于 2018 年 3 月 6 日,来自https://towards data science . com/starting-off-in-bio informatics-turning-DNA-sequences-into-protein-sequences-c 771 DC 20 b 89 f
  4. 范围?,H. (2018)。如何将数据归一化到 0–1 范围?。Stats.stackexchange.com。2018 年 3 月 7 日检索,来自https://stats . stack exchange . com/questions/70801/how-to-normalize-data-to-0-1-range
  5. TF . reset _ default _ graph | tensor flow(2018).张量流。检索于 2018 年 3 月 10 日,来自https://www . tensor flow . org/API _ docs/python/TF/reset _ default _ graph\
  6. 具有交互式代码的机器学习任务的 DNA /蛋白质表示。(2018).走向数据科学。检索于 2018 年 3 月 10 日,来自https://towards data science . com/DNA-protein-representation-for-machine-learning-task-with-interactive-code-6aa 065 b 69227
  7. 数组?,I. (2018)。有没有 Numpy 函数返回数组中某个东西的第一个索引?。Stackoverflow.com。检索于 2018 年 3 月 10 日,来自https://stack overflow . com/questions/432112/is-there-a-numpy-function-to-return-the-first-index-of-something-in-a-a-array
  8. NumPy . arg max—NumPy 1.13 版手册。(2018).Docs.scipy.org。检索于 2018 年 3 月 10 日,来自https://docs . scipy . org/doc/numpy-1 . 13 . 0/reference/generated/numpy . arg max . html
  9. 遗传密码。(2018).Geneinfinity.org。检索于 2018 年 3 月 10 日,来自http://www.geneinfinity.org/sp/sp_gencode.html

将中型文章转换为博客的降价文章

原文:https://towardsdatascience.com/converting-medium-posts-to-markdown-for-your-blog-5d6830408467?source=collection_archive---------7-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(Source)

如何快速导出中型文章到你的博客

如果你像我一样,开始在 Medium 上写博客,但也想建立自己的网站来展示你的文章,你需要一种方法将文章从 Medium 转移到 Markdown 语言。Markdown 是一种轻量级语言,旨在被转换成 HTML 格式用于网络,有几个工具可以让你从现有的中型文章转为博客的 Markdown。

(如果你还没有博客,那么就按照这个指南使用 Jekyll 和 GitHub 页面在五分钟内建立你自己的网站。)

中等至降价工具

有一个 Chrome 扩展和一个命令行工具用于将你的中型帖子进行降价。不幸的是,我发现 Chrome 扩展不可靠,如果它真的工作,它会产生许多格式错误,需要纠正。

如果你能让 chrome 扩展正常工作,而你不习惯命令行,那么这可能是你最好的选择。然而,我发现命令行工具更适合我的使用,因为它每次都能工作,而且运行后需要对文本进行的重新调整更少。

在命令行上使用中到低

medium-to-markdown 命令行包是用 Javascript 编写的,这意味着你需要node来运行和npm来安装这个包。如果你在 Windows 上,使用这个页面来安装两者(大约需要 3 分钟)。然后,使用npm install medium-to-markdown安装软件包。您需要运行的实际脚本可以在这里找到,如下所示。

Medium to Markdown JS script

要运行,将脚本保存为medium-to-markdown.js,将"<medium post url">更改为您发布的文章的地址,并在命令行键入node medium-to-markdown.js(确保脚本在您的目录中。

这将在您的控制台中输出整篇文章作为 Markdown。要将输出重定向到一个文件,您可以键入node medium-to-markdown.js >> file.md。如果您的博客使用 GitHub Pages + Jekyll,您会希望将存储库的_posts/目录中的md文件保存为date-title.md。比如我的最新贴档_posts/2018-09-16-Five-Minutes-to-Your-Own-Website.md。一旦文章被转换成正确命名的 Markdown 文件,就可以通过将存储库推送到 GitHub 来发布。

就我个人而言,我发现手动重命名文件的过程很繁琐,所以我编写了一个 Python 脚本,该脚本接受一篇已发布的媒体文章的 url 和日期,用该 url 调用medium-to-markdown.js转换脚本,并用正确的文件名保存结果 markdown。该脚本可以在这里找到,命令行用法如下:

Command line usage of Python script for converting medium to Markdown.

总的来说,运行脚本需要 15 秒,网站更新大约需要 5 分钟!去你的博客看看这篇文章。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Website after pushing changes to GitHub.

常见问题的解决方案

Chrome 扩展和命令行工具都会在 Markdown 中产生一些小问题,您必须解决这些问题。我在散文在线编辑器中完成所有的编辑工作,并喜欢并排调出编辑器和原始媒体文章。(我也经常在我的博客上使用 Chrome 开发工具——右键和inspect——来调整 css 并立即看到变化。)

以下是我注意到的一些问题以及如何解决它们。我将假设你正在为你的博客使用 GitHub Pages 和 Jekyll(按照这个指南开始使用),尽管这些技巧可能适用于其他框架。这些解决方案并不详尽,所以如果你遇到更多的问题,请在评论或 Twitter 上告诉我。

图像标题

正如你在上面看到的,默认的 Markdown 转换在图片下方左对齐显示图片标题。要使标题居中,请将以下内容添加到您的styles.scss文件中(在存储库根目录中):

// Captions for images
img + em {
    font-style: italic;
    font-weight: 600;
    margin-bottom: 20px;
    margin-top: 8px;
    display: block;
    text-align: center;
    font-size: 14px;
    color: black;
}

然后,在 Markdown 本身中,将标题文本从顶部显示的默认文本更改为底部显示的文本。确保标题在单独的行上:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

标题现在将在图像下方居中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Caption centered below image.

如果您不喜欢这种样式,请更改上面列出的 css。

并排图像

要在 markdown 中并排呈现图像,可以使用两列表格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我发现你必须包含标题,否则表格不能正确显示。有几个其他的选项,但是这个桌子很好用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Side by Side Images using a table

这里是表格的空白代码,所以只需替换image_linkheader:

Header Left |  Header Right
:--------:|:-------:
![](image_link)  |  ![](image_link)

代码块

如果你写了很多关于编程的东西,那么你希望你的代码看起来很棒!幸运的是,与 on Medium 不同,您可以使用语法突出显示来使您的代码块在您的博客上突出显示。Jekyll 原生支持胭脂语言荧光笔,它有许多风格可供选择(查看它们在这里)。

在文章的降价中,使用反斜线将代码块括起来,并指定高亮显示的语言:

```python
from sklearn.ensemble import RandomForestClassifier 
# Create the model with 100 trees
model = RandomForestClassifier(n_estimators=100,                                                     
                               bootstrap = True,                              
                                max_features = 'sqrt')
# Fit on training data
model.fit(train, train_labels)

默认语法突出显示如下:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/578b2612bc975d189908fbe50e77ae22.png)

Default Python syntax highlighting with Rouge

使用自定义主题,突出显示如下:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/119b5db1d594c700ebf23d7e058760e7.png)

Custom Python syntax highlighting

要设置你自己的代码主题,参考[这篇文章](https://bnhr.xyz/2017/03/25/add-syntax-highlighting-to-your-jekyll-site-with-rouge.html),或者如果你喜欢我的样子,你可以将我的代码样式表`code-highlighting.scss` ( [链接](https://github.com/WillKoehrsen/willkoehrsen.github.io/blob/master/_sass/_code-highlighting.scss))复制粘贴到你的`_sass/`目录中。然后更改`style.scss`中的行`@import “highlights”`到`@import “code-highlighting"`(这应该在底部附近)来导入新的样式。

## GitHub Gists

我的媒体帖子的另一个常见部分是 GitHub gists。为了在你的文章中恰当地展示这些,首先转到原始的中型文章,右击要点,然后选择`inspect frame`。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e15d835b0eea09fcea82e05b2a6771cb.png)

这将显示一页看起来难以理解的代码。然而,你需要做的就是复制`<script>`标签之间的内容,如下所示:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0e34f593a0270cedf9897067a2c1c261.png)

简单地复制这一行并粘贴到如下所示的 Markdown 中,它就会正确地呈现在你的博客上。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/109cd904ee7169c5aeaad3e9187be916.png)

GitHub Gist in Markdown

当然,像你的网站上的任何其他元素一样,你可以用 css 来设计你喜欢的样式!

## 帖子摘录

默认情况下,Jekyll 只会在你的博客主页上显示文章的第一段,并有一个显示“阅读更多”的按钮来访问其余部分。如果你的帖子顶部有一张图片,这将是所有显示的内容。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/cb0b72903cce94701fa05bec5434356a.png)

Default excerpt shown on blog home page

要扩展摘录,在`_config.yaml`中添加以下一行:

Specifies end of excerpt

excerpt_separator:


然后将`<!--more-->` 标签放在 post markdown 中您希望摘录结束的地方。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c99f69231fad48182aa81afa985d7ef2.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3efdd8dd3b93a3e9d4a05940d77a9c63.png)

Specifying extent of post excerpt in Markdown (left) and how it looks on my website (right).

## 其他注意事项

还有很多选择我没有探索。如果你想在你的博客上做点什么,很有可能有一种方法可以做到。例如,你可以通过创建一个 Disqus 账户并将其添加到你的`_config.yaml`文件中来为你的所有帖子添加评论。如果你有很多文章,并且想要限制出现在一个页面上的数量,你也可以在配置文件中使用`pagination`([指令](https://jekyllrb.com/docs/pagination/))来指定。

建立一个网站是令人兴奋的,因为你可以让它看起来像你想要的那样!虽然对大多数人来说这可能不令人惊讶,但我仍然很感激当我对我的网站进行小的更新时,我可以在网上看到我想要的变化。你无法想象当我终于在我的 about 页面上运行了一个实时代码编辑器时,我是多么的热情!在一天结束的时候,是的,建立一个网站是为了让世界看到你自己,但也是为了对你创造的东西感到自豪。

# 结论

使用命令行工具可以快速地从一篇现有的中型文章转到 [Markdown](https://daringfireball.net/projects/markdown/syntax) 。在转换为 Markdown 后,有几个小错误需要解决,但这也给了你机会来定制你想要的帖子。

如果你仍然有任何问题,看看我的[网站库](http://github.com/willkoehrsen/willkoehrsen.github.io),看看你是否能在那里找到解决方案,或者与我联系。此外,如果你发现你可以用 Jekyll 博客做一些很酷的事情,我很乐意听听。现在出去开始写吧。

一如既往,我欢迎评论和建设性的批评。可以通过推特 [@koehrsen_will](http://twitter.com/@koehrsen_will) 或者通过我的网站 [willk.online](http://willk.online) 找到我

# 将拇指向上/拇指向下转换为完整偏斜度的百分位数

> 原文:<https://towardsdatascience.com/converting-thumbs-up-thumbs-down-to-percentiles-with-skewness-intact-5ee70574a694?source=collection_archive---------22----------------------->

## 用 Python 写亚马逊书评

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a00911685ab289f4cf2bbe7c5d260a02.png)

拇指向上/拇指向下的度量标准已经变得非常流行。它在 YouTube、亚马逊和其他网站上被用来获取用户和产品信息。该指标简单、有用且有吸引力。

当我为我的女儿搜索蹒跚学步的视频时,我得到了 50 万个赞成和 30 万个反对的视频。这些视频并不特别令人印象深刻。我希望它们能以另一种方式分类。

百分比和投票计数提供了不同的数据显示方式。百分比必须在 0 到 1 之间,而投票通常在 0 到无限的范围内。将选票转换成 0 到 1 之间的百分位数可以将这些系统结合起来。

我以前写过一篇关于 Medium 的文章,强调了转换倾斜数据的标准方法。在那篇文章中,我讨论了流行方法的优点和缺点,所以我不会在这里讨论它们。

相反,我提出了一个原始的分段线性函数,它将偏斜的数据转换成偏斜度不变的百分位数。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b207ec791180385a12e4152b6254ad89.png)

Base e distribution. Graph taken from Corey Wade’s [Helpful Reviews: Exploratory Data Analysis](https://github.com/coreyjwade/Helpful_Reviews/blob/master/Helpful_Reviews_Exploratory_Data_Analysis.ipynb).

一般来说,大多数拇指朝上/拇指朝下的系统都是右偏的。大多数样本只获得几票,而受欢迎的样本可能获得高出 10 个数量级的投票。离群值可能远远超过第 99 百分位,正如[亚马逊书评“有用投票”的情况](https://github.com/coreyjwade/Helpful_Reviews)

## 有益的投票

In[1]:df.Helpful_Votes.describe()Out[1]:count 4.756338e+06
mean 5.625667e+00
std 2.663631e+01
min 0.000000e+00
25% 1.000000e+00
50% 2.000000e+00
75% 4.000000e+00
max 2.331100e+04


数百万个数据点,从 4 到 23311 的跳跃是惊人的。

将该数据转换成有意义的百分位数可以通过如下分段线性函数来完成:

1.  选择多个透视来分隔数据。
2.  使用日志空间划分数据。
3.  对于每个枢纽,x 值是投票数,y 值是百分位数。
4.  用直线连接相邻的(x,y)点。

作为一个简单的例子,考虑 5 个线性枢轴。(我们很快就会到达 logspace。)我需要第 0、25、50、75 和 100 百分位的点。上表给出了以下分布情况:

(0,0)、(1,0.25)、(2,0.5)、(4,0.75)和(2311,1)。

接下来,我用一条直线连接这些点。这听起来可能微不足道,但是除以 0 是有问题的。相同的 x 值将产生 0 个分母。出于计算目的,非常陡的斜率就足够了。

## 直线函数

In[2]:# Define line from two points and a provided column
def two_points_line(a, b, column):

*# Case when y-values are the same*
if b[1]==a[1]:

    *# Slope defaults to 0*
    slope = 0

*# Case when x-values are the same*
elif b[0]==a[0]:

    *# Case when max value is less than 999999999*
    if column.max() < 999999999:

        *# Add 999999999 to max value*
        slope = column.max() + 999999999

    *# All other cases*
    else:

        *# Multiply max value by itself (greater than 999999999)*
        slope = column.max() * column.max()

*# When x-values and y-values are not 0*
else:

    *# Use standard slope formula*
    slope = (b[1] - a[1])/(b[0]-a[0])

*# Equation for y-intercept (solving y=mx+b for b)*
y_int = a[1] - slope * a[0]

*# Return slope and y-intercept*
return slope, y_int

当连接(4,0.75)到(2311,1)时,结果是一条很长的水平线。大多数数据点将聚集在 0.75 附近,导致数据比以前更加倾斜。

日志空间和更多的枢轴帮助极大。

在为日志空间做准备时,让我们回顾一下 linspace。假设我们想把 0 到 100 分成 5 个单位区间。快捷键不是写 0,5,10,…,100,而是 linspace。

## 林空间

In[3]:# Split the numbers between 0 and 100 into 21 evenly spaced points np.linspace(0,100,21)Out[3]:array([ 0., 5., 10., 15., 20., 25., 30., 35., 40., 45., 50.,
55., 60., 65., 70., 75., 80., 85., 90., 95., 100.])


Logspace 返回对数刻度上间隔均匀的数字。每个端点需要 10 的次方。对于结束于 100 的对数间隔段,我们需要 2 作为上限。

## 日志空间

In[4]:# Split the numbers between 0 and 100 into 21 logspace points np.logspace(0, 2, 21)Out[4]:array([ 1. , 1.25892541, 1.58489319, 1.99526231,
2.51188643, 3.16227766, 3.98107171, 5.01187234,
6.30957344, 7.94328235, 10. , 12.58925412,
15.84893192, 19.95262315, 25.11886432, 31.6227766 ,
39.81071706, 50.11872336, 63.09573445, 79.43282347,
100. ])


日志空间最初看起来更适合左侧倾斜的数据。这很容易通过从 101 中减去每个点并颠倒顺序来补救。

## 反向对数空间

In[5]:# Create logspace
left_logspace = np.logspace(0, 2, 21)# Reverse logspace
right_logspace = 101 - left_logspace*# Reverse array to ascending order*
percent_array = right_logspace[::-1]# Display results
percent_arrayOut[5]:array([ 1. , 21.56717653, 37.90426555, 50.88127664,
61.18928294, 69.3772234 , 75.88113568, 81.04737685,
85.15106808, 88.41074588, 91. , 93.05671765,
94.69042656, 95.98812766, 97.01892829, 97.83772234,
98.48811357, 99.00473769, 99.41510681, 99.74107459,
100. ])


好多了。

对于“有帮助的投票”列,偏斜度远远超过了第 99 个百分点。经过一些反复试验,我选择了 50 个 logspace 段(51 个点)。

## 有用的投票日志空间枢轴

percents= [ 1. 9.79891606 17.82362289 25.1422425 31.81690291
37.90426555 43.45600627 48.51925398 53.13699077 57.34841678
61.18928294 64.69219452 67.88688785 70.8004828 73.45771297
75.88113568 78.09132347 80.10703869 81.94539282 83.62199171
85.15106808 86.54560229 87.81743261 88.97735565 90.03521804
91. 91.87989161 92.68236229 93.41422425 94.08169029
94.69042656 95.24560063 95.7519254 96.21369908 96.63484168
97.01892829 97.36921945 97.68868879 97.98004828 98.2457713
98.48811357 98.70913235 98.91070387 99.09453928 99.26219917
99.41510681 99.55456023 99.68174326 99.79773557 99.9035218
100. ]pivots= [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 4.0, 4.0, 4.0, 5.0, 6.0, 6.0, 7.0, 8.0, 9.0, 9.0, 10.0, 11.0, 12.0, 14.0, 15.0, 16.0, 18.0, 19.0, 21.0, 23.0, 25.0, 28.0, 30.0, 33.0, 36.0, 40.0, 44.0, 48.0, 54.0, 60.0, 67.0, 77.0, 89.0, 104.0, 126.0, 163.0, 243.0, 23311.0]


枢轴现在展开得很漂亮!如果我使用 linspace,分布应该是[0,0,0,0,0,…,14,17,24,42,23311]。

在分享返回这些结果的函数之前,我想回顾一下总体思路。

竖起大拇指,不竖起大拇指的系统通常会导致数据向右倾斜。该数据可以通过保持偏斜度不变的分段线性函数转换为 0 到 1 之间的值。选择枢纽数,用 logspace 划分数据,取 x 值为票数,y 值为百分位数,用直线连接相邻点。

编码快乐!

## 偏斜线性函数

In[6]:# Import essentials
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Show all plots in cells
%matplotlib inline*# Transform skewed column into piecewise linear function by choosing number of segments*def skewed_to_linear(num_segments, column, logspace=True, rightSkew=True, show_graph=True, print_arrays=True, nonNegative=True):

*# GET PIVOTS AND PERCENTILES*
*#********************************************************************

*# Number of pivots equals number of segments plus 1*
num_pivots = num_segments + 1

*# Last index equals number of segments*
last_index = num_segments

*# By default, logspace is True*
if logspace:

    *# Create array of percents between 1 and 100 with log base 10 intervals*
    percents_array = np.logspace(0,2,num_pivots)

    *# By default, rightSkew is True*
    if rightSkew:

        *# Stack array with more values closer to 100* 
        backwards_array = 101 - percents_array

        *# Reverse array to standard ascending order*
        percents_array = backwards_array[::-1]

*# If logspace is False*
else:

    *# Linspace divides 0 and 100 into even segments*
    percents_array = np.linspace(0, 100, num_pivots)

*# Create array of pivots*
pivots_array = []

*# Loop over percents_array*
for i in percents_array:

    *# Obtain value for each percentile*
    pivot = np.percentile(column, i)

    *# Add each value to pivots_array*
    pivots_array.append(pivot)

*# By default, print_arrays is False*
if print_arrays:

    *# Display array of percents*
    print('percents=',(percents_array))

    *# Display corresponding array of pivots*
    print('pivots=',(pivots_array))

*# Convert percents_array from integers to decimals (75 becomes 0.75)*
percents_array = percents_array/100

*# GET SLOPES AND Y-INTERCEPTS*
*#********************************************************************

*# Initialize slope array*
slopes = np.random.rand(num_pivots)

*# Initialize y-intercept array*
yints = np.random.rand(num_pivots)

*# Loop over number of elements of percents_array minus 1*
for n in range(len(percents_array)-1):

    *# Create point a by matching elements in pivots_array with element in percents array*
    a = (pivots_array[n], percents_array[n])

    *# Create point b by matching elements in pivots_array with element in percents array*
    b = (pivots_array[n+1], percents_array[n+1])

    *# Use two_points_line function to find slope, y-intercept of a and b* 
    slopes[n], yints[n] = two_points_line(a, b, column)

    *# By default, show_graph is true*
    if show_graph:

        *# Define points_between_x to create appearance of continuous graph*
        points_between_x = (pivots_array[n+1] - pivots_array[n]) * 1000

        *# Define x for each loop as number of points between the pivots*
        x = np.linspace(pivots_array[n], pivots_array[n+1], points_between_x)

        *# Plot graph using x values with corresponding slop and y-intercepts*
        plt.plot(x, slopes[n] * x + yints[n])

*# By default, print_arrays is False*
if print_arrays:

    *# Show all slopes*
    print('slopes=',(slopes))

    *# Show all y-intercepts*
    print('yints=',(yints))

*# GET Y-VALUES BETWEEN 0 AND 1 FOR EACH COLUMN ELEMENT*
*#********************************************************************

*# Create numpy array of y-values the same length as given column*
y = np.random.rand(len(column))

*# Convert y to a Series*
y = pd.Series(y)

*# Start iteration*
i = 0

*# Loop over each element in column*
for x in column:

    *# Case when column is non-negative and element is 0*
    if (nonNegative) & (x == 0):

        *# Min value should be 0*
        y[i] = 0

        *# Add 1 to i*
        i+=1

    *# Case when element is last member of pivots_array*
    elif x == pivots_array[last_index]:

        *# Last pivot should have value of 100%*
        y[i] = 1.0

        *# Add 1 to i*
        i+=1

    *# All other cases*
    else:

        *# Loop over pivots array*
        for pivot in pivots_array: 

            *# Find first pivot greater than x*
            if x < pivot:

                *# The appropriate index is n-1*
                index = pivots_array.index(pivot)-1

                *# Find slope and yint with same index*
                y[i] = slopes[index] * x + yints[index]

                *# Add 1 to i*
                i+=1

                *# Break out of loop*
                break

*# SHOW GRAPH AND RETURN Y-VALUES*
*#********************************************************************

*# By default, show_graph is True*
if show_graph:

    *# Display graph*
    plt.show()

*# Return y-values*
return y

*[*亚马逊图书评论数据集*](http://jmcauley.ucsd.edu/data/amazon/) *来源于 R. He,J. McAuley,WWW,2016 年出版的《沉浮:用一类协同过滤对时尚趋势的视觉演变进行建模》。**

*![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/87c4fa9742057d76716c4e7e60f58045.png)*

# ConvNets 系列。使用 Mask R-CNN 的实际项目原型

> 原文:<https://towardsdatascience.com/convnets-series-actual-project-prototyping-with-mask-r-cnn-dbcd0b4ab519?source=collection_archive---------5----------------------->

# 介绍

这个 ConvNets 系列从德国交通标志的玩具数据集进展到我被要求解决的一个更实际的现实生活问题:**“有没有可能实现一种深度学习魔法,仅使用照片作为单一输入,来区分*好的*质量的菜肴和*差的*质量的菜肴?”**。简而言之,企业希望这样:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b7e784325d2eb8836cf29aed961e5907.png)

When a business looks at ML through pink glasses, they imagine this

这是一个不适定问题的例子:由于 done 的定义非常模糊(更不用说实现了),所以无法确定解决方案是否存在,以及该解决方案是否唯一且稳定。虽然这篇文章不是关于有效的沟通或项目管理,但有一点是必要的:**你永远不应该参与范围很小的项目。处理这种不确定性的一个行之有效的方法是首先建立一个定义良好的原型,然后再构建剩下的任务。这就是我们采取的策略。**

# 问题定义

在我的原型中,我专注于菜单中的单个项目——煎蛋卷——并构建了一个可扩展的数据管道,输出煎蛋卷的感知“质量”。可以概括为这样:

*   **问题类型:**多类分类,质量的 6 个离散类:`[good, broken_yolk, overroasted, two_eggs, four_eggs, misplaced_pieces]`。
*   **数据集:** 351 张手动采集的各种煎蛋的 DSLR 相机照片。Train/val/test: 139/32/180 洗牌照片。
*   **标签:**给每张照片分配一个主观质量等级。
*   **度量:**分类交叉熵。
*   **必要的领域知识:**一个“好”的煎蛋的定义是三个鸡蛋,蛋黄未破裂,一些培根,没有烧焦的碎片,中间有一片欧芹。此外,它的组成应该是视觉上正确的,例如,不应该有分散的碎片。
*   **done 的定义:**原型开发两周之后测试集上的最佳可能交叉熵。
*   **结果可视化:**测试集低维数据表示的 t-SNE。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/959c1be9b642400a74bae9f9dc4bb25f.png)

Input images as they are captured with camera

主要目标是*使用神经网络分类器获得并组合提取的信号*,并让分类器做出关于测试集中项目的类别概率的 softmax 预测。这样的目标将使这个原型可行,并可用于以后的使用。以下是我们提取并发现有用的信号:

*   关键成分面膜(Mask R-CNN): *信号#1。*
*   按每种成分分组的关键成分计数(基本上是不同成分计数的矩阵):*信号#2。*
*   背景被删除的煎蛋卷板的 RGB 作物。为了简单起见,我决定暂时不将它们添加到模型中。这可能是最明显的信号:只需使用一些奇特的损失函数在这些图像上训练一个 ConvNet 分类器,并在低维嵌入中采用从选定的典范图像到当前图像的 L2 距离。不幸的是,我没有机会测试这个假设,因为我只限于训练集中的 139 个样本。

# 50K 管道概述

我省略了几个重要的阶段,如数据发现和探索性分析、基线解决方案和主动标记(这是我自己对受[多边形-RNN 演示视频](https://www.youtube.com/watch?v=S1UUR4FlJ84)启发的半监督实例注释的花哨名称)以及 Mask R-CNN 的管道(在后面的帖子中会有更多相关内容)。为了拥抱整个管道,这里是它的 50K 英尺视图:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/085e8262433b634e29aea010c3e09d6e.png)

We are mostly interested in the Mask R-CNN and classification stages of the pipeline

对于这篇文章的其余部分,我将重点关注三个阶段:[1]屏蔽 R-CNN 的成分屏蔽推理,[2]基于 Keras 的 ConvNet 分类器,[3]t-SNE 的结果可视化。

# 阶段 1:屏蔽 R-CNN 和屏蔽推理

口罩 R-CNN (MRCNN)最近得到了大量的报道和炒作。从最初的[脸书的论文](https://arxiv.org/abs/1703.06870)开始,到 Kaggle 上的[数据科学碗 2018](https://www.kaggle.com/c/data-science-bowl-2018) ,Mask R-CNN 证明了自己是实例分割(对象感知分割)的强大架构。我使用的基于 Keras 的 [Matterport 的 MRCNN 的实现](https://github.com/matterport/Mask_RCNN)绝对是一种享受。代码结构良好,文档清晰,开箱即用,尽管比我预期的要慢。

MRCNN 中的一段话:

> MRCNN 由两个明确的部分组成:主干网络***和网络头部***从而继承了更快的 R-CNN 架构。基于特征金字塔网络(FPN)或 ResNet101 的卷积骨干网络作为整个图像的特征提取器。在此之上是区域建议网络(RPN ),它对头部的多尺度 RoI(感兴趣区域)进行采样。网络头进行边界框识别和应用于每个 RoI 的掩模预测。在两者之间,RoIAlign 图层将 RPN 提取的多尺度要素与输入精确对齐。******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/40a40bc89105abc80990f04e5c109952.png)******

******MRCNN framework as presented in the original paper******

********对于实际应用,尤其是原型制作,预训练的 ConvNet 至关重要。**在许多现实生活场景中,数据科学家的标注数据集非常有限,甚至没有任何标注。相比之下,*conv net 需要大的标记数据集来收敛*(例如,ImageNet 数据集包含 1.2M 的标记图像)。这就是[迁移学习](http://cs231n.github.io/transfer-learning/)帮助的地方:一种策略是冻结卷积层的权重,只重新训练分类器。为了避免模型过度拟合,Conv 图层权重冻结对于小数据集非常重要。******

******以下是我在一个时期的训练后得到的样本:******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/175237c3b48102c62edffe903f5dfd6f.png)******

******The result of instance segmentation: all key ingredients are detected******

******下一步(*处理分类器*的推断数据,在我的 50K 管道视图中)是裁剪包含盘子的图像部分,并从该裁剪中提取每种成分的 2D 二进制掩码:******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0b25f2c16fce35d560aa2931eee2f6a5.png)******

******Cropped image with the target dish and its key ingredients as binary masks******

******这些二进制掩码然后被组合成一个 8 通道图像(正如我为 MRCNN 定义的 8 个掩码类)——这就是我的*信号#1* :******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e44e93b8bb9f39d3f617eda6ebdf198f.png)******

******Signal #1: 8-channel image composed of binary masks. Colors are just for better visualization******

******对于*信号#2* ,我从 MRCNN 推断中计算了每种成分的数量,并将其打包到每种作物的特征向量中。******

# ******阶段 2:基于 Keras 的 ConvNet 分类器******

******CNN 分类器是使用 Keras 从头开始实现的。我心中的目标是融合几个信号(*信号#1* 和*信号#2* ,以及在未来添加更多数据),并让网络对菜肴的质量等级做出预测。以下架构是实验性的,离理想状态还很远:******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5999862190c632b8da720cb92208d678.png)******

******关于分类器架构的几点观察和评论:******

*   ********多尺度卷积模块**:最初我为卷积层选择了一个 5x5 的内核,但是这个决定只给了我一个满意的分数。用几种不同核的卷积层`AveragePooling2D`得到了更好的结果:3x3,5x5,7x7,11x11。在每一层之前增加了额外的 1x1 卷积层,以减少维数。这个组件有点类似于 [Inception 模块](https://www.cv-foundation.org/openaccess/content_cvpr_2015/papers/Szegedy_Going_Deeper_With_2015_CVPR_paper.pdf),尽管我克制自己不去构建一个深度网络。******
*   ********更大的内核:**我使用了更大的内核大小,因为更大的尺度特征可以很容易地从输入图像中提取出来(输入图像本身可以被视为具有 8 个过滤器的激活层——每个成分的二进制掩码基本上是一个过滤器)。******
*   ********信号融合:**我的简单实现只使用了一层非线性来合并两个特征集:处理过的二进制掩码(信号#1)和成分计数(信号#2)。尽管很幼稚,添加信号#2 为分数提供了一个很好的提升(交叉熵从`0.8`提高到`[0.7, 0.72]`)******
*   ********逻辑:**根据张量流,这是应用`tf.nn.softmax_cross_entropy_with_logits`计算批次损失的层。******

# ******阶段 3:t-SNE 的结果可视化******

******对于测试集结果可视化,我使用了 t-SNE,一种用于数据可视化的流形学习技术。t-SNE 使用非常显著的非凸损失函数来最小化低维嵌入数据点和原始高维数据的联合概率之间的 KL 散度。你绝对应该读一下[的原始论文](https://lvdmaaten.github.io/publications/papers/JMLR_2008.pdf),它信息量极大,写得很好。******

******为了可视化测试集分类结果,我推断了测试集图像,提取了分类器的 logits 层,并对该数据集应用了 t-SNE。虽然我应该用不同的困惑值来玩,但结果看起来还是不错的。动画 GIF:******

******![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b5cfbc7c44da88d0ce020093bfc8f23a.png)******

******t-SNE of the test set predictions by the classifier******

******虽然不完美,但这种方法确实有效。尽管如此,仍有许多需要改进的地方:******

*   ********更多数据。** ConvNets 需要大量数据,而我只有 139 个样本用于训练。像数据增强这样的技巧工作得很好(我使用了一个 [D4,或二面角,对称群](https://en.wikipedia.org/wiki/Dihedral_group)增强,产生了 2K+增强图像),但更多的真实数据对于良好的性能至关重要。******
*   ********合适的损失函数。**为了简单起见,我使用了开箱即用的分类交叉熵损失。我会切换到一个更合适的损失函数,一个更好地利用类内方差的函数。一开始一个好的选择可能是三重损失(详见 [FaceNet 论文](https://arxiv.org/pdf/1703.07737.pdf))。******
*   ********更好的整体分类器架构。**当前的分类器基本上是一个原型,其目标是解释输入的二进制掩码并将多个特征集组合成一个推理管道。******
*   ********更好的标注。我在手动图像标记(6 个质量等级)上相当马虎:分类器在十几个测试集图像上胜过了我自己!********

********超越与自省。**在实践中,企业没有数据、没有注释、没有清晰明确的技术任务需要完成的情况非常普遍(我们应该停止否认这一事实)。这是一件好事(否则,他们为什么需要你?):您的工作是拥有工具、足够多的多 GPU 硬件、业务和技术专业知识的组合、预训练的模型以及为业务带来价值所需的一切。******

******从小处着手:可以用乐高积木搭建的工作原型可以提高进一步对话的效率——作为一名数据科学家,你的工作就是向企业推荐这种方法。******

# ConvNets 系列。图像处理:行业工具

> 原文:<https://towardsdatascience.com/convnets-series-image-processing-tools-of-the-trade-36e168836f0c?source=collection_archive---------2----------------------->

# 简介和系列发布

我越是研究 [Udacity 的自动驾驶汽车项目](https://www.udacity.com/drive),卷积神经网络(ConvNets)这个话题对我来说似乎就越重要。原因很简单:在过去的几年里,在计算机视觉和机器人领域,convnets 已经变得无处不在。测绘,图像分类,分割,无人机和自动驾驶汽车的运动规划——许多处理图像(或图像序列)的问题都可以通过 convnets 高效解决。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/bae8fd7feda2a5af20b86870cd3a1cef.png)

MultiNet as an example of a convolutional network (three in one, actually). We are going to use it in one of next posts. Source: [https://arxiv.org/pdf/1612.07695.pdf](https://arxiv.org/pdf/1612.07695.pdf)

我想,你对神经网络的工作原理有很强的直觉。有大量关于这个主题的博客文章、课程和书籍,所以我不想重复:

*   [第六章:深度前馈网络](http://www.deeplearningbook.org/contents/mlp.html)——摘自 I.Goodfellow,Y.Bengio,A.Courville 所著的《深度学习》一书,强烈推荐。
*   [用于视觉识别的 CS231n 卷积神经网络](http://cs231n.github.io/) —费-李非和安德烈·卡帕西教授的著名斯坦福课程。动手和面向工程。卓越的课程材料质量。
*   [深度学习](https://youtu.be/PlhFWT7vAEw)——南多·德·弗雷塔斯的牛津课程。
*   [机器学习简介](https://www.udacity.com/course/intro-to-machine-learning--ud120)—uda city 的免费课程。一个非常温和和广泛的介绍 ML 的初学者。

只有一个建议:为了确保你理解了神经网络的基础知识,[用它们](http://playground.tensorflow.org/)和[构建一个](http://cs231n.github.io/neural-networks-case-study/)!

本系列没有重复基础知识,而是专注于**特定的神经网络架构** : STN(空间转换器网络)、IDSIA(用于交通标志分类的卷积网络)、NVIDIA 用于端到端自动驾驶的网络、用于道路和交通标志检测和分类的 MultiNet。我们开始吧!

**本帖的主题是图像预处理**。Convnets 不能被提供“任何”手边的数据,也不能被视为“自动”提取有用特征的黑匣子。预处理不好或没有预处理会使即使是顶尖的卷积网络也无法收敛或得分很低。因此,强烈建议所有网络进行图像预处理和增强(如果有的话)。在这篇文章中,我们为以后在神经网络中使用和重用打下了基础。

# 工具 1。通过可视化进行数据发现

在这篇和下一篇文章中,我们将使用 gt SRB——一个[德国交通标志识别基准数据集](http://benchmark.ini.rub.de/?section=gtsrb&subsection=dataset)。我们的任务是使用来自 GTSRB 数据集的标记数据来训练交通标志分类器。一般来说,当你有一个数据集时,最好的习惯方法是从中抽取数据样本,并建立一个训练、验证和/或测试集的数据分布直方图。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3192c6b556b0d28f10215908e58a984b.png)

GTSRB 数据集的基本统计如下:

Number of training examples = 34799Number of validation examples = 4410Number of testing examples = 12630Image data shape = (32, 32, 3)Number of classes = 43


在这个阶段,`matplotlib`是你最好的朋友。虽然你可以单独用`pyplot`构建良好的可视化效果,但是你可以用`matplotlib.gridspec.`将几个图表合并成一个

例如,您可以用这种方式初始化一个包含三个子图的空图表:

gs = gridspec.GridSpec(1, 3, wspace=0.25, hspace=0.1)
fig = plt.figure(figsize=(12,2))
ax1, ax2, ax3 = [plt.subplot(gs[:, i]) for i in range(3)]


Gridspec 是高度可定制的。例如,你可以像我在图表中所做的那样,为每个子情节设置不同的宽度。gridspec 中的轴可以被视为独立的图表,允许您创建非常复杂的绘图。

然后,一个单独的图表可以说明你的数据。这里有三个任务可以通过良好的绘图来解决:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/ce4493d303b20ae832ddccde5d2d8df3.png)

*   **样本图像可视化**:我们马上会看到很多太暗或太亮的图像。光照变化应该(也将会)得到解决:这是一种数据标准化。
*   **检查类别不平衡**:如果类别极度不平衡,您可能需要在批处理生成器中使用[过采样或欠采样方法](http://www.chioka.in/class-imbalance-problem/)。
*   比较训练、验证和测试组上的**数据分布是相似的。这可以通过查看上面的直方图来验证,但是您也可以使用 [Spearman 等级相关性](https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient)(通过`scipy`)。**

# 工具 2。scikit-image 的 IPython 并行

为了帮助网络融合,我们需要均衡图像的亮度,并(如 [LeCun 关于交通标志识别的论文](http://yann.lecun.com/exdb/publis/pdf/sermanet-ijcnn-11.pdf)中所建议的)将它们转换成灰度。这可以使用 OpenCV 来完成,但是 Python 的工具箱包含了一个很棒的 [scikit-image](http://scikit-image.org/) ( `skimage`)库,可以通过 pip 轻松安装(与自己编译 OpenCV 形成对比)。关键的见解是使用基于内核的 [CLAHE](https://en.wikipedia.org/wiki/Adaptive_histogram_equalization#Contrast_Limited_AHE) (对比度受限的自适应直方图归一化)方法来归一化图像的直方图:`skimage.exposure.equalize_adapthist`。

`skimage`逐个处理图像并利用单个 cpu 核心,这显然是低效的。为了并行化图像预处理,我们使用了 [IPython 并行](https://ipyparallel.readthedocs.io/en/latest/intro.html) ( `ipyparallel`)包。`ipyparallel`的好处之一是它的简单性:并行运行 CLAHE 只需要几行代码。首先,从您的 shell 启动一个控制器和引擎(假设您已经安装了`ipyparallel`):

$ ipcluster start


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/d1deb4f69b8e92b31931f0791cb60976.png)

One of the benefits of ipyparallel is its client interface which abstracts communication with engines, task scheduling, etc. Running parallel map is just trivial.

我们的并行化方法是最简单的:我们将数据集分成几批,并独立处理每一批。当所有的批次被处理后,我们将它们合并成一个单独的数据集。我的 CLAHE 批处理例程如下:

现在,转换函数已经准备好了,我们可以实现一段代码,将该函数应用于批量数据:

现在我们可以运行它了:

X_train: numpy array of (34799, 32, 32, 3) shape

y_train: a list of (34799,) shapeX_tr, y_tr = preprocess_equalize(X_train, y_train, bins=128)


现在,我们确实利用了系统的所有 cpu 内核(在我的例子中是 32 个),并获得了显著的性能提升。以下是预处理的示例结果:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/77d8a6ef1d01e3ba54ea26fae17700c8.png)

Grayscale and equalize the histogram

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/1d5b9d3e05ede531bf06bacf75e1c957.png)

Histogram equalization for RGB image (I used a different function for rc[:].map)

由于整个预处理管道现在只需要几十秒钟就可以运行,我们可以测试不同的`num_bins`值来了解这个论点:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/86f43f32d93e8e4dcb7f7b077e652975.png)

num_bins: 8, 32, 128, 256, 512

较大的`num_bins`值确实增加了图像的对比度,但也过度突出了背景,增加了图像的噪声。不同的箱也可以用于**对比度增强**,因为我们需要防止对背景特征的过度拟合。

最后,我们可以利用 IPython 的`%store` [魔法](https://ipython.org/ipython-doc/3/config/extensions/storemagic.html)来快速序列化我们的数据集以供进一步使用:

Same images, multiple bins (contrast augmentation)

%store X_tr_8
%store y_tr_8

%store X_tr_512
%store y_tr_512


# 工具 3。在线数据扩充

众所周知,增加更多的数据可以提高神经网络的泛化能力。在我们的例子中,我们可以通过使用旋转、翻转和仿射变换来变换我们所拥有的(数据扩充)来构建人工图像。虽然我们可以对整个数据集运行一次这个过程,保存结果并在以后使用它,但更好的方法是动态(在线)构建新图像,以便能够快速修改和迭代数据扩充的参数。

首先,让我们列出我们的转换。我们用`numpy`和`skimage`:

仿射变换增加数据集,同时保持图像标签不变。相反,旋转和翻转可以将一个交通标志转换成另一个。为了处理这个问题,我们可以为每个交通标志和它将被转换成的类别列出一个可用的转换列表:

A part of [the whole transformation table](https://gist.github.com/dnkirill/8aab1c5dbe0471795cdf93729a572d49). Values are class numbers (as in label_class) an image will take after transformation. Empty cell means that transformation is not available for that label.

请注意,上表中的转换名称与我们之前介绍的函数名称相匹配。这样做是为了动态添加更多的转换:

接下来,我们构建一个管道,将`augmentation_table.csv`中列出的所有可用函数应用于所有类:

很好。现在我们有两个数据集扩充例程:

*   `affine_transform`:没有旋转组件的可定制的剪切和缩放变换(不是很一致,因为旋转是仿射变换的一部分)。
*   `flips_rotations_augmentation`:基于随机旋转和增强 _table.csv 的图像变换,可以改变图像标签。

最后一步是将它们合并到一个增强的批处理生成器中:

当我们从这个批处理生成器采样时,我们得到了我们所需要的,对比度和位置数据增强:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/2c19689a6c0432b1132541f4f7c70df9.png)

Generated images via augmented_batch_generator

**注:**强化只在训练时需要。我们做预处理,但不增加验证或测试集。

之后,一个好主意可能是检查该批处理生成器中批处理的数据分布是否仍然合理(要么与原始数据相似,要么是专门针对过采样设计的)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/6abd6a30e69bacb8b9b6f20b407f028d.png)

Left: data distribution from augmented batch generator. Right: original train. As we see, values differ, but distributions are similar.

# 向神经网络迈进

在完成数据预处理、批处理生成器设置和数据集分析后,我们可以继续训练。我们将使用双卷积网络:STN(空间转换器网络)获取一批图像,专注于交通标志,去除背景,IDSIA 网络从 STN 提供的图像中识别交通标志。下一篇文章将专门讨论这些网络、培训、性能分析和演示。敬请期待,下期帖子再见!

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8f89a578469ee9ffc84a88a12ee2590a.png)

Left: original preprocessed image. Right: STN-transformed image which is fed to IDSIA network for classification.

# ConvNets 系列。空间变压器网络

> 原文:<https://towardsdatascience.com/convnets-series-spatial-transformer-networks-cff47565ae81?source=collection_archive---------0----------------------->

空间转换器是不同模块集合中的另一个乐高积木。它通过应用可学习的仿射变换然后进行插值来消除图像的空间不变性。STN 模块可以放在卷积神经网络(CNN)中,它主要靠自己工作。

这个项目的完整代码可以在 GitHub 上找到:【https://github.com/dnkirill/stn_idsia_convnet 

**为了对 STN 做什么有一些直觉,请看下面我的项目中的两个演示:**

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9ad6e8c4896a26fd942ba59c2166dbe1.png)

Left image: an original input image from traffic signs dataset. Right image: same image transformed by STN. **Spatial transformers learn what part of an image is the most important and scale or rotate the image to focus on this part.**

在本帖中,我们将回顾 STN 模块的内部工作,并将其与**一个对德国交通标志数据集**进行分类的卷积神经网络结合使用。我们将构建它们:STN 和分类器。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a4ce776ff576a71627f0618fddd70d2d.png)

Another example of STN learning and transformation. This is just the first epoch of training. It is clear how the STN learns the sign representation and focuses on the sign itself.

STN 检测甚至在更困难的情况下也能工作(例如,图像上的两个标志)。不过,最重要的是,STN 确实提高了分类器的准确性(在我的例子中是 IDSIA)。

# 空间变压器网络的绝对最小速成课程

卷积神经网络的问题在于它缺乏对输入变化的鲁棒性。这些变化包括比例、视点变化、背景混乱以及更多的变化。一些不变性可以通过池化操作来实现,池化操作只是对导致信息丢失的特征图进行下采样。

不幸的是,由于标准 2×2 池的小感受野,它仅在更靠近输出层的较深层中提供空间不变性。此外,池化不提供任何旋转或缩放不变性。凯文·扎克卡在他的帖子中对这个事实[提供了一个很好的解释。](https://kevinzakka.github.io/2017/01/18/stn-part2/)

使模型对这些变化稳健的基本且最常用的方法是像我们在[上一篇文章](https://medium.com/towards-data-science/convnets-series-image-processing-tools-of-the-trade-36e168836f0c)中所做的那样扩充数据集:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0a57446bd8f861c05504b544af5e0974.png)

Augmented images. In this post, we will use no augmentations at all.

这种方法没有错,但是我们可能希望开发一种更加智能和自动化的方法来准备图像。这种方法应该有助于分类器得出正确的、更确定的预测。这就是空间转换器网络或 STN 模块发挥作用的地方。**通俗地说,STN 是一种旋转或缩放输入图像或特征地图的机制,目的是聚焦在目标对象上,并消除旋转变化**。STNs 最显著的特征之一是它们的模块化(模块可以被注入到模型的任何部分)以及它们能够在不修改初始模型的情况下用单个反向传播算法进行训练。

下面是另一张图片,让你对 STN 有一个直观的认识:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/cf1ad92752b1aedfe24564c19a3749e1.png)

Cluttered MNIST example from the [original paper](http://papers.nips.cc/paper/5854-spatial-transformer-networks.pdf). Cluttered MNIST (left) original image, target object detected by STN (center), transformed image (right).

如果我们排除学习部分,STN 模块可以归结为以下过程:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/d82a74e6fcd88b2d2b8787e23ab92b6d.png)

Four steps of applying a STN transformation given that the transformation matrix 𝛳 is defined.

在下一节中,我们将更深入地探讨这一过程,并更仔细地观察转换的每一步。

# STN:转型的步骤

**第一步。**定义描述线性变换本身的变换矩阵𝛳(θ)。θ可定义如下:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/88dee309540adf01f6a6850837cbd126.png)

Affine transformation matrix theta.

不同的矩阵对应不同的变换。我们最感兴趣的是这四个:

*   **身份**(输出相同的图像)。这是θ的初始值。在这种情况下,θ矩阵是对角的:
    `theta = np.array([[1.0, 0, 0], [0, 1.0, 0]])`
*   **旋转**(逆时针旋转 45°)。`cos(45º) = 1/sqrt(2) ≈ 0.7`:
    
*   **放大。**
    (放大 2 倍)放大中心:
    `theta = np.array([[0.5, 0, 0], [0, 0.5, 0]])`
*   **缩小。**
    缩小中心(放大 2 倍):
    `theta = np.array([[2.0, 0, 0], [0, 2.0, 0]])`

**第二步。**我们不是将变换直接应用于初始图像,而是生成一个与初始图像大小相同的采样网格`U`。网格是覆盖整个输入图像空间的一组索引`(x_t, y_t)`。它不包含任何颜色信息。这在代码中有更好的解释:

由于张量流的特殊性,`x_t`和`y_t`赋值可能看起来很麻烦。Numpy 翻译做得更好:

`x_t, y_t = np.meshgrid(np.linspace(-1, 1, width), np.linspace(-1, 1, height))`

**第三步。**将线性变换矩阵应用于我们初始化的 meshgrid,以获得新的一组采样点。变换网格的每个点可以定义为θ与坐标`(x_t, y_t)`和偏置项的矩阵向量乘积:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8efba3341d26b2054a636a36035c0fa9.png)

**第四步。**使用初始特征图、转换网格(见步骤 3)和您选择的可微分插值函数(如双线性函数)产生采样输出`V`。插值是必需的,因为我们需要将采样的结果(像素的分数)映射到像素值(整数)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/19f71a571fa6f4a6b13954683025d762.png)

Sampling and interpolation

**学习问题。**如果我们以某种方式为每个输入图像提供正确的θ,我们可以开始使用我们刚刚描述的过程。事实上,我们希望从数据中推导出θ,我们确实可以做到!**首先,**我们需要确保交通标志分类器的损失可以反向传播到采样器并通过采样器。**其次,**我们定义了关于`U`和`G`(网格)的梯度:这就是插值函数必须可微或次可微的原因。第三,我们计算`x`和`y`相对于θ的偏导数。[如果真的好奇的话,梯度计算见原文。](http://papers.nips.cc/paper/5854-spatial-transformer-networks.pdf)

最后,我们定义了一个**定位神经网络**(回归器),其唯一的任务是学习,然后使用我们通过采样器反向传播的损失为给定图像产生正确的θ。

**这种方法的神奇之处在于,我们得到了一个可微分的带记忆(通过可学习的权重)的自包含模块,它可以放在 CNN 的任何部分。**

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/40bd2e3a11688a12c06726079e7eef1e.png)

See how 𝛳 changes while the STN learns the representation of the main object (a traffic sign) in images .

简而言之,这就是 STN。以下是最初论文中的 STN 方案:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5e133956e2f454820ef2c1cd66e26f63.png)

Spatial Transformer with the locnet from the [original paper.](http://papers.nips.cc/paper/5854-spatial-transformer-networks.pdf)

如你所见,我们已经涵盖了 STN 的所有构建模块:本地化网络、meshgrid 生成器和采样器。在下一部分中,我们将训练一个张量流分类器,它将 STN 作为其图形的一部分。

# TensorFlow 模型概述

这个模型的代码太长了,无法在这篇文章中一一列出,但是可以在 github 资源库中免费获得:
[https://github.com/dnkirill/stn_idsia_convnet](https://github.com/dnkirill/stn_idsia_convnet)

我更倾向于关注一些重要的代码和模型训练。

**首先**,由于最终任务是对交通标志进行分类,我们需要定义和训练分类器本身。选择很多:从 LeNet 到你能想象到的任何新的顶级网络。在这个项目中,受 [Moodstocks 对 STN](https://github.com/Moodstocks/gtsrb.torch) (在 Torch 中实现)的研究的启发,我使用了一个类似 IDSIA 的网络。

**第二个**,我们定义并训练 STN 模块,该模块将一幅原始图像作为输入,用采样器对其进行变换,并产生另一幅图像(或一批图像)。该图像然后被分类器用作输入。请注意,STN 可以很容易地从 DAG 中分离出来,并由原始图像批处理生成器替换。这种被放置在 CNN 的任何部分的能力是 STN 的主要优点之一。

以下是组合网络的概述:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b743995e2cd607a7efe392559f410f26.png)

Spatial transformer network outputs images to IDSIA traffic signs classifier and trains using a single backprop algorithm.

DAG 的这一部分使用一批原始图像作为输入,通过 STN 模块对它们进行转换,将转换后的数据传输到分类器(IDSIA)并输出 logits:

假设我们有计算 logits 的方法(STN + IDSIA 网络),下一步是计算损失(我们使用交叉熵或 logloss 损失函数作为分类问题的默认选择):

接下来是定义更多的 ops —我们基本上初始化 TensorFlow 的 DAG 的 ops。我们需要选择一个优化器和训练 op,将损失反向传播回输入层:

我以更高的学习率(0.02)开始:这有助于将更强的梯度信息传播到 STN 的定位网络,该定位网络位于整个网络的“前”层,否则可能训练非常慢(由于[消失梯度问题](https://en.wikipedia.org/wiki/Vanishing_gradient_problem))。学习率的初始值越小,网络就越难放大到更小的交通标志。

[Adam optimizer](http://ruder.io/optimizing-gradient-descent/index.html#adam) (结合自适应学习率并保持过去梯度的指数衰减平均值)与学习率的分段常数一起使用。学习率衰减使用`boundaries`(批次数量)切换到较小的学习率。

使用一个非常简单的声明将输出 logits(网络的前向通道)的 DAG 部分添加到图中:

这个简单的声明展开了整个网络,即 STN + IDSIA。下一节将讨论它们。

# IDSIA 分类器网络

我的灵感来自 Moodstocks 的研究和来自 IDSIA 瑞士人工智能集团的[初始论文](http://www.idsia.ch/~juergen/nn2012traffic.pdf),其中他们使用了一组 CNN 来击败这个数据集的最先进的分数。我从系综中提取了单个网络架构的蓝图,并在 TensorFlow 中用我自己的术语定义了它。分类器的配置如下所示:

*   第 1 层:卷积(批量归一化,relu,dropout)。**内核** : 7x7,100 个滤镜。**输入** : 32x32x1(一批 256 个)。**输出** : 32x32x100。
*   第 2 层:最大池化。**输入** : 32x32x100。**输出** : 16x16x100。
*   第三层:卷积(批量归一化,relu,dropout)。**内核** : 5x5,150 滤镜。**输入** : 16x16x100(一批 256)。**输出** : 16x16x150。
*   第 4 层:最大池化。**输入** : 16x16x150。**输出** : 8x8x150。
*   第五层:卷积(批量归一化,relu,dropout)。**内核** : 5x5,250 滤镜。**输入** : 16x16x100(一批 256)。**输出** : 16x16x150。
*   第 6 层:最大池化。**输入** : 8x8x250。**输出** : 4x4x250。
*   第 7 层:多比例要素的附加池。conv 层 1、2 和 3 的内核大小分别为 8、4 和 2。
*   第 8 层:多尺度特征的展平和拼接。**输入**:2x2x 100;2x2x1502x2x250。**输出**:全连通层的特征向量 400+600+1000 = 2000。
*   第 9 层:全连接(批量归一化,relu,dropout)。**输入** : 2000 个特征(一批 256 个)。300 个神经元。
*   第 10 层:Logits 层(批量标准化)。**输入** : 300 个特征。输出:logit(43 类)。

下图可以说明这一点:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e30e2bcb1560760d1dcdb313e1ad13a3.png)

如您所见,每个卷积层的激活随后被合并,并针对全连接层进行扁平化。这是**多尺度特征**的例子,它们**确实**提高了最终得分。

正如我们前面所讨论的,`conv1`的输入来自 STN 的输出。

# TensorFlow 中的空间转换器

TensorFlow models zoo 包含一个 STN 的实现,它将用于我们的模型:[https://github . com/tensor flow/models/tree/master/transformer](https://github.com/tensorflow/models/tree/master/transformer)。

我们的任务是定义和训练本地化网络,为`transformer`提供 theta,并将 STN 模块注入 TensorFlow 的 DAG。`transformer`生成网格并提供变换和插值功能。

本地化网络的配置如下:

**loc net 的卷积层数:**

*   第 1 层:最大池化。**输入** : 32x32x1。**输出** : 16x16x1。
*   第二层:卷积(relu,批量归一化)。**内核** : 5x5,100 个滤镜。**输入** : 16x16x1(一批 256 个)。**输出** : 16x16x100。
*   第 3 层:最大池化。**输入** : 16x16x100。**输出** : 8x8x100。
*   第四层:卷积(批量归一化,relu)。**内核** : 5x5,200 滤镜。**输入** : 8x8x100(一批 256 个)。**输出** : 8x8x200。
*   第 5 层:最大池化。输入:8x8x200。输出:4x4x200。
*   第 6 层:多比例要素的附加池。conv 层 1 和 2 的内核大小分别为 4 和 2。
*   第 7 层:多尺度特征的展平和拼接。**输入**:2x2x 100;2x2x200。**输出**:全连通层的特征向量 400+800 = 1200。

**全连接 LocNet:**

*   第 8 层:全连接(批量归一化,relu,dropout)。**输入** : 1200 个特征(一批 256 个)。100 个神经元。
*   第 9 层:Logits 定义仿射变换的 2×3 矩阵 theta。权重被初始化为零,偏差被初始化为恒等式变换:`[[1.0, 0, 0], [0, 1.0, 0]]`。
*   第 10 层:变压器:网格生成器和采样器。该逻辑在`spatial_transformer.py`中实现。此图层输出与原始图层(32x32x1)尺寸相同的变换图像,并对其应用仿射变换(例如,放大或旋转的图像)。

locnet 的卷积层的结构类似于 IDSIA(尽管 locnet 由 2 个 conv 层而不是 3 个组成,并且我们首先对输入图像进行下采样)。完全连接层的图示更值得注意:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e260020aef36bd449b8ee243b04ae54f.png)

# 培训和结果

带有 STN 模块的 CNN 的问题是需要监控两个网络的过度匹配。这使得训练变得棘手和不稳定。另一方面,增加一点增强数据(尤其是增强亮度)确实可以避免两个网络过度拟合。无论如何,利大于弊:我们在**没有任何增强的情况下得到很好的结果**,STN+IDSIA 比没有这个模块的 IDSIA 性能好 0.5–1%。

以下参数用于训练:

即使仅仅过了 10 个时期,我们也能在验证集上得到`accuracy = 99.3`。CNN 仍然过拟合,但是过拟合的影响可以通过图像增强来减少。事实上,通过添加额外的扩充,我在 10 个时期后得到了验证集上的`accuracy = 99.6`(尽管训练时间显著增加)。

下面是训练的结果(`idsia_1`是单个 IDSIA 网络,`idsia_stn`是 STN+IDSIA)。准确度是德国交通标志数据集的整体验证准确度,而不是 STN:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5e8e6b38db11cc1779a5504bdb1d8abb.png)

STN+IDSIA 优于单个 IDSIA 网络,尽管它需要更多的时间来训练。请注意,上图中的认证准确度是按批次计算的,而不是按整个认证集计算的。

最后,下面是 STN 转换器训练后的输出示例:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0f934bcaa155482a64c468a90b79719d.png)

STN 确实抓住了图像的本质,并专注于交通标志,而不是背景或其他特征。

**最后,让我们回顾一下:**

*   STN 是一个可微分的模块,可以注入到卷积神经网络中。默认选择是将它放在输入层的正“后”,使其学习最佳变换矩阵 theta,从而最小化主分类器的损失函数(在我们的例子中,这是 IDSIA)。
*   STN 的采样器将仿射变换应用于输入图像(或特征地图)。
*   STNs 可以被视为图像增强的替代方案,图像增强是 CNN 实现空间不变性的默认方式。
*   向 CNN 添加一个或多个 stn 会使训练更加困难和不稳定:现在你不得不监控两个(而不是一个)网络的过度适应。这似乎是为什么 stn 还没有被广泛使用的原因。
*   用一些数据增强(特别是光照条件增强)训练的 stn 表现更好,并且不会过度拟合。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/42cb31e89ef7940c94004eac354ed203.png)

# 卷积:探索一个熟悉的算子的深层根源

> 原文:<https://towardsdatascience.com/convolution-a-journey-through-a-familiar-operators-deeper-roots-2e3311f23379?source=collection_archive---------8----------------------->

在现代机器学习的世界中,卷积算子占据着奇怪的位置:它对任何一个读过 2012 年以来的神经网络论文的人来说都非常熟悉,同时也是一个对其更深层次的数学基础往往知之甚少的对象。在音频处理环境中,您可能会听到它被描述为信号平滑器。在卷积网络中,它聚集来自附近像素的信息,也被描述为模式匹配过滤器,根据特定的局部像素模式更强烈地激活。从表面上看,卷积的所有这些不同的概念方面是如何植根于一个共享的数学现实的,这并不明显。

将所有这些解释拼凑成一个共享的理解网络的过程让人想起最终*真的看着*你每天经过的建筑上的一幅壁画,却发现它有着你以前从未见过的深刻内涵。从表面上看,这一理论的大部分可能与从业者的工作无关,但我认为,对我们日常使用的网络回旋的知识谱系有一个更坚实的理解,可以让我们从信心的基础上参与这个主题的文学,而不是困惑。

# 最好的起点

我们的故事不是从卷积进入应用科学领域开始的,而是从它下面的简单数学定义开始的。我知道,对于那些熟悉基于滤波器的卷积的人来说,这种框架可能是新的和陌生的,但请坚持下去,我将尽最大努力最终将所有的点连接起来。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a9502ae4cd33a1c27d800c5018f765df.png)

在上式中,f 和 g 都是作用于相同输入域的函数。在概率的背景下,你可以把它们框定为密度函数;在音频处理中,它们可能是波形;但是,从根本上说,我们可以把它看作是一些通用函数。当你将两个函数卷积在一起时,卷积本身就是一个函数,因为我们可以计算卷积在特定点 t 的值,就像我们可以计算一个函数一样。

为了遍历这里发生的情况,为了计算 f 和 g 在 t 点的卷积,我们对负无穷和正无穷之间的所有τ值进行积分,并且在每一点,将 f(x)在τ位置的值乘以 g(x)在 t—τ的值,即计算卷积的点与积分中给定点的τ之间的差。

乍一看,这个计算似乎是任意的:很容易机械地理解正在计算的内容,但是很难凭直觉理解为什么这是一个有用的操作。为了更清楚地说明它的用途,我将从几个不同但相互关联的角度来研究这个操作。

# **卷积作为函数平滑**

我发现考虑卷积的一个有用的方法是类比核密度估计。在 KDE,你选择某个核函数——也许是高斯函数——并以数据集中的每一点为中心,将该核函数的副本相加。在许多数据点密集地彼此靠近的情况下,这些函数副本将会增加;最终,这个过程会产生一个概率密度函数的经验近似值。为了这个类比的目的,重要的事情是内核在数据点周围充当平滑器的方式。如果我们只是使用一个简单的直方图,并在每个观察数据点的位置直接添加一个质量单位,我们的结果将会非常不连贯和不连续,特别是在小样本量的情况下。通过使用将质量分散到附近点的核,我们表达了对光滑函数的偏好,利用了自然界中许多潜在函数都是光滑的直觉。

在卷积中,我们不是平滑由数据点的经验分布创建的函数,而是采用更一般的方法,这允许我们平滑任何函数 f(x)。但是我们使用类似的方法:我们取某个核函数 g(x ),在积分中的每一点放置一个 g(x)的副本,放大——也就是说,乘以——f(x)在该点的值。

上图显示了这种效果的可视化效果,摘自[对卷积](http://bmia.bmt.tue.nl/Education/Courses/FEV/book/pdf/90%20Appendix%20B%20-%20The%20concept%20of%20convolution.pdf)的出色总结。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/7c19f72c8d8835c0ac3fb9a32cedfa1f.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/643fac340947d550d15570967150de81.png)

上面的图显示了原始 f(x),即我们想要平滑的噪声信号。左下方显示了“内核加权”过程,在这里,高斯函数被放置在每个点的中心,并通过该点的 f(x)值按比例放大。*【题外话:这在技术上显示了一个有限卷积,其中你对一组有限的缩放核求和,每个核以沿着函数的一组有限的采样点中的一个为中心,但直觉转移到更难可视化的无限情况,在这种情况下,你对函数进行真正的积分,而不仅仅是对采样点求和】*。最后,右下方的图显示了当你对所有这些比例核求和时得到的结果:( f*g)(x)的卷积图。

# **卷积作为局部化信息的聚合**

一个完全不同的视角——使我们更接近于在神经网络中使用卷积的方式——是卷积作为一种信息聚合,但从特定点的角度进行聚合:卷积被评估的点。(为了简洁起见,我将这个点称为“输出点”,积分所经过的点称为“输入点”)输出点想要汇总关于函数的整个域中 f(x)的值的信息,但是它想要根据一些特定的规则来这样做。也许它只关心 f 在距离它一个单位的点上的值,而不需要知道那个窗口之外的点。也许它更关心空间中离自己更近的点,但它关心的程度会平稳衰减,而不是像第一个例子那样,在某个固定窗口之外下降到零。或者,也许它最在乎的是离它很远的点。所有这些不同种类的聚合都可以归入卷积的框架中,它们通过函数 g(x)来表示。

从数学的角度来看,卷积可以被看作是计算 f(x)的值的加权和,并且这样做的方式是每个 x 的贡献由其与输出点 t 之间的距离来确定。更准确地说,权重是通过询问“如果有一个以每个点 x 为中心的 g(x)的副本,如果我们在输出点 t 对其求值,该复制函数的值会是多少”来确定的。

为了形象化这一点,看看下面的图。在这个例子中,我们使用 g(x) = x,想象我们如何计算 x = -2 的加权和的权重。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/38f6d1fd3e9c3b8b94f60dd651dbf58b.png)

橙色曲线是 g(x),但以 x=1 为中心,它在 x=-2 的值是 9。绿色和紫色曲线分别表示以 x=2 和 x=3 为中心的 g(x)。如果我们假设 f 是一个只在 1、2 和 3 取非零值的函数,我们可以计算(f * g)(-1)如下: **9*f(1) + 16*f(2) + 25*f(3)**

看上面这张图,有了 g(x)的多个重叠副本,信息聚合框架和 KDE 框架之间的联系很容易。当我们把注意力集中在一个特定的输入点上时,每个点的 g(x)的副本都在回答“来自这个点的 f(x)信息将如何被传播出去”这个问题。当我们聚焦一个特定的输出点时,我们在问“在这个输出点上,其他点对 f(x)的聚合的贡献有多强”。前一部分的多拷贝图上的每条垂直线对应于给定 x 处的卷积,读取该线与每个 g(x)拷贝的交点,得到 f(x)在 x 处的权重,该拷贝位于 x 的中心。

# 以一个混乱点为中心

将卷积视为信息聚合器让我们更接近它们在神经网络中扮演的角色,在神经网络中,它们在某个点周围的局部区域中总结下层的行为。然而,仍然存在两个有意义的差距。

第一个事实是,乍一看,图像卷积滤波器似乎与本文迄今为止使用的示例在结构上非常不同,因为滤波器是 2D 和离散的,而示例是 1D 和连续的。但是,在实践中,这些差异更多的是装饰性的,而不是根本性的:简单的情况是,在图像上,f(x)和 g(x)是在 2D 空间(x_1,x_2)上定义和索引的,并且该空间被分块到函数值不变的离散仓中。

关于从传统卷积到网络卷积的跳跃,实际上困难和不直观的是,当我们看到局部聚集在神经网络上下文中发生时,我们通常将它描述为通过以聚集点为中心的加权核**发生,**根据该核从周围环境中提取信息。网络中的卷积滤波器由输出点(以及输出点本身)周围所有输入点的权重组成。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/11e6089927b445ba7b53c4a9f2635c47.png)

You’ve probably seen this image before, or something very like this

然而,正如你可能还记得的,在这篇文章前面的讨论中,传统的数学卷积实际上并不把它的 g(x)权重核放在输出点的中心。在卷积公式中,g(x)的副本位于每个输入点的中心,并且该副本在给定输出处的值决定了该输入点的权重。因此,令人困惑的是,我们在网络卷积中所知的**滤波器核与卷积公式中的 g(x)不是一回事。**如果我们想使用卷积公式应用网络过滤器,我们必须翻转它(在 1D 的情况下)或对角翻转它(在 2D 的情况下)。反过来,如果我们想从卷积积分中提取一个 g(x)并将其用作输出中心滤波器,那么该滤波器就是 g(-x)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/78a1d4c9debb6f3a3a1ebb605c0c5fdf.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5245df6ed050a693a7d47583131c5302.png)

在内核对称的情况下,这并不重要,但在典型的卷积滤波器中,对称并非如此:“在中心的右侧,向下一个”的权重不同于“在中心的左侧,向上一个”的权重,因此,如果您简单地使用以输出为中心的滤波器,并尝试在以输入点为中心的适当卷积框架中使用它,您将获得不同的权重。您可以在上面的可视化中更清楚地看到这一点,其中我们使用以输出为中心的 g(x)内核版本来为每个输入生成权重,然后使用以输入为中心的版本,并且可以看到,您不能在一个过程中使用相同的内核,而在另一个过程中使用相同的内核来获得相同的结果。这个事实——你不能直接把以输出为中心的核作为 g(x)插入卷积方程——是我对卷积最大的持续困惑,因为它似乎在做几乎相同的事情,而且因为如此多的解释使用对称核,所以区别并不突出。

# 卷积作为模式匹配器

如果你已经做到了这一步,你现在有希望更好地理解我们所知道和喜爱的滚动重量过滤器是如何连接到一个看起来模糊的积分的——尽管不是直接插入——的。最后一个难题是理解权重过滤器如何作为模式匹配器工作,这是卷积过滤器通常被描述的方式。为什么一个点周围的 f(x)值越像过滤器权重(此处 f(x)是像素值或来自较低网络层的值),该点的卷积值就越高?

简单的答案是,离散卷积相当于在滤波器权重和滤波器下的值之间取点积,从几何角度来说,点积衡量向量相似性。以输出为中心的卷积的工作原理是取一个权重向量和一个输入值向量,然后将对齐的条目相乘并求和:这就是计算点积。当然,您可以通过增加一个或两个向量的大小来增加点积的值,但是对于固定的大小,当向量指向相同的方向时,或者在我们的情况下,当像素值中的强度模式与权重过滤器中的高权重和低权重匹配时,点积的最大值就会达到。

# 剩余问题

即使我到了一个我可以舒服地发表博客的地方,我还是经常会有一些我直觉上不太理解的问题,而这篇文章也不例外。对我来说,这里最突出的问题是卷积算子和傅里叶变换之间的联系。傅里叶变换的众多名声之一是它对角化了卷积算子:也就是说,如果你把你的基转移到傅里叶变换的指数集,卷积两个函数就相当于在这个基上乘以它们。虽然我可以大声说出这些事实,但我还真不明白为什么它们是真的。

# 用简单图像解密卷积神经网络

> 原文:<https://towardsdatascience.com/convolution-neural-network-decryption-e323fd18c33?source=collection_archive---------12----------------------->

本文试图通过简单图像的可视化来解释卷积神经网络。使用非常基本的对象,如垂直线和水平线。避免了来自 ImageNet 数据集的复杂图像,因为可视化不容易解释。

当我在 2017 年开始为一个计算机视觉项目进行深度学习时,我遇到的第一个教程是像许多其他人一样使用卷积神经网络的猫/狗分类和 MNIST 例子。尽管这些例子让我们大致了解了 CNN 的工作方式及其令人难以置信的效率,但要真正理解其内部工作方式却很困难。我看到有很多关于使用不同的框架从头开始构建 CNN 的文章,也有关于各种数据集构建分类器的文章。毫无疑问,现在任何人都可以使用许多著名的框架在 30 分钟内建立一个非常好的图像分类模型。

我不打算进入梯度下降和反向传播的数学,因为已经有足够的资源可用。我们中的许多人确实理解数学,但仍然觉得我们错过了一些东西。自从深度神经网络出现以来,许多人都有同样的感觉,并一直试图找出理解黑盒真正学习什么以及如何更好地调整它们的方法。

许多人创造了许多可视化技术来了解 CNN 所学的内容,我相信你们中的许多人会遇到许多奇怪的彩色图像,这些图像会给我们带来很少的概念,甚至更糟,让我们觉得我们根本不了解任何东西,就像下面的这些:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9aa1242e9d5556df309f17d37a120e7a.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e0a61587f124a09d407f92ed04dba529.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/4a844337238110896c516eeaeb6c817e.png)

我觉得这主要是因为我们实验的所有例子都是高层次的图像。对于没有计算机视觉经验的人来说,猫/狗、ImageNet 甚至 MNIST 数据集都是太复杂的问题。

所以,在这里我将用一个非常简单的水平线和垂直线的数据集来解释 CNN。我在每个类中生成了大约 600 张大小为 50x50 的图像,如下所示,我们将使用 CNN 对它们进行分类:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0e09e999ff4b5f1609125321c514df36.png)

现在想象一下,给你一个任务,让你从头开始编写一个算法来对图像进行分类。对于任何有计算机视觉背景的人来说,这都是一个非常简单的任务,因为我们需要做的只是实现一个基本的边缘检测算法。现在有一些算法已经用于边缘检测很多年了。

我将在这里演示 Prewitt 操作符,但也可以尝试其他算法。Prewitt 算子用于图像的边缘检测。它检测两种类型的边缘:

*   水平边缘
*   垂直边缘

通过使用图像的相应像素强度之间的差异来计算边缘。从数学上来说,操作者使用两个 3×3 的核来计算导数的近似值,这两个核与原始图像进行卷积(参见 GIF 以获得基本概念),一个用于水平变化,另一个用于垂直变化。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9597b5abf46e1f4591f2696f675118e5.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/eafc6d146a76415c1082217f6f90daf5.png)

其中*表示 1 维卷积运算。Gx 和 Gy 将分别找到垂直边和水平边。它只是像一阶导数一样工作,并计算边缘区域中像素强度的差异。由于中间列为零,它不包括图像的原始值,而是计算该边缘周围的左右(或上下)像素值的差。这增加了边缘强度,并且与原始图像相比,它变得增强了。

现在让我们回到 CNN,这里我们有多层卷积,最大池,ReLU,Dropout 等等。在许多层中,卷积层是具有可训练参数的层之一,这些参数是内核。在数据科学社区中,内核也被称为权重。

我在一个相当简单的 CNN 模型上训练了我的数据集,如下所示:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b184966e82489677bf8d206fd2a8d0c5.png)

我使用 7x7 内核进行卷积。从上述模型可以看出,我在第一层中使用了 8 个内核,因此有 400 个可训练参数,计算如下:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9fa9f4d8b145c103ffd20f83a9faf616.png)

我已经保存了每个时期所有层的权重,并可视化了训练的进度。内核值的范围在 0 到 1 之间,可视化是使用 matplotlib 的颜色映射创建的,因此颜色映射不会准确地再现实际值,但它会给我们一个关于值的分布的好主意。下面是每个训练期后内核的 GIF 图。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3ef4311c519095dd61388d4cf74c2ad1.png)

Kernel visualization during training

7x7 内核如下图所示,当时它们被**随机初始化**,然后在数据集上训练相同的内核**。**

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/4484af852972591f57d23f7b1bab8e12.png)

比较训练前后的内核,我们将不能非常清楚地理解每个内核已经学习了什么。这可以通过在图像上卷积内核并通过 ReLU 和 Maxpooling 层传递图像来更好地理解。为了更容易理解,我选择了两个内核,它们对于水平和垂直边缘都被很好地激活了。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/916f9299fa227fd2b55656f4bec416a5.png)

当在输入图像上卷积时,训练前的核 5 和 8 具有非常模糊的输出,并且没有清晰的激活。但是在训练之后,内核 5 很好地激活了垂直线,而不是水平线。更具体地说,它从左向右搜索边缘。如果你仔细观察内核 5,你会发现内核的左边更接近于 0,右边更接近于 1。在内核 8 中可以看到类似的模式,水平线被激活。

因此,从上面的图像中,我们可以了解到,通过反向传播,该模型已经学会了通过理解数据集来自己提出类似 Prewitt 算子核的东西。这里唯一的区别是有很多内核,每个内核都学到了一些东西(除了少数死内核)。

现在,如果我们进入下一层,与边缘检测相比,内核开始学习更高级别的特征,例如低级和高级模式识别。但问题是,因为即使在小模型中也存在大量可训练参数,所以很难将更高级的特征可视化。我这里不包括可视化,因为将会有大量的数据,并且很难理解。我将在另一篇文章中写它。

下面,我将我的模型可视化,在一个输入的水平线图像上,从头到尾,只是为了给出一个图像在下一层如何进展的概念:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0f679adab9cbbe04c0b2b62fc0fb9385.png)

我希望这篇文章能帮助你更好地理解 CNN。请在下面分享您的反馈或疑问。

# 卷积神经网络

> 原文:<https://towardsdatascience.com/convolution-neural-network-e9b864ac1e6c?source=collection_archive---------4----------------------->

## 对于初学者

# 介绍

卷积层用于从输入训练样本中提取特征。每个卷积图层都有一组有助于要素提取的过滤器。一般来说,随着 CNN 模型的深度增加,通过卷积层学习的特征的复杂性增加。例如,第一个卷积层捕获简单特征,而最后一个卷积层捕获训练样本的复杂特征。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/12d4f54ad07889d12291c4bde2475c3c.png)

通过考虑数据样本部分的卷积来提取特征。过滤器每次遍历的数据部分的数量与步长和填充值成比例。数据样本在卷积之前可以/可以不进行零填充。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b4eeed70a559079f9e2ad09ba7c5736f.png)

卷积输出然后通过一个称为 ReLU(整流线性单元)的激活单元。这个单元将数据转换成非线性形式。只有当卷积输出为负时,ReLU 的输出才会被削波为零。

由于消失梯度问题,Sigmoid 单元不是优选的激活单元。如果 CNN 的深度很大,那么当在输入层发现的梯度穿过输出层时,它的值会大大减小。这导致网络的总输出变化很小。这反过来导致收敛缓慢/没有收敛。为了避免这种情况,最好使用 ReLU。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/231ea0fae3411766523ad9411bd60711.png)

ReLU 的输出然后通过一个池层。合并图层移除卷积过程中捕获的任何冗余要素。因此,这一层减少了数据样本的大小。池化背后的原理是它假设图像像素的相邻值几乎相同。使用四个相邻像素值的平均值/最小值/最大值来进行合并。一般来说,在 2*2 过滤器的帮助下,输入图像的大小减少了一半。输入数据在汇集之前可能会/可能不会进行零填充。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/87a46f8f0ff05c7b9583080068b1722f.png)

按照 CNN 模型的设计,重复这种连续通过卷积和汇集层传递数据的过程。出于学习目的,这个过程重复 2-4 次。来自连续卷积和汇集层的输出然后通过多层神经网络。这里,每个神经元单元充当携带关于单元的信息的特征图。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/bbec227cb3be7e620b5740e782775d12.png)

丢弃层用于通过使 CNN 模型对噪声鲁棒来减少过拟合。这些层通常被引入两个完全连接的神经网络层之间。它们暂时切断两个完全连接的层之间的部分数据流。这相当于让模型在存在噪声的情况下学习准确分类。因此,减少了由于过拟合而导致的模型分类不准确的机会。

使用 SoftMax 函数计算 CNN 模型的输出。SoftMax 是首选,因为它给出了不同类别的输出概率,而不是在 sigmoid 输出的情况下> = 0.5。使用 SoftMax 函数根据类的最高概率查找输出结果可提高输出的准确性。

交叉熵用于衡量系统的性能。它们是在 SoftMax 函数的帮助下计算出来的。这里的优点是 SoftMax 输出是对应于我们知道输出所属的类的元素的踪迹。这通常节省了计算时间。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9d39f208c825c0c709f797cef3cdcd81.png)

# CNN 层概述

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/40356b328fc11157f66705f775c067e8.png)



# 特征提取— MNIST

本节让读者直观地了解如何将图像与核进行卷积,从而从输入图像中提取特征。我们考虑一个数字为 2 的图像,在每个示例中,该图像与翻转了 90 度的相同 3*3 滤波器进行卷积。

在我们的实验中,我们假设滤波器的阈值为+2。黑色像素表示为 0,白色像素表示为 1。卷积的结果如下所示。

1.

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a52d0cda908ee48c7f4358ffcec9875f.png)

卷积的输出表明该滤波器善于检测内部边缘。这通过沿着对角线的图像中的明显边缘来显示。使用的 3*3 滤波器值为[[2,-1,-1],[-1,2,-1],[-1,-1,2]]。因此,当卷积输出大于定义的阈值 2 时,我们认为该卷积的输出为 1,否则为 0。

2.

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5ebcf0eeb2124ec099fc72987a6c8bd8.png)

卷积的输出表明滤波器在对角线边缘是坏的。这通过沿着对角线的图像中的明显边缘来显示。使用的 3*3 滤波器值为[[-1,-1,2],[-1,2,-1],[2,-1,-1]]。因此,当卷积输出大于定义的阈值 2 时,我们认为该卷积的输出为 1,否则为 0。

3.

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/99e6cab6a34686e2edf303d0e30a527c.png)

卷积的输出表明该滤波器擅长检测水平边缘。这通过沿着水平面的图像中的明显边缘来显示。使用的 3*3 滤波器值为[[-1,2,-1],[-1,2,-1],[-1,2,-1]]。因此,当卷积输出大于定义的阈值 2 时,我们认为该卷积的输出为 1,否则为 0。

4.

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3d21d355466296a96093b062b204c40d.png)

卷积的输出表示滤波器擅长检测垂直边缘。这通过沿着垂直平面的图像中的明显边缘来显示。使用的 3*3 滤波器值为[[-1,2,-1],[-1,2,-1],[-1,2,-1]]。因此,当卷积输出大于定义的阈值 2 时,我们认为该卷积的输出为 1,否则为 0。

源代码

[](https://github.com/shree6791/Deep-Learning/blob/master/CNN/MNIST/keras/src/Feature%20Extraction.ipynb) [## shree 6791/深度学习

### 深度学习——这个知识库由 Shreenidhi Sudhakar 实施的深度学习项目组成。

github.com](https://github.com/shree6791/Deep-Learning/blob/master/CNN/MNIST/keras/src/Feature%20Extraction.ipynb)

# 自然语言推理的卷积注意模型

> 原文:<https://towardsdatascience.com/convolutional-attention-model-for-natural-language-inference-a754834c0d83?source=collection_archive---------2----------------------->

在这篇文章中,我想向你展示一个我在 Quora 问题配对竞赛中使用的模型。首先,我将描述一个用于自然语言推理的可分解注意力模型( [Parikh 等人,2016](https://arxiv.org/pdf/1606.01933.pdf) ),然后用卷积层扩展它,以提高损失和分类精度。出于本文的目的,我将使用斯坦福 NLI 语料库进行比较。

# 介绍

自然语言推理(NLI)和复述检测是自然语言处理的主要研究课题之一。自然语言推理指的是确定两个语句之间的蕴涵和矛盾的问题,而复述检测的重点是确定句子的重复。发表在这方面的论文使用递归神经网络[王&江,2016](https://arxiv.org/pdf/1611.01747.pdf) ,[王等,2017](https://arxiv.org/pdf/1702.03814.pdf) ,卷积神经网络[牟等,2016](https://arxiv.org/abs/1512.08422) 或带软对齐和注意的前馈神经网络[帕里克等,2016](https://arxiv.org/pdf/1606.01933v1.pdf) 。

# 模型架构

模型的输入是表示为单词嵌入向量序列的两个短语`a = {a1,...,am}`和`b = {b1,...,bn}`。目标是估计这两个短语相互蕴涵或矛盾的概率。在模型训练过程中,我们还将使用一个变量`y`,它是一个基础事实和辅助输入`a_len`和`b_len`来帮助我们构建掩蔽矩阵。下图描绘了由三层组成的核心模型架构:关注、比较和聚集。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e08137c5d9d9e7eafed845e8ed67f1ca.png)

A high-level overview of the model architecture. (Image credit: Parikh et al., 2017)

## 注意力

注意力层使用的是 [Bahdanau et al .,2016](https://arxiv.org/pdf/1409.0473.pdf) 提出的一种神经注意力的变体。它是使用分别应用于这两个问题的前馈神经网络`F`实现的(Bahdanau 的工作使用递归神经网络的内部状态)。然后,使用 softmax 函数对神经网络的输出进行归一化,并将其与第二个句子软对齐。该图层的方程式如下所示:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/bec8206d1d499877ce5c2014ded15a9e.png)

where m = number of words in a, n = number of words in b

对于训练,我使用预先训练的 300 维手套单词嵌入。`F(a)`的输出大小是`mx200`,而`F(b)`的输出大小是`nx200`,这意味着注意力权重矩阵`e`将具有形状`mxn`。`beta`和`alpha`则是 softmax 标准化注意力权重和相应句子矩阵之间的点积。

## 比较

下一步是比较软对齐的句子矩阵。类似于前一步骤,使用前馈神经网络`G`,并且网络的输入分别是连接的句子矩阵`[a, beta]`和`[b, alpha]`。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/7469210d299e762d2a0f2bc512e06490.png)

Soft-aligned matrix comparison

## 聚合

核心模型架构的最后一部分是聚合层。这一层所做的只是对比较网络的输出进行列式求和,这样我们就可以获得每个句子的固定大小的表示。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/1ae9d209fb91735db84b66e351b99a7e.png)

Comparison matrix aggregation

最后,聚合的句子表示被连接起来并输入到一个密集的分类网络中。分类器的输出层是 softmax 标准化的,以便我们获得目标类的概率分布。

# 卷积层

NLI 的可分解注意力模型的扩展是基于这样一个事实,即同一个单词在给定的上下文中可以有不同的含义。类似于我们人类在上下文中理解单词的方式,机器学习模型可以通过使用递归神经网络(计算成本更高)或卷积层(成本更低但效率也更低)来学习这些更高级的单词表示。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/401675fc4ba1ff5695580fac0b71fcb9.png)

Two convolutional layers with filter size 3 and stride 1

上图显示了如何使用卷积层构建更高级别的表示。例句“*我们在动物园里看到了一只漂亮的鹤”*包含单词 **crane** which 可以是一只鸟,但根据句子的上下文,它也可以是一个结构装置。

# 模特培训

首先使用`nltk.word_tokenize`函数对句子进行标记化,然后执行嵌入索引查找。如果在字典中找不到某个标记,则将其忽略,不进行插补。然后用零向量填充嵌入索引,直到给定批次中最长句子的长度。卷积层然后在第一个令牌之前和最后一个令牌之后附加零向量,以便在应用卷积之后,有效句子长度保持不变。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3eb4c09652c25627cb427f30abc485b0.png)

High level overview of a Tensorflow model graph

注意力权重矩阵`e`将所有填充值替换为`-np.inf`,以便在应用 softmax 归一化后,我们获得句子有效部分的概率分布,并且所有填充值为`0`。最后,如本文的**模型架构**部分所述,应用比较、聚集和分类层,并使用交叉熵损失来训练模型。

# 结果

首先,我在 Tensorflow 中实现了 NLI 最初的可分解注意力模型,以获得基线分数。虽然原始论文报告了 86.3%的测试准确性,但我无法将它提高到 83.8%以上(这可能是因为我使用了 AdaM optimizer 而不是 Adagrad,并且只训练了 100 个时期)。加入卷积层后,模型达到了分类精度 *84.5%* 。我还将 optimizer 改为 Adagrad,因为它与卷积架构配合得更好。

*在撰写本文时,目前最先进的自然语言推理模型是双边多视角匹配模型(* [*王等,2017*](https://arxiv.org/pdf/1702.03814.pdf) *),达到分类准确率 88.8%。我在这篇文章中选择 NLI 的可分解注意力模型的原因是,该模型的架构更简单,因此运行训练/推理花费的时间更少,我可以更多地进行实验。*

# 结论

正如我们所看到的,卷积层在分类精度上给了我们一点点改进。这种扩展可以对包含更多具有上下文条件意义的单词的数据集提供更大的改进,也可以对没有这种单词的数据集提供很少或没有改进。对于具有多个超参数组合的更多训练时期,训练模型也可以获得更好的分数。

完整的 Tensorflow 模型代码可以在[这里](https://gist.github.com/marekgalovic/a1a4073b917ae1b18dc7413436794dca)找到。如果你喜欢这篇文章,请随意推荐给其他人。此外,如果你对我做错了什么或者本可以做得不一样有任何建议,请在下面的评论区留下它们。

# 卷积神经网络

> 原文:<https://towardsdatascience.com/convolutional-neural-network-17fb77e76c05?source=collection_archive---------1----------------------->

## 卷积神经网络导论

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8a5755826e783e52734abc032440d0d6.png)

[**Fig 1\. Toon Discovers how machines see**](https://unsplash.com/photos/YvkH8R1zoQM)

在本文中,我们将了解什么是卷积神经网络,简称 ConvNets。ConvNets 是将深度学习中的图像工作提升到下一个水平的超级英雄。对于 ConvNets,输入是一幅图像,或者更具体地说,是一个 3D 矩阵。

让我们先来看看 ConvNet 是什么样子的!

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/465b94f9c72e20fc3609853c1038c82b.png)

**[Fig 2.]** [**Convolutional Neural Network**](http://file.scirp.org/Html/4-7800353_65406.htm)

简单来说,
一个 ConvNet 通常有 3 种类型的层:
1) **卷积层** ( *CONV* )
2) **池层** ( *池* )
3) **全连接层** ( *FC*

让我们更详细地看看每一层:

# 卷积层

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/89cb13a8f9c57d1ceb2e4fa383929f5c.png)

**Fig 3\. Convolutional Layer**

卷积层是 CNN 的第一层。
作为 ***输入*** 得到一个维度为*【h1 * w1 * D1】*的矩阵,就是上图中的蓝色矩阵。

接下来,我们有 ***内核*** (滤镜)。
仁?
内核是一个尺寸为*【H2 * w2 * D1】,*的矩阵,它是上图中(内核层中)多个长方体(内核)中的*一个*黄色长方体。
对于每个卷积层,有多个内核堆叠在彼此的顶部,这就是形成图 2 中的黄色三维矩阵的原因,其维度为*【H2 * w2 * D2】*,其中 *d2* 是内核的数量。

对于每个内核,我们都有其各自的**偏差**,这是一个标量。

然后,我们有一个 ***输出*** 给这一层,图 2 中的绿色矩阵,它有尺寸*【H3 * w3 * D2】。*

让我们从上面揭示一些显而易见的事情。
1)输入和*一个*内核**的深度( *d1* )(或通道数)相同**。
2)输出**的深度( *d2* )等于**内核的数量(即橙色三维矩阵的深度)。

好,我们有输入,内核和输出。现在让我们看看 2D 输入和 2D 内核会发生什么,即 *d1=1* 。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c444d022ad171fbe6a0b57593327555f.png)

**Fig 4\.** [**Calculation of output using 2D Convolution**](/types-of-convolutions-in-deep-learning-717013397f4d)

对于图像上内核的每个位置,内核上的每个数字与输入矩阵上的相应数字相乘(*蓝色矩阵*),然后对它们求和,得到输出矩阵中相应位置的值(*绿色矩阵*)。

使用 *d1 > 1* 时,每个通道发生相同的情况,然后将它们相加,再与相应滤波器的偏置相加,这就形成了输出矩阵相应位置的值。让我们想象一下!

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/39a98fbf0d99e8bdc7696238858a2db9.png)

**Fig 5\.** [**An example of how Inputs are mapped to Outputs**](http://cs231n.github.io/assets/conv-demo/index.html)

这是构成输出层的 *d2* 矩阵之一。

对所有的 *d2* 内核重复整个过程,这些内核形成输出层中的 *d2* 通道。

# 汇集层

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e2a50bb987e445a5b539cac20f503e59.png)

**Fig 6\. Max Pooling Layer**

共有两种类型的池:
1)最大池
2)平均池

汇集层的主要目的是减少输入张量的参数数量,从而
-有助于减少过拟合
-从输入张量中提取代表性特征
-减少计算,从而提高效率

池层的输入是张量。

在 Max Pooling 的情况下,其示例在图 6 的*中示出,*大小为`n*n` *(在上述示例中为 2×2)*的核在矩阵中移动,并且对于每个位置,取**最大值**并放入输出矩阵的相应位置。

在平均汇集*、*的情况下,大小为`n*n`的核在矩阵中移动,并且对于每个位置,对所有值取**平均值,并放入输出矩阵的相应位置。**

对输入张量中的每个通道重复这一过程。所以我们得到了输出张量。
所以,要注意的一点是,**池化在图像的高度和宽度上对图像进行缩减采样,但是通道的数量(深度)保持不变。**

# 全连接层

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/2f06f34df79a570b155cdd46ab17ce30.png)

**Fig 4\. Fully Connected Network**

全连接层简单地说就是,[](https://en.wikipedia.org/wiki/Feedforward_neural_network)**前馈神经网络。*完全连接的层形成网络中的最后几层。*

*到全连接层的**输入**是来自*最终*池化或卷积层的输出,它被 ***展平*** 然后馈入全连接层。*

> *变平了?
> 最终(和任何)池和卷积层的输出是一个三维矩阵,展平就是将其所有值展开成一个向量。
> 我们来形象化一下!*

*![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/7dc8ea42ae93c6b9f136ca9b74b8d85a.png)*

***Fig 5\. Flattening***

*这个展平的向量然后连接到几个完全连接的层,这些层与人工神经网络相同,执行相同的数学运算!*

*对于人工神经网络的每一层,进行以下计算*

*![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/54e29b00a99ab78814cc60c314158715.png)*

***Fig 6\. ANN Calculation for each layer***

*其中,
**x** — *为输入向量,维数为****【p _ l,1】***
**W**—*为权重矩阵,维数为****【p _ l,n _ l】****其中,****p _ l****为上一层神经元个数* **b** *—是维度为****【p _ l,1】*****g***—是激活函数,通常是****ReLU****。**

*对每一层重复这种计算。*

*在通过完全连接的层之后,最终层使用***【soft max】激活函数*** *(而不是 ReLU)* ,该函数用于获得输入在特定类中的概率(*分类*)。*

*最后,我们得到了图像中物体属于不同类别的概率!!*

*这就是卷积神经网络的工作原理!!
输入图像被归类为标签!!*

*现在,让我们想象如何从输入张量计算输出张量的维数。*

*![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a29b0c91121c7505bfec35591c523dee.png)*

***Fig 7\. Output Dimension Calculations from Input Dimensions***

*其中,
***W1***—*是输入张量* ***F***—*是内核* ***P****—是填充** 

> ****垫高?通常,输入矩阵用零填充,这样内核可以在矩阵上均匀移动,结果矩阵具有期望的维数。因此,P=1 意味着输入矩阵的所有边都用 1 层零填充,如图 4 所示,输入(蓝色)矩阵周围有虚线。****
> 
> ****跨步?**
> 内核在矩阵上一次移动一个像素(图 4)。因此,这被称为具有 1 的步幅。我们可以将步距增加到 2,这样内核在矩阵上一次移动 2 个像素。这将反过来影响输出张量的维度,并有助于减少过拟合。**

*****输出张量的通道数会发生什么变化?***
嗯,在卷积层的情况下,等于内核的数量。
在合并层的情况下,输入张量和输出张量中的通道保持相同!**

# 卷积神经网络——实施的鸟瞰图

> 原文:<https://towardsdatascience.com/convolutional-neural-network-a-birds-eye-view-with-an-implementation-1bff505dd3d9?source=collection_archive---------12----------------------->

*这篇文章正在被移到我的* [*子栈发布*](https://vishalramesh.substack.com/) *。这里* *可以免费阅读文章* [*。这篇文章将于 2022 年 5 月 18 日被删除。*](https://vishalramesh.substack.com/p/convolutional-neural-network-a-birds-eye-view-with-an-implementation-1bff505dd3d9?s=w)

这个内核旨在给出一个卷积神经网络(CNN)的简单理解。这将按以下顺序实现:

*   理解卷积运算
*   理解神经网络
*   数据预处理
*   了解使用的 CNN
*   了解优化器
*   理解`ImageDataGenerator`
*   做出预测并计算精确度
*   看到神经网络的运行

# 什么是卷积?

> *在数学(尤其是泛函分析)中,卷积是对两个函数(f 和 g)进行数学运算,以产生第三个函数,该函数表示一个函数的形状如何被另一个函数修改。*
> 
> (来源:[维基百科](https://en.wikipedia.org/wiki/Convolution))

这种运算应用于多个领域,如概率、统计、计算机视觉、自然语言处理、图像和信号处理、工程和微分方程。

该操作在数学上表示为

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9471ff84c27cb32730f6d2038aa81815.png)

The Convolution operation

(图片来源:[维基百科](https://en.wikipedia.org/wiki/Convolution#Definition))

检查此[链接](https://github.com/vdumoulin/conv_arithmetic)以直观了解卷积运算

# 什么是人工神经网络?

> 人工神经网络(ANN)或连接主义系统是由构成动物大脑的生物神经网络模糊启发的计算系统。这种系统通过考虑例子来“学习”执行任务,通常没有用任何特定于任务的规则来编程。
> 
> (来源:[维基百科](https://en.wikipedia.org/wiki/Artificial_neural_network))

人工神经网络是一个被称为人工神经元的更小的处理单元的集合,它与生物神经元大致相似。

**生物神经回路**

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/beed7c84847f1b30c5023fdd78d150c5.png)

A Biological Neural Circuit

*(图片来源:* [*维基百科*](https://en.wikipedia.org/wiki/Neural_circuit) *)*

互连电路的集合构成一个网络

**人工神经网络**

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/be82b2341185f626d2d9b4ea4154218c.png)

Artificial Neural Network

*(图片来源:* [*维基百科*](https://en.wikipedia.org/wiki/Artificial_neural_network) *)*

现在,我们从实现开始

# 导入必要的库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

import tflearn.data_utils as du
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from keras.optimizers import RMSprop
from keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import confusion_matrix


# 加载数据集

train_data = pd.read_csv(‘…/input/csvTrainImages 13440x1024.csv’, header = None)
train_label = pd.read_csv(‘…/input/csvTrainLabel 13440x1.csv’, header = None)
test_data = pd.read_csv(‘…/input/csvTestImages 3360x1024.csv’, header = None)
test_label = pd.read_csv(‘…/input/csvTestLabel 3360x1.csv’, header = None)


# 数据集

这里使用的数据集是[阿拉伯手写字符数据集](https://www.kaggle.com/mloey1/ahcd1)。

trainImages.csv 有 1024 列和 13440 行。每一列代表图像中的一个像素,每一行代表一个单独的灰度图像。每个像素的值在 0 -255 之间变化。

train_data = train_data.iloc[:,:].values.astype(‘float32’)
train_label = train_label.iloc[:,:].values.astype(‘int32’)-1
test_data = test_data.iloc[:,:].values.astype(‘float32’)
test_label = test_label.iloc[:,:].values.astype(‘int32’)-1


# 可视化数据集

def row_calculator(number_of_images, number_of_columns):
if number_of_images % number_of_columns != 0:
return (number_of_images / number_of_columns)+1
else:
return (number_of_images / number_of_columns)def display_image(x, img_size, number_of_images):
plt.figure(figsize = (8, 7))
if x.shape[0] > 0:
n_samples = x.shape[0]
x = x.reshape(n_samples, img_size, img_size)
number_of_rows = row_calculator(number_of_images, 4)
for i in range(number_of_images):
plt.subplot(number_of_rows, 4, i+1)
plt.imshow(x[i])


**训练集**

display_image(train_data, 32, 16)


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/4e14111ad2ac92e3af258a8e3ed2cb69.png)

The training dataset

**测试设置**

display_image(test_data, 32, 16)


![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/dd6308181ad8fac994b94bce43d6765b.png)

The test data

# 数据预处理

**编码分类变量**

***什么是分类变量?***

> *在统计学中,分类变量是一个变量,它可以取有限的、通常是固定数量的可能值中的一个,根据一些定性属性将每个个体或其他观察单位分配到特定的组或名义类别。*
> 
> (*来源:* [*维基百科*](https://en.wikipedia.org/wiki/Categorical_variable) )

简单地说,分类变量的值代表一个类别或类。

## 为什么我们需要对分类变量进行编码?

对代表一个类别的数字执行运算是没有意义的。因此,需要进行分类编码。

查看 stackoverflow 上的这个链接,通过一个例子来理解。

阿拉伯字母表中有 28 个字母。所以,有 28 节课。

train_label = du.to_categorical(train_label,28)


# 正常化

## 什么是正常化?

进行标准化是为了将整个数据带入一个明确定义的范围内,最好在 0 和 1 之间

> *在神经网络中,不仅要对数据进行标准化,还要对其进行缩放,这是一个好主意。这是为了在误差表面更快地接近全局最小值。*
> 
> *(来源:* [*堆栈溢出*](https://stackoverflow.com/questions/4674623/why-do-we-have-to-normalize-the-input-for-an-artificial-neural-network) *)*

train_data = train_data/255
test_data = test_data/255train_data = train_data.reshape([-1, 32, 32, 1])
test_data = test_data.reshape([-1, 32, 32, 1])


进行整形以使数据代表 2D 图像

train_data, mean1 = du.featurewise_zero_center(train_data)
test_data, mean2 = du.featurewise_zero_center(test_data)


基于特征的零中心化是用指定的平均值对每个样本进行零中心化。如果未指定,则评估所有样本的平均值。

# 构建 CNN

recognizer = Sequential()recognizer.add(Conv2D(filters = 32, kernel_size = (5,5),padding = ‘Same’, activation =‘relu’, input_shape = (32,32,1)))
recognizer.add(Conv2D(filters = 32, kernel_size = (5,5),padding = ‘Same’, activation =‘relu’))
recognizer.add(MaxPool2D(pool_size=(2,2)))
recognizer.add(Dropout(0.25)) recognizer.add(Conv2D(filters = 64, kernel_size = (3,3),padding = ‘Same’, activation =‘relu’))
recognizer.add(Conv2D(filters = 64, kernel_size = (3,3),padding = ‘Same’, activation =‘relu’))
recognizer.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))
recognizer.add(Dropout(0.25)) recognizer.add(Flatten())
recognizer.add(Dense(units = 256, input_dim = 1024, activation = ‘relu’))
recognizer.add(Dense(units = 256, activation = “relu”))
recognizer.add(Dropout(0.5))
recognizer.add(Dense(28, activation = “softmax”))


## 什么是最大池?

汇集意味着组合一组数据。组合数据的过程遵循一些规则。

> *根据定义,最大池取定义网格的最大值。*
> 
> (*来源:*[*machine learning online . blog*](https://machinelearningonline.blog/2017/06/29/max-pooling/))

最大池用于减少维度。也可以避免过度拟合。查看[这篇](https://machinelearningonline.blog/2017/06/29/max-pooling/)博客,更好地理解最大池。

## 什么是辍学?

> *Dropout 是一种正则化技术,通过防止对训练数据的复杂协同适应来减少神经网络中的过拟合。这是用神经网络进行模型平均的一种非常有效的方法。术语“丢失”是指在神经网络中丢失单元(隐藏的和可见的)。*
> 
> (*来源:* [*维基百科*](https://en.wikipedia.org/wiki/Dropout_(neural_networks) *)* )

## 什么是扁平化?

进行展平是为了将多维数据转换成 1D 特征向量,以供作为密集层的下一层使用

## 什么是密集层?

密集层只是一层人工神经网络

# CNN 的优化器

## 什么是优化器?

> *优化算法帮助我们最小化(或最大化)目标函数(误差函数的另一个名称)E(x ),它是一个简单的数学函数,依赖于模型的内部可学习参数,这些参数用于根据模型中使用的一组预测值(X)计算目标值(Y)。例如,我们将神经网络的权重(W)和偏差(b)值称为其内部可学习参数,用于计算输出值,并在最佳解决方案的方向上学习和更新,即通过网络的训练过程最小化损失,并且在神经网络模型的训练过程中也起主要作用。*
> 
> *(来源:* [*走向数据科学*](/types-of-optimization-algorithms-used-in-neural-networks-and-ways-to-optimize-gradient-95ae5d39529f) )

optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)


这里使用的优化器是一个 RMSprop。点击[此处](https://engmrk.com/rmsprop/)了解更多关于 RMSprop 的信息

recognizer.compile(optimizer = optimizer , loss = “categorical_crossentropy”, metrics=[“accuracy”])


# 什么是`ImageDataGenerator`?

图像数据生成器用于生成具有实时增强的批量张量图像数据。这些数据是成批循环的。

它用于批量加载图像。

datagen = ImageDataGenerator(
featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
rotation_range=10,
zoom_range = 0.1,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=False,
vertical_flip=False)datagen.fit(train_data)


# 用 CNN 拟合训练数据

recognizer.fit_generator(datagen.flow(train_data,train_label, batch_size=100), epochs = 30, verbose = 2, steps_per_epoch=train_data.shape[0] // 100)


# 做出预测

predictions = recognizer.predict(test_data)
predictions = np.argmax(predictions,axis = 1)


# 生成混淆矩阵

## 什么是混淆矩阵?

> 混淆矩阵是一种总结分类算法性能的技术。如果每个类中的观测值数量不相等,或者数据集中有两个以上的类,那么分类精度本身就可能会产生误导。计算混淆矩阵可以让您更好地了解您的分类模型是正确的,以及它正在犯什么类型的错误。
> 
> [来源](https://machinelearningmastery.com/confusion-matrix-machine-learning/)

cm = confusion_matrix(test_label, predictions)


# 计算精确度

accuracy = sum(cm[i][i] for i in range(28)) / test_label.shape[0]
print("accuracy = " + str(accuracy))


获得了 97%的准确度

# 观看 CNN 的运作

要实时了解 CNN 的工作情况,请点击[中的](http://scs.ryerson.ca/~aharley/vis/conv/flat.html)链接。它展示了一个 CNN 的工作原理,这个 CNN 被训练来识别手写数字。

# 卷积神经网络— II

> 原文:<https://towardsdatascience.com/convolutional-neural-network-ii-a11303f807dc?source=collection_archive---------7----------------------->

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/96ff93bf1b025900fa00a870f2eefde5.png)

继续我们在[上一篇文章](/cnn-part-i-9ec412a14cb1)中的学习,我们将在这篇文章中讨论以下主题:

*   体积卷积
*   一次多个过滤器
*   一层卷积网络
*   了解尺寸变化

我已经尽可能地通过插图来解释大多数主题。如果有些东西不容易理解,请告诉我。

> *我们开始吧!*

# 体积卷积

不要害怕读“音量”,这只是一种用一个以上的通道,即`RGB`或任何其他通道来表达图像的方式。

到目前为止,我们只有一个通道,所以我们只关心图像的`height`和`width`。但是,如果增加一个以上的通道,我们需要考虑所涉及的滤波器,因为它们还应该包含所有通道的卷积(此处为 3)。
因此,如果图像尺寸为`n x n x #channels`,那么之前的`f x f`滤波器现在也需要尺寸为`f x f x #channels`。

直观上,我们的输入数据不再是二维的,事实上,如果考虑通道,它是三维的,因此被命名为 **volume** 。

下面是一个体积卷积的简单示例,图像的尺寸为`6 x 6 x 3`,3 表示 3 个通道 R、G 和 b。类似地,滤波器的尺寸为`3 x 3 x 3`。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c87d8dac705bbe6d184c569e193124a8.png)

Fig 1\. Convolution over volume (colour image — 3 channels) with filter of dimension 3 x 3

在给定的例子中,滤波器的目的是检测垂直边缘。如果只需要在`R`通道中检测边沿,那么只需要根据要求设置`R`通道中的权重。如果您需要检测所有通道的垂直边缘,那么所有滤波器通道将具有如上所示的相同权重。

# 一次多个过滤器

很有可能你需要从一幅图像中提取许多不同的特征,为此你将使用多个过滤器。如果单独的滤波器被分别卷积,将增加计算时间,因此直接一次使用所有需要的滤波器更方便。

与单个滤波器的情况一样,单独执行卷积,然后将两个卷积的结果合并在一个堆栈中,以形成具有代表滤波器数量的第三维的输出体积。

下面的例子考虑了一个如上的`6 x 6 x 3`图像,但是我们使用了 2 个维度为`3 x 3 x 3`的过滤器(垂直边缘和水平边缘)。将每个`4 x 4`的合成图像叠加在一起,得到一个`4 x 4 x 2`的输出体积。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b4e5f5c5bedc255ac8e5040cc67747fc.png)

Fig 2\. Convolution over volume with multiple filter of dimensions 3 x 3

对于任何一般情况,可以使用以下公式计算输出尺寸:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8b784f7ed902164edd654e673c6449eb.png)

Fig 3\. Equation governing the output image/signal dimension wrt input and filter dimension

这里,`nc`是输入图像中的通道数,`nf`是使用的滤波器数。

# 一层卷积网络

如果我们考虑一个卷积网络的一个层,而不考虑汇集层和展平,那么它将看起来接近这样:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/f925d51bfc4dab8809d90b7df684b454.png)

Fig 4\. Single layer of convolution network only with Relu activation

重要的是要理解,像在任何其他神经网络中一样,卷积神经网络也具有输入数据`x`和模型权重,输入数据`x`在这里是图像,模型权重由滤波器 F1 和 F2 给出,即`W`。一旦权重和输入图像被卷积,我们得到加权输出`W * x`,然后我们加上偏差`b`。

这里的一个关键功能是`RELU`激活功能,它是一个整流线性单元。Relu 帮助我们将非线性添加到学习模型中,并帮助我们更好地训练/学习通用情况下的模型权重。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/2900a815d816f187f0915aa34f473c3e.png)

Fig 5\. Relu activation function

对于低于某个阈值(这里是 0)的值,relu 函数根本不更新参数。它就会死去。对于要考虑用于训练的特定训练示例,需要为要激活的神经元设置最小值。Relu 还帮助我们减少在大多数深度神经网络中面临的消失和爆炸梯度问题,因为 Relu 提供了有效的梯度传播。

# 了解尺寸变化

现在我们已经对单层中发生的事情有了概念性的了解,让我们用公式表示卷积网络的任何给定层`l`的轮廓。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c4614ce4436a86002dfb8f749993bc07.png)

Fig 6\. Equations governing change in input dimensions based on filters, padding and stride

计算单个组件尺寸后,层`l`的最终尺寸`n`可通过下式计算:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c3feadcee779509c2b9525472d001c0a.png)

Fig 7\. Dimensions of last layer **l** with filter size **f**, padding **p** and a stride of **s**

# 结论

本文一开始,我们探讨了体积卷积,然后立即讨论了多个滤波器。很容易理解,这里的*体积*就是指图像数据的 3 个颜色通道。关于卷积网络的单个层的讨论对于掌握整个网络架构非常重要,所以要确保这些概念(relu、激活函数)是清楚的。最后一节讲述了我们如何根据滤波器卷积中使用的填充量和步幅来评估模型的层尺寸。

> 在下一篇文章中,我将详细解释各种 CNN 架构,并评估其独特的功能

*原载于 2017 年 11 月 18 日*[*mandroid 6 . github . io*](https://mandroid6.github.io/2017/11/18/Convolutional-Neural-Networks-II/)*。*

[https://twitter.com/mandroid_6](https://twitter.com/mandroid_6)

## 查看我关于机器学习和深度学习的其他帖子:[https://medium.com/@razzormandar](https://medium.com/@razzormandar)

# 基于结构化银行客户数据的卷积神经网络

> 原文:<https://towardsdatascience.com/convolutional-neural-network-on-a-structured-bank-customer-data-358e6b8aa759?source=collection_archive---------1----------------------->

## 一个案例研究证明了 CNN 的价值,即使你没有处理计算机视觉问题。

作为一名为传统银行工作的定量分析师,我坐在一旁看着深度学习颠覆和改变了相当多的行业,但对它对我所在行业的实际用处持怀疑态度。你知道,可能有一些应用程序,如捕捉支票图像或聊天机器人,但当涉及到贷款业务的核心问题时,如信用风险、欺诈风险和营销等问题,我们处理的数据是非常结构化的,这些数据可以放入二维或三维表格中。深度学习在这里似乎有些矫枉过正。或者是?多年来,我已经看到了一些在非图像数据上成功使用卷积神经网络(CNN)的例子,但所有这些例子似乎都具有复杂的空间数据结构,算法可以利用这种结构。此外,银行仍在努力从线性模型过渡到更复杂的模型,如 GBM。深度学习似乎太遥远了。带着许多疑问,我开始了一个为期 3 周半的旅程,使用[桑坦德产品推荐 Kaggle 竞赛](https://www.kaggle.com/c/santander-product-recommendation)数据构建卷积神经网络。剧透一下——CNN 在结构化数据方面也做得非常好!

# 问题是

2016 年,桑坦德银行(西班牙)在 Kaggle 上举办了他们的第二次比赛。他们向 Kaggle 社区发出挑战,要求他们根据现有客户和类似客户过去的行为,预测他们的现有客户在下个月将使用哪些产品。数据集捕获客户信息的每月快照,一些是人口统计信息,如性别、年龄、收入和位置信息,一些是关系信息,如任期、关系类型等。该数据还跟踪每月客户的产品使用情况。这家银行提供 24 种产品,包括支票、储蓄、抵押贷款、信用卡等。如果客户在某个月使用了某个产品,则使用指标设置为 1,否则为 0。任务是根据客户 2015 年 1 月至 2016 年 5 月的产品使用情况以及 2015 年 1 月至 2016 年 6 月的其他信息,预测 2016 年 6 月的所有 24 个使用指标(但他们只关心那些从 0 变为 1 的使用情况)。为模型性能选择的指标是 [MAP@7](https://medium.com/@pds.bangalore/mean-average-precision-abd77d0b9a7e) ,它衡量推荐与客户的实际使用有多相关,以及推荐的排名顺序有多好(想想你会如何衡量从谷歌关键词搜索返回的第一页的有用性:结果越相关越好;结果从上到下的实际顺序与您的预期越一致,就越好)。由于一个客户在某个月可以使用多种产品,这是一个多类多标签的分类问题。

在宽客/经济学家的世界里,这种数据通常被称为“[面板数据](https://en.wikipedia.org/wiki/Panel_data)”。这些数据没有什么特别的,如果目标被一个默认标签代替,它可能是一个[行为记分卡](https://www.creditcards.com/glossary/term-behavior-score.php)模型的很好的数据集。然而,它确实包含一个时间维度和一个 sudo 空间维度(产品使用), CNN 或许可以利用这一点。

# CNN 的力量——特色工程

一般来说,如果没有广泛的特征工程,你不可能赢得一场竞争。在这种情况下也不例外,请看本次比赛的两个获奖方案:[第二](http://blog.kaggle.com/2017/01/12/santander-product-recommendation-competition-2nd-place-winners-solution-write-up-tom-van-de-wiele/)和[第三](http://blog.kaggle.com/2017/02/22/santander-product-recommendation-competition-3rd-place-winners-interview-ryuji-sakata/)名。特征工程在这两者中都扮演了重要的角色。他们想出了输入数据的智能转换,努力得到了回报。

下图显示了 CNN 算法的概念。最终密集连接的神经网络之前的卷积/汇集层用于从输入图像中提取和抽象模式。换句话说,对预测任务有用的工程特征。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8fa83c805a3cd6ad6beee0b7635270cc.png)

我的计划是把专题工程任务交给 CNN,自己不做任何工程。怎么会?通过将客户数据转换成类似图像的结构。在这种情况下,每个客户都有一个时间维度(从他们开始与银行建立关系到 2016 年 5 月),最大 17 个像素,以及一个 24 个像素的产品维度。收入和与银行的关系等一些特征随着时间的推移发生了变化,所以我最终得到了一些 45×17 像素的低分辨率“图片”,这些图片捕捉了我需要了解的关于客户的所有信息。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/fc62c7723058a81ba1bb0db4eac6e8b5.png)

Two samples of customer pictures plotted with nipy_spectral colormap

你可能想要设计的一些特征,比如“产品的上个月指数”,“到上个月为止指数从 0 到 1 的转换次数”或者“产品 A 和 B 一起使用的频率”——如果它们有用,它们将成为 CNN 检测的图像中的模式。这最棒的部分是什么?我不需要提出什么特征转换可能有用的假设,我可以去喝杯茶,同时算法勤奋地工作以发现有用的特征组合,其中一些可能超出我的想象。我确实提出了一个假设——如果一个顾客改变了他/她的性别,那么这个顾客的行为和产品使用会因为荷尔蒙和社会互动的变化而有所不同。但是没人变性。相当令人失望。

# 模型

我使用 Keras 和 Tensorflow 后端来构建 CNN。该模型有两条路径——一条路径执行卷积/汇集/丢弃操作,然后连接到密集连接的神经网络,另一条路径只执行简单的密集连接的神经网络,因为某些功能不会随着时间的推移而改变,或者以结构化的方式(例如,任期)为特定客户而改变。该模型有大约 55K 个参数——如果与典型的 CNN 图像识别模型相比,这是一个小网络。我花了大部分时间调整模型的结构(层、节点),没有调整其他超参数,如辍学率、L1 和 L2 惩罚。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e1ac050b8328367e35501c3d97aa6108.png)

# 结果和收获

我建立的 CNN 模型在 1787 个团队中,在私人排行榜上排名第 26,在公共排行榜上排名第 22。比赛已经结束了,所以我的表演不会被放在那里。然而,这比我的预期好得多。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b56b5d73ce7913e87872740f69316734.png)

我可以做更多的调整和模型组合来进一步推动它,但这不是练习的重点。要点是,CNN 在对结构化银行数据建模时也非常有用!我担心,像我这样的银行定量分析师再也不能舒舒服服地坐在椅子上,认为深度学习不会扰乱我们的行业。这可能不会是明天,因为所有的监管审查,但没有理由认为一个自动化,高效和有效的算法不会至少与我们共存。毕竟,几十年前定量分析师和统计学家取代了承销商,因为承销的统计模型比当时的承销商更加自动化、高效和有效。

# 解读

到目前为止开发的用于解释 CNN 的工具倾向于针对图像问题。但由于它是一个神经网络,人们可以随时查看梯度,并了解为什么模型会做出某些预测。我们知道模型是可微分的,因此通过使用一阶[泰勒级数](https://en.wikipedia.org/wiki/Taylor_series)近似,我们可以用输入(在这种情况下,特定客户的特征值)周围的线性函数来近似模型,然后我们可以使用预测相对于输入的梯度来显示输入的变化如何影响预测。下面是一张预测信用卡使用的梯度“图片”,与客户的输入值有关。蓝色块表示负值,红色块表示正值。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/30196a7e3b564bd16104d4ec3f904f13.png)

亮红色块显示,如果客户在最近 2 个月使用了直接存款,他/她将更有可能在 2016 年 6 月使用信用卡。蓝色块显示,如果客户在 2016 年 5 月使用信用卡,他/她在 2016 年 6 月使用信用卡的可能性将大大降低。猜猜看,这是因为我手动将目标指标更改为 0,而前一个月的使用量为 1,因为 Santander 只想知道谁从不使用产品变为使用产品。事后看来,我应该使用原始指标,建立模型,并使用后处理规则来处理,因为手动调整成为模型需要学习的另一件事。然而,模型能够学习调整的事实表明模型正在做正确的事情。

# 最后的想法

我把这个展示给了当地的数据科学家社区,他们觉得非常有趣。提出的一个问题是为什么 CNN 而不是 RNN(循环神经网络)。毕竟,用 RNN 对时间序列数据建模更有意义。这场比赛的第 15 名获胜者似乎使用了 RNN 作为他们的算法。很难说 RNN 在这种情况下一定更好,因为我建立的 CNN 有点粗糙,我没有做很多调整和模型组合。然而,应该注意的是,时间相关性信息可能会在卷积和池化过滤器中丢失,因此 CNN 可能并不总是适用于时间序列问题。不过,与 RNN 模型相比,CNN 的优势在于相对容易训练。

# 卷积神经网络在游戏中驾驶车辆

> 原文:<https://towardsdatascience.com/convolutional-neural-network-to-steer-a-vehicle-inside-a-game-2aab41a5ef60?source=collection_archive---------11----------------------->

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/1129e11396c6dd6837fd6febf06f2080.png)

大约两年前,英伟达发表了 [PilotNet 论文](https://arxiv.org/abs/1604.07316),以端到端的方式展示了自动驾驶汽车的卷积神经网络(CNN)。在这篇文章中,我想展示我是如何在游戏中使用这个架构来预测车辆的方向盘轴线的。我已经将转向角预测公式化为回归问题。

任何有监督的机器学习问题都是在有标签的数据(X,Y)上工作的。其中 **X** 是输入, **Y** 是输出。学习算法学习映射函数 Y = f(X)。在这个问题中,输入 X 是任意给定点的道路图像,输出 Y 是方向盘轴。

## 资料组

我从[这里](https://github.com/marsauto/europilot#sample-training-data)获得了大约 16 万张图像的数据集。该数据集是通过以 10fps 的速度驾驶大约 5 个小时,通过游戏杆捕捉游戏窗口和方向盘轴的截图而生成的。方向盘轴不是以度为单位,而是以操纵杆的不同刻度为单位,范围从-10k(左转)到 10k(右转)。原始图像大小为 1024 X 768 X 3 像素。这里有一些例子图片—

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/aa8ca5b8dbbccc806084d4fd95bddd24.png)

Driving in the daylight

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/6ba9309d83d62ffffe525494dd85e7b1.png)

Driving at the night

图像的大部分不是很有用,因此感兴趣区域(ROI)被裁剪并按比例缩小以获得尺寸为 200 x 66 x 3 的图像。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/ea9af98c10ca673d80a3e00961bf14ab.png)

ROI(200 x 66 x 3)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/1c169a071710e486281d2918d9a8b8fc.png)

ROI(200 x 66 x 3)

这是数据准备的一个重要部分,因为裁剪确保了学习算法只关注 ROI,而不是整个图像,缩小比例确保了网络没有太多的输入参数。

整个数据被混洗,然后分成训练集(87%)和验证集(13%)。具有超参数调整的模型训练在训练集上完成,而验证集用于检查模型的最终准确性。洗牌确保了训练集和验证集都有来自所有不同驾驶条件的数据,如白天、夜晚、下雨等。

现在来看标签,这是方向盘轴的直方图。正值对应于右转的方向盘旋转量,反之亦然。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5948ab4fcd7438bf847b5c7a977cecc4.png)

Distribution of steering wheel axis (labels) BEFORE Augmentation

急转弯的例子很少,大多数数据在-2500 到 2500 之间。此外,由于这种分布是正常的,均方差(MSE)损失(已用于回归)应该工作得很好。

此外,**数据通过水平翻转图像并因此翻转转向轴而得到增强**。

if(np.random.choice(2, 1)[0] == 1):
pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
label = -1 * label # Changing the direction of wheel axis.


这几乎使训练数据翻倍。

## 网络体系结构

我选择了 Nvidia 著名的 [PilotNet 架构,并做了一些修改。这是最初的建筑](https://arxiv.org/abs/1604.07316)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9493991c13c17befb114a0c13f5834c5.png)

Source [Nvidia blog](https://devblogs.nvidia.com/deep-learning-self-driving-cars/)

为了更快的训练,我在每一层之后增加了**【BN】**(在卷积层的信道轴上)。我也尝试使用**辍学**进行正规化,但这似乎并不影响准确性,因此删除了它。关于何时应用 BN 有许多[争论,BN](https://www.reddit.com/r/MachineLearning/comments/67gonq/d_batch_normalization_before_or_after_relu/)是在非线性之前还是在非线性之后。因为我在每一层使用了 **Relu 激活**,在 Relu 激活后应用 BN 是**增加了隐藏层激活的平均值并减少了方差**,因为 BN 没有考虑负面激活。因此,我在非线性**、**后应用 BN,结果很好。

我将输入图像缩小到 200 x 66(与 PilotNet 相同),以保持全连接层的参数较低(卷积层的参数不受影响)。这对于避免过度拟合非常重要。具有非常高的参数的模型具有高熵,并且它们倾向于过度拟合(即记忆训练集)。在低熵的情况下,梯度下降算法迫使模型学习数据中的重要模式,而不是记忆训练集。而参数很低也是不好的,因为模型可能什么也学不到。

可以通过使用最大池来避免参数的增加,但是它通常用于空间不变性,这在这种情况下是不期望的。

通过将输入像素除以 255 来归一化模型的输入。使用整个训练集的均值和方差来归一化输入图像有更好的方法,但这也很好。我使用没有任何正则化的均方误差损失。在验证集上测试了这些参数之后,我想出了所有这些设计选择。其余的网络参数保持不变。

这是我和`input_shape = (66, 200, 3)`一起使用的最终架构。


Layer (type) Output Shape Param #

conv2d_1 (Conv2D) (None, 31, 98, 24) 1824


batch_normalization_1 (Batch (None, 31, 98, 24) 96


conv2d_2 (Conv2D) (None, 14, 47, 36) 21636


batch_normalization_2 (Batch (None, 14, 47, 36) 144


conv2d_3 (Conv2D) (None, 5, 22, 48) 43248


batch_normalization_3 (Batch (None, 5, 22, 48) 192


conv2d_4 (Conv2D) (None, 3, 20, 64) 27712


batch_normalization_4 (Batch (None, 3, 20, 64) 256


conv2d_5 (Conv2D) (None, 1, 18, 64) 36928


batch_normalization_5 (Batch (None, 1, 18, 64) 256


flatten_1 (Flatten) (None, 1152) 0


dense_1 (Dense) (None, 100) 115300


batch_normalization_6 (Batch (None, 100) 400


dense_2 (Dense) (None, 50) 5050


batch_normalization_7 (Batch (None, 50) 200


dense_3 (Dense) (None, 10) 510


batch_normalization_8 (Batch (None, 10) 40


dense_4 (Dense) (None, 1) 11

Total params: 253,803
Trainable params: 253,011
Non-trainable params: 792


我使用 Keras 和 Tensorflow 后端进行所有的实验和最终训练。

## 培养

该数据集在相邻图像之间具有非常高的相关性,因此对训练进行洗牌是很重要的。与此同时,在每个时期之后,数据集被重新洗牌,这样每个批次在多个时期中都是唯一的。

total data: 162495, training set: 140800, validation set: 21695
batch_size: 128, train_steps: 1100, val_steps: 170


由于 keras [没有用于回归](https://github.com/keras-team/keras/issues/5152)任务的 `[flow_from_directory](https://github.com/keras-team/keras/issues/5152)` [,我不得不编写自己的带有数据扩充的 data_generator。](https://github.com/keras-team/keras/issues/5152)

INPUT_NORMALIZATION = 255.0
OUTPUT_NORMALIZATION = 655.35 #picked this number to compare results with data source model.
img_shape = (66, 200, 3)
batch_size = 128
def generator(df, batch_size):
img_list = df[‘img’]
wheel_axis = df[‘wheel-axis’]
# create an empty batch
batch_img = np.zeros((batch_size,) + img_shape)
batch_label = np.zeros((batch_size, 1))
index = 0 while True:
for i in range(batch_size):
label = wheel_axis.iloc[index]
img_name = img_list.iloc[index]
pil_img = image.load_img(path_to_data+img_name)
**# Data augmentation **
if(np.random.choice(2, 1)[0] == 1):
pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
label = -1 * label
batch_img[i] = image.img_to_array(pil_img)
batch_label[i] = label
index += 1
if index == len(img_list):
#End of an epoch hence reshuffle
df = df.sample(frac=1).reset_index(drop=True)
img_list = df[‘img’]
wheel_axis = df[‘wheel-axis’]
index = 0
yield batch_img / INPUT_NORMALIZATION, (batch_label / OUTPUT_NORMALIZATION)


决定使用多大的迷你批次也很棘手。如果我们使用非常小的批量,计算的梯度可能会非常不准确,因此训练会有噪声。如果你选择一个非常大的批量,它可能不适合内存。我选择使用 128 作为迷你批次大小。

我使用具有动量和学习率衰减的随机梯度下降优化器来训练网络。

sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)


该模型在 CPU 上训练 41 个时期,持续约 30 小时,以实现 0.1166 的验证均方误差和 0.2429 的验证平均绝对误差(在第 36 个时期),这对应于 20k 标度上 160 (=0.2429 x 输出 _ 归一化)的平均误差。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8ee155da9de4767a8c862a4ec0140eff.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b02459ebc0caf4cba7c752c12b08f44f.png)

Validation MAE and MSE

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/6b5e22157f325ec4b522611da2c23791.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/777d5e0d1451191b6960b39d328c583b.png)

Training MAE and MSE

而训练批次规范化有助于更快的转换。与 20 个时期内没有批量标准化的架构相比,我能够在仅 9 个时期内通过批量标准化实现相同的 MSE 损失。

## 结果

以下是一些结果(提醒—负值表示左转,反之亦然)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/43f59e9c75a5ab954f3afad0a1f19e9a.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/bc6214c3bcb78a77938b94e4c838b967.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9667447819e473d55bd0675883d2bacd.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/da571b1664f41cc2330d01c953517716.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b09656129034349bbff8795016a9c471.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/f4a2268bda620dbe2e6e4813c50a6585.png)

尽管急转弯的例子很少,但 model 仍然学会了这些模式。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8abd91d0a59e099f9fc4a0132febd172.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e44535de64893c29c12b3b635573beee.png)

Sharp Right Turns

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8d98c561eb35eefe5535c5d389c525f3.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/f4b86072907b8612b0474d05d3517c31.png)

Sharp Left Turns

有些情况下,模型比真实标签表现得更好。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/cef37c30f2f57fcf3152b821fdbf0c21.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/50cea1d9bbf06fba53e44a1003841504.png)

Model predictions are better than ground truth labels

在某些情况下,模型的表现不是很好。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/348b7ac1f9c413dd8a7511553241ffed.png)![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b096f0c401766dfa21a3e1036db3d1c4.png)

Model prediction are not very good

这篇文章的重量和代码可以在 [my Github](https://github.com/aryarohit07/PilotNetSelfDrivingCar) 上找到。

## 结论

对于这个项目,一个基于 CNN 的小型架构似乎工作得很好。我使用了各种技术,如数据处理(裁剪 ROI、缩放输入大小)、数据扩充、批量标准化,仅用大约 5 小时的行驶数据就实现了相当好的验证损失。这可以通过使用不同的架构,如[CNN-RNN](http://cs231n.stanford.edu/reports/2017/pdfs/626.pdf)网络来获得更好的结果,并通过使用其他梯度下降优化器,如 Adam、Adadelta 等来进一步改善。

如果你喜欢读这篇文章,请鼓掌并与你的同事和朋友分享。谢谢!

还有,我们来连线一下[脸书](https://www.facebook.com/aryarohit07)、[推特](https://twitter.com/arya_rohit07)、 [Linkedin](https://in.linkedin.com/in/aryarohit07) 和 [Github](https://github.com/aryarohit07/) 。

# 全卷积神经网络|第一部分

> 原文:<https://towardsdatascience.com/convolutional-neural-networks-for-all-part-i-cdd282ee7947?source=collection_archive---------5----------------------->

## 导师指导的学习指南,以应对 Coursera 深度学习专业化课程 4

Coursera 深度学习专业化课程的前三门课程是可以忍受的艰难,但接下来是 T2 课程第四门。这么多伟大的主题和概念!但是无数次停止视频、做笔记和重新观看讲座让我们,一群官方导师,决定学习指南值得努力。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/3c47e6005836ca7f6d5e3d7f02c029cc.png)

Let’s walk this CNN tour until Neural Style Transfer together.

本学习指南三部曲的第一部分回顾了本课程涵盖的广泛概念。什么是卷积神经网络,YOLO 实际上是如何工作的?[第二部分](https://medium.com/machine-learning-world/convolutional-neural-networks-for-all-part-ii-b4cb41d424fd)总结了每一次演讲,并深入解释了顶层概念。第三部分提供了一个 deeplearning.ai 字典,帮助你整理 ng 大师的缩略语、专业术语和偶尔的笑话。

先把 CNN 课程最有意思的概念一个个分解一下。

# 卷积神经网络

## 什么是卷积神经网络?

卷积神经网络(CNN)是计算机视觉的首要深度学习模型。计算机视觉已经变得如此之好,以至于它目前在某些任务上击败了人类,例如[识别猫和狗的品种](http://www.nytimes.com/2012/06/26/technology/in-a-big-network-of-computers-evidence-of-machine-learning.html),CNN 在这个成功故事中发挥了重要作用。如果你有一个涉及计算机视觉的任务,让它识别人脸或物体,CNN 是首选模型。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0e7de8a67e0c197106c87d417e45b499.png)

Convolving the pixels of an image.

## CNN 是如何工作的?

CNN 用于通过卷积来评估输入。输入与过滤器进行卷积,如上面的 *gif* 所示。这种卷积导致网络检测网络中较早层中的边缘和较低级别的特征以及较深层中更复杂的特征。CNN 与池层结合使用,它们通常在最后有完全连接的层,如下图所示。像在普通神经网络中一样运行前向传播,并通过反向传播最小化损失函数来训练 CNN。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/fff293357945e7f1d58d1fca7db08cbd.png)

Simple CNN architecture. Source: [https://goo.gl/dVSMQo](https://goo.gl/dVSMQo)

某些架构,如 ResNets 或 InceptionNets,可以加速 CNN 的训练。处理大量的图像和训练权重需要时间,因为有太多的联系。幸运的是,许多伟大的 CNN 已经被训练出来,像 [ImageNet](http://www.image-net.org/) 或 [VGG](http://www.robots.ox.ac.uk/~vgg/practicals/cnn/index.html) ,你可以重用他们的模型。吴恩达的建议是,在现有 CNN 架构和预训练模型的基础上使用迁移学习,快速开始你的计算机视觉任务。

# **通过 YOLO 探测物体**

## 什么是 YOLO?

YOLO 是一种也实时工作的多目标检测算法。图片[自动驾驶汽车在行驶中需要识别汽车、行人、红绿灯](https://www.youtube.com/watch?v=OksuVuNY5o0)或者[简单标注一部电影](https://www.youtube.com/watch?v=VOC3huqHrss)。YOLO 非常快,因为“你只看一次”,这意味着你运行一个单一的前向传播步骤,你立即知道一个对象在图像中的确切位置和这个对象属于哪个类。作为顶端的樱桃,YOLO 能够检测图像中的多个对象。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b6b5f34fa72b5eb90d5b5e0635a7e4a0.png)

Output of YOLO object detection. Source: [https://goo.gl/yefAZa](https://goo.gl/yefAZa)

## YOLO 是如何工作的?

要使用 YOLO 训练 CNN,首先必须在训练图像上放置一个网格,例如形状为 3×3 的网格。接下来,为每个格网创建输出标签。在每个网格中的对象周围绘制一个边界框,并相应地标记输出向量。给尽可能多的图像加标签。CNN 的最后一层具有来自输入图像的网格单元的形状,宽度和高度以及与单个输出向量中的元素数量一样多的通道。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/722273f7578a0cff076f37d1479fdc8e.png)

How to label your training set for YOLO.

反向传播调整 CNN 的权重,以便它学习识别对象。您可以使用非最大抑制来确定对象的最佳边界框。如果在同一个网格单元中遇到多个对象重叠,可以使用定位框来分隔这些对象。这些细节在[第二部分](https://medium.com/machine-learning-world/convolutional-neural-networks-for-all-part-ii-b4cb41d424fd)中有更详细的解释。

# **人脸识别**

## 什么是人脸识别?

人脸识别用于根据人脸图像来识别一个人。虽然人脸验证是根据人脸来验证一个人是否是他们声称的那个人,但人脸识别要复杂得多,因为您要尝试将那个人的脸与人脸图像数据库进行匹配。此外,你经常必须通过一次性学习来识别一个人,这意味着你必须根据一张图像来识别她,并检查它是否与数据库中的任何图像足够相似——相当困难!

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/a5ed1e9a0a1885bf17fd15864bf3a741.png)

Their faces are detected! Now we can check if these faces belong to people who are allowed to be there. Source: [https://goo.gl/ubrq3H](https://goo.gl/ubrq3H)

## 人脸识别是如何工作的?

你的目标是学习一个相似性函数,例如三重损失。相似性函数旨在检测不同组图像上的人是否相同。三元组损失函数需要三个图像来计算相似性:一个锚、那个人的正面和负面例子。三元组损失函数基于锚图像调整权重以最大化正图像和负图像之间的差异。基于三重损失的输出,CNN 决定是否识别该人。确保使用 hard 为相似性函数训练图像。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/5247665a2f7a7ba16221c4ce392c078c.png)

Triplet loss learns that the similarity between two images of Jen Aniston should be bigger than between Jen Aniston and LL Cool J. Source: [https://goo.gl/hWn8jJ](https://goo.gl/hWn8jJ)

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/61e674c7e747138309fece2abcc061ef.png)

Good example of a difficult to train image triplet for the similarity function.

# **神经风格转移**

## 这是什么?

神经类型转移是一个有趣的应用程序,将提高您对 CNN 的理解。本质上,你试图生成一个新的图像,将一个图像的内容与另一个图像的风格结合起来,比如说来自一个受欢迎的艺术家。你想知道毕加索会怎么画你吗?去吧,用神经风格转移自己尝试一下!

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c9be807f4be3cb2135fd1a7c3c8551b7.png)

Van Gogh’s Starry Night applied to a GIF.

## 神经风格转移是如何工作的?

在神经风格转移中,您从生成的图像 *G* 开始,它包含随机像素值,如下所示。接下来,您定义一个内容图像 *C* 和一个样式图像 *S* ,您想要组合它们。您的目标是调整 *G* 中的像素值,以便 *G* 变得与 *C* 和 *S* 相似。为此,您需要定义成本函数 *J(C)* 和 *J(S)* ,并尝试最小化这两个函数。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/0ce68c87f3a25af524c548ee4c782aba.png)

Random pixel values to start NST.

*J(C)* 确保 *G* 看起来与 *C* 中的内容相似。你知道,CNN 学习识别较低级别的特征,如早期隐藏层中的边缘,以及更复杂的特征,如后期隐藏层中的人脸。在 CNN 中间选择一个隐藏层,用 *C* 和 *G* 进行正向传播。接下来,比较两幅图像的激活值,并通过反向传播尽量减小激活值之间的差异。

接下来,你还必须调整 *G* 的样式,以匹配 *S* 中的样式。最小化 *J(S)* 的关键是调整 *G* 中通道激活之间的相关性,以匹配 *S* 。你可以通过计算 *S* 和 *G* 的 Gram 矩阵来实现。Gram 矩阵计算每一对可能的滤波器组合。接下来,你选择 CNN 中间的一层,再次为 *S* 和 *G* 运行前向传播。 *J(S)* 通过反向传播最小化 gram 矩阵之间的差异,并使 *G* 看起来更类似于 *S* 。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/c62a782941b718f8100a5f623e8fe3ce.png)

Beautiful, historic Strausberger Platz in Berlin combined with Van Gogh’s Starry Night through NST.

最酷的是,神经网络学会了调整像素值,而不仅仅是权重!这是一种非常直观的研究和理解 CNN 的方式,我鼓励你创建自己的神经风格传输图像。

声明:所有功劳归于 [deeplearning.ai](http://deeplearning.ai/) 。虽然我是一名导师,但我只是总结和重新表述内容,以帮助学习者进步。

第一部分是一个包,关到第二部分和第三部分的[。如果你认为这篇文章是有帮助的,不要忘记展示你的💛穿过👏 👏 👏并关注我,听更多关于深度学习、在线课程、自动驾驶汽车、生活的文章。还有,](https://medium.com/machine-learning-world/convolutional-neural-networks-for-all-part-ii-b4cb41d424fd)[查一下](https://medium.com/machine-learning-world/netflix-or-coursera-how-to-finish-andrew-ngs-1st-deep-learning-course-in-7-days-6fa293ee83d8) [这些](/https-medium-com-janzawadzki-applying-andrew-ngs-1st-deep-neural-network-on-the-titanic-survival-data-set-b77edbc83816) [关于深度学习专精的帖子](/structuring-your-machine-learning-project-course-summary-in-1-picture-and-22-nuggets-of-wisdom-95b051a6c9dd)。请评论分享你的看法。干杯!🙇

# 卷积神经网络

> 原文:<https://towardsdatascience.com/convolutional-neural-networks-from-the-ground-up-c67bb41454e1?source=collection_archive---------2----------------------->

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/1e626f893c1c9d7502403835f8a8abae.png)

Visualization of a convolutional neural network. [image source](https://www.kdnuggets.com/2018/02/8-neural-network-architectures-machine-learning-researchers-need-learn.html)

## 著名的卷积神经网络的 NumPy 实现:迄今为止最有影响力的神经网络架构之一。

当 Yann LeCun 发表了他关于一种新的神经网络体系结构[1]卷积神经网络(CNN)的研究成果时,他的工作很大程度上没有引起人们的注意。在 2012 年 ImageNet 计算机视觉竞赛期间,多伦多大学的一组研究人员花了 14 年时间将 CNN 带入公众视野。他们的参赛作品以首席建筑师 Alex Krizhevsky 的名字命名为 AlexNet,在对来自数千个类别的数百万张图像进行分类时,误差仅为 15.8%。快进到 2018 年,当前最先进的卷积神经网络实现了超过人类水平性能的精度[3]。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/9db821b129908837c096779ac5cddcc4.png)

ImageNet top-5 error 2010–2015\. [source](https://devblogs.nvidia.com/mocha-jl-deep-learning-julia/)

在这些有希望的结果的激励下,我开始了解 CNN 的功能,以及它们是如何表现得如此出色的。正如理查德·费曼指出的那样,*“我不能构建的,我不理解”*,因此为了全面了解人工智能的这一进步,我在 NumPy 中从头开始构建了一个卷积神经网络。完成这个项目后,我觉得卷积神经网络看起来有多复杂,和它们实际上有多复杂之间有一个脱节。希望你从零开始建立自己的网络后,也能分享这种感觉。

这个项目的代码可以在[这里](https://github.com/Alescontrela/Numpy-CNN)找到。

# 挑战

CNN 以其识别图像中存在的模式的能力而闻名,所以这篇文章中描述的网络的任务是图像分类。衡量计算机视觉算法表现如何的最常见基准之一是在 [MNIST 手写数字数据库](http://yann.lecun.com/exdb/mnist/)上训练它:一个 7 万个手写数字及其相应标签的集合。目标是训练 CNN 在标记手写数字(范围从 0 到 9)时尽可能准确。经过大约五个小时的训练和训练集上的两次循环,这里介绍的网络能够在测试数据上达到 98%的准确率,这意味着它可以正确地猜出几乎每个显示给它的手写数字。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8e3c1db38cb200589ae8bea8d7d51480.png)

Example of digits from the MNIST dataset. [image source](https://codeburst.io/use-tensorflow-dnnclassifier-estimator-to-classify-mnist-dataset-a7222bf9f940?gi=4a1246898237)

让我们来看一下构成网络的各个组件,以及它们如何链接在一起以根据输入数据形成预测。解释完每个组件后,我们将对其功能进行编码。在这篇文章的最后一部分,我们将使用 NumPy(这里的代码[是](https://github.com/Alescontrela/Numpy-CNN))对网络的每一部分进行编程和训练。值得注意的是,本节假设至少具备线性代数和微积分的工作知识,并且熟悉 Python 编程语言。如果你对这些领域不熟悉或者需要调整,请查看[这份出版物](https://arxiv.org/pdf/1802.01528.pdf)以了解机器学习领域的线性代数,以及[这份资源](https://www.codecademy.com/learn/learn-python)以开始用 Python 编程。事不宜迟,我们开始吧。

# 卷积神经网络如何学习

## 回旋

CNN 利用**过滤器**(也称为内核),来检测图像中存在哪些特征,比如边缘。过滤器只是一个称为权重的值矩阵,用于检测特定的特征。过滤器在图像的每个部分上移动,以检查它想要检测的特征是否存在。为了提供表示特定特征存在的置信度的值,滤波器执行**卷积运算**,这是两个矩阵之间的逐元素积和。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/fe29c8b39d7c899f742c90b2b83ea2d8.png)

[image source](http://technodocbox.com/3D_Graphics/70716176-Deep-neural-networks-applications-in-handwriting-recognition.html)

当特征出现在图像的一部分中时,滤波器和图像的该部分之间的卷积运算产生具有高值的实数。如果该特征不存在,则结果值较低。

在下面的示例中,负责检查右侧曲线的滤镜会经过图像的一部分。由于图像的该部分包含过滤器正在寻找的相同曲线,卷积运算的结果是一个大的数字(6600)。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/89108a44e1646a3937b1d3342d88382e.png)

[image source](https://adeshpande3.github.io/A-Beginner%27s-Guide-To-Understanding-Convolutional-Neural-Networks/)

但是,当相同的滤波器通过图像的一部分时,具有相当不同的一组边缘,卷积的输出很小,这意味着没有强烈的右手曲线。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/007472c70ba6ae08315ba4b8f4641142.png)

[image source](https://adeshpande3.github.io/A-Beginner%27s-Guide-To-Understanding-Convolutional-Neural-Networks/)

在整个图像上传递该滤波器的结果是输出矩阵,该矩阵存储该滤波器在图像的各个部分上的卷积。滤波器的通道数必须与输入图像的通道数相同,这样才能进行逐元素乘法。例如,如果输入图像包含三个通道(例如 RGB),则滤镜也必须包含三个通道。

2D 图像上滤波器的卷积;

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/f8a3b202e4265e39abf4c39943957d8f.png)

[Introduction to Convolutional Neural Networks](https://rubikscode.net/2018/02/26/introduction-to-convolutional-neural-networks/) by rubikscode

此外,使用**步距**值,滤波器可以以不同的间隔在输入图像上滑动。步幅值由过滤器在每一步应该移动的量决定。步进卷积的输出维度可通过以下公式计算:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b12056eec0b22b974721997b11d2d079.png)

其中`n_in`表示输入图像的尺寸,`f`表示窗口大小,`s`表示步幅。

为了使卷积神经网络能够学习检测输入数据中存在的特征的滤波器的值,滤波器必须通过非线性映射。滤波器和输入图像之间的卷积运算的输出与偏置项相加,并通过**非线性激活函数**。激活函数的目的是将非线性引入我们的网络。由于我们的输入数据是非线性的(对形成手写签名的像素进行线性建模是不可行的),我们的模型需要考虑这一点。为此,我们使用整流线性单元(ReLU)激活功能:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/35556070badea0b30aac16e9a241d0ac.png)

[image source](https://medium.com/@kanchansarkar/relu-not-a-differentiable-function-why-used-in-gradient-based-optimization-7fef3a4cecec)

可以看到,ReLU 函数相当简单;小于或等于零的值变为零,所有正值保持不变。

通常,网络每层使用多个过滤器。在这种情况下,输入图像上每个滤波器卷积的输出沿最后一个轴连接,形成最终的 3D 输出。

**代码**

使用 NumPy,我们可以很容易地对卷积运算进行编程。卷积函数利用 for 循环对图像上的所有滤波器进行卷积。在 for 循环的每次迭代中,使用两个 while 循环在图像上传递过滤器。在每一步,滤波器与输入图像的一部分按元素相乘(`*`)。然后,使用 NumPy 的 [sum](https://www.google.com/search?q=numpy+sum&rlz=1C5CHFA_enUS741US741&oq=numpy+sum&aqs=chrome..69i57j0l5.1102j0j4&sourceid=chrome&ie=UTF-8) 方法对这种逐元素乘法的结果求和以获得单个值,然后加上偏置项。

convolution operation

使用标准正态分布初始化`filt`输入,并且`bias`被初始化为零向量。

在一个或两个卷积层之后,通常减少由卷积层产生的表示的大小。这种表示尺寸的减小被称为**缩减采样。**

## 向下采样

为了加快训练过程并减少网络消耗的内存量,我们尝试减少输入要素中存在的冗余。有几种方法可以对图像进行缩减采样,但在这篇文章中,我们将看看最常用的一种:**最大池**。

在 max pooling 中,窗口根据设定的步幅(每次移动多少个单位)通过图像。在每一步,窗口内的最大值被汇集到输出矩阵中,因此命名为最大汇集。

在下图中,大小为 f=2 的窗口以 2 的步幅通过一幅图像。f 表示最大池窗口(红框)的尺寸,s 表示窗口在 x 和 y 方向移动的单位数。在每一步,选择窗口内的最大值:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/8f9ab333da58c6b38f99818d1bd49ce0.png)

[image source](https://zhuanlan.zhihu.com/p/32442184)

最大池显著减小了制图表达的大小,从而减少了所需的内存量以及稍后在网络中执行的操作数量。最大池化操作的输出大小可以使用以下公式计算:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/b12056eec0b22b974721997b11d2d079.png)

其中`n_in`表示输入图像的尺寸,`f`表示窗口大小,`s`表示步幅。

max pooling 的另一个好处是,它迫使网络专注于少数几个神经元,而不是所有神经元,这对网络具有正则化效果,使其不太可能过度拟合训练数据,并有望很好地推广。

**代码**

最大池操作归结为一个 for 循环和几个 while 循环。for 循环用于遍历输入图像的每一层,而 while 循环用于在图像的每一部分滑动窗口。在每一步,我们使用 NumPy 的 [max](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.maximum.html) 方法来获得最大值:

max pooling operation

在多个卷积层和下采样操作之后,3D 图像表示被转换成特征向量,该特征向量被传递到多层感知器,该感知器仅仅是具有至少三层的神经网络。这被称为**全连接层。**

## 全连接层

在神经网络的全连接操作中,输入表示被展平成特征向量,并通过神经元网络来预测输出概率。下图描述了拼合操作:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e785da865dd0feb2961473cfde3f67ec.png)

[image source](https://rubikscode.net/2018/02/26/introduction-to-convolutional-neural-networks/)

这些行被连接起来形成一个长特征向量。如果存在多个输入图层,其行也会被连接起来形成一个更长的特征向量。

然后,特征向量通过多个密集层。在每个密集层,特征向量乘以层的权重,与其偏差相加,并通过非线性。

下图显示了完全连接的操作和密集图层:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/74c8116a674b47df91f00b16f5cbf0f9.png)

[image source](https://cambridgespark.com/content/tutorials/convolutional-neural-networks-with-keras/index.html)

值得注意的是,[根据 Yann LeCun](https://www.facebook.com/yann.lecun/posts/10152820758292143) 的《脸书邮报》,“不存在完全连接的层”,他是对的。当回想卷积层时,人们意识到全连接层是具有 1x1 输出内核的卷积运算。也就是说,如果我们在 n 乘 n 维的图像上通过 128 个 n 乘 n 滤波器,我们将得到长度为 128 的向量。

**代码**

NumPy 使得对 CNN 的全连接层进行编程变得非常简单。事实上,您可以使用 NumPy 的 [reshape](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.reshape.html) 方法在一行代码中完成:

fully connected

在这个代码片段中,我们收集了前一层的尺寸(通道数和高度/宽度),然后使用它们将前一层展平为完全连接的层。这个完全连接的层由多个**密集的神经元层**处理,最终产生原始预测:

dense layers

## 输出层

CNN 的输出层负责在给定输入图像的情况下产生每个类别(每个数字)的概率。为了获得这些概率,我们初始化最终的密集层,使其包含与类别数量相同的神经元。然后,该密集层的输出通过 **Softmax 激活函数**,该函数将所有最终的密集层输出映射到一个向量,该向量的元素总和为 1:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/cd3b1b11c2d0d155af4ada710a01ba83.png)

其中 x 表示最终层输出中的每个元素。

**代码**

同样,softmax 函数可以用几行简单的代码编写:

softmax activation function

## 计算损失

为了测量我们的网络从输入图像中预测手写数字的准确性,我们使用了一个**损失函数**。当预测输出数字时,损失函数分配一个实数值来定义模型的准确性。预测多个输出类时常用的损失函数是**分类交叉熵损失函数,**定义如下:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/12a1ec77356c9d797726fa4bdac0bcda.png)

这里,ŷ是 CNN 的预测,y 是期望的输出标签。当对多个示例进行预测时,我们取所有示例的平均损失。

**代码**

分类交叉熵损失函数可以使用两行简单的代码轻松编程,这是上面所示等式的镜像:

categorical cross-entropy loss

这大概就是构成卷积神经网络的所有操作。让我们加入这些行动来构建 CNN。

# 网络

给定相对低数量的类(总共 10 个)和每个训练图像的小尺寸(28×28 像素)。),选择了一个简单的网络结构来解决数字识别的任务。该网络使用两个连续的卷积层,然后进行最大池操作,以从输入图像中提取特征。在最大池操作之后,表示被展平并通过多层感知器(MLP)来执行分类任务。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/e0bc525c6c87330b181179265c8cb17b.png)

Network Architecture

# 为 CNN 编程

现在,我们已经讨论了形成卷积神经网络的基本操作,让我们来创建它。

在跟进时,请随意使用[这个回购](https://github.com/Alescontrela/Numpy-CNN)。

## 步骤 1:获取数据

MNIST 手写数字训练和测试数据可以在[这里](http://yann.lecun.com/exdb/mnist/)获得。这些文件将图像和标签数据存储为张量,因此必须通过它们的字节流读取这些文件。我们定义了两个助手方法来执行提取:

extract train and test data

## 步骤 2:初始化参数

我们首先定义初始化卷积层的滤波器和密集层的权重的方法。为了使训练过程更平滑,我们用平均值 0 和标准偏差 1 初始化每个滤波器。

methods to initialize the network’s parameters

## 步骤 3:定义反向传播操作

为了计算将迫使网络更新其权重并优化其目标的梯度,我们需要定义通过卷积和最大池层反向传播梯度的方法。为了保持这篇帖子(相对)简短,我不会深入这些梯度的推导,但是,如果你想让我写一篇描述通过卷积神经网络反向传播的帖子,请在下面留下评论。

## 步骤 4:构建网络

在精神抽象中,我们现在定义了一种结合卷积神经网络的向前和向后操作的方法。它将网络的参数和超参数作为输入,并输出梯度:

convolutional neural network forward and backward operation

## 步骤 5:训练网络

为了有效地迫使网络参数学习有意义的表示,我们使用了**亚当优化算法**。关于这个算法,我不会讲太多细节,但可以这样想:如果随机梯度下降是一个喝醉的大学生跌跌撞撞地下山,那么亚当就是一个滚下同一座山的保龄球。更好的解释亚当发现[这里](https://machinelearningmastery.com/adam-optimization-algorithm-for-deep-learning/)。

training the network with Adam optimization

这就概括了网络的发展。要在本地训练它,下载[这个 repo](https://github.com/Alescontrela/Numpy-CNN) 并在终端中运行以下命令:

$ python3 train_cnn.py ‘<file_name>.pkl’


用您喜欢的任何文件名替换`<file_name>`。终端应显示以下进度条,显示培训进度以及当前培训批次的费用。

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/7680b920b9d4c182f756ef5f3de05bf0.png)

a training process with a (very) long way to go

CNN 完成训练后,一个包含网络参数的. pkl 文件被保存到运行脚本的目录中。

在我的 macbook pro 上训练网络大约需要 5 个小时。我在 GitHub repo 中以`params.pkl`的名字包含了经过训练的参数。要使用它们,用`params.pkl`替换`<file_name>`。

要测量网络的准确性,请在终端中运行以下命令:

$ python3 measure_performance.py ‘<file_name>.pkl’


此命令将使用定型参数对测试数据集中的所有 10,000 位数字运行预测。完成所有预测后,显示网络精度的值将出现在命令提示符中:

![](https://gitee.com/OpenDocCN/towardsdatascience-blog-zh-2016to2018/raw/master/docs/img/ff64bf194dc600e96386ee2d15aa33b0.png)

network performance

如果您遇到任何关于依赖关系的问题,可以使用以下命令来安装所需的软件包:

$ pip install -r requirements.txt


# 结果

在对训练集进行两次运算后,网络在测试集上的准确率平均为 98%,我认为这相当不错。在将训练时间延长 2-3 个时期后,我发现测试集的性能下降了。我推测,在第三到第四次训练循环中,网络开始过度适应训练集,不再泛化。

因为我们传递的是成批的数据,网络必须考虑到每一批数据的可变性,这就是为什么在培训期间成本波动如此之大:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2016to2018%2Fraw%2Fmaster%2Fdocs%2Fimg%2Fcdcbef6364bce20f5b6cffa87ad3dffd.png&pos_id=img-cr2NH7Vd-1727112673501)

cost vs. number of iterations

此外,我们测量网络的**回忆**,以了解它能够多好地预测每个数字。回忆是对准确性的一种衡量,它可以通过下面的例子来理解:在我们的测试集中所有标记为“7”(或任何其他数字)的数字中,我们的网络正确预测了多少?

下面的条形图显示了每个数字的召回:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fgitee.com%2FOpenDocCN%2Ftowardsdatascience-blog-zh-2016to2018%2Fraw%2Fmaster%2Fdocs%2Fimg%2F41661a96cc0611bb980520d336e17ba0.png&pos_id=img-O7tzn3t2-1727112673501)

这表明我们的网络学习了所有数字的有意义的表示。总的来说,CNN 概括得很好。

# 结论

希望这篇文章能让你对卷积神经网络有更深入的了解,甚至消除它们的复杂性。如果您有任何问题或想了解更多,请在下面留言:)

## 参考

[1]: Lecun,y .等,“基于梯度的学习应用于文档识别”美国电气和电子工程师学会会议录,第 86 卷,第 11 期,1998 年,第 2278-2324 页。,doi:10.1109/5.726791。

[2]: Krizhevsky,Alex 等,“用深度卷积神经网络进行 ImageNet 分类”*《美国计算机学会通讯*》,第 60 卷,2017 年第 6 期,第 84–90 页。,doi:10.1145/3065386。

[3]:何,,等,“深入挖掘整流器:在 ImageNet 分类上超越人类水平的性能” *2015 年 IEEE 计算机视觉国际会议(ICCV)* ,2015,doi:10.1109/iccv.2015.123
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值