前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零开始深度学习(九):神经网络编程基础

从零开始深度学习(九):神经网络编程基础

作者头像
我是管小亮
发布2020-04-20 16:39:10
1.2K0
发布2020-04-20 16:39:10
举报

文章首发于本人CSDN账号:https://blog.csdn.net/tefuirnever

由于微信不允许外部链接,你需要点击页尾左下角的“阅读原文”,才能访问文中的链接。

1、python中的广播

这是一个不同食物(每100g)中不同营养成分的卡路里含量表格,表格为3行4列,列表示不同的食物种类,从左至右依次为苹果(Apples),牛肉(Beef),鸡蛋(Eggs),土豆(Potatoes)。行表示不同的营养成分,从上到下依次为碳水化合物,蛋白质,脂肪。

那么,现在假设我们想要计算不同食物中不同营养成分中的卡路里百分比,应该怎么做?

以计算苹果中的碳水化合物卡路里百分比含量为例,首先计算苹果(Apples)(100g)中三种营养成分卡路里总和 56+1.2+1.8 = 59,然后用 56 / 59 = 94.9% 算出结果。可以明显地看出苹果(Apples)中的卡路里大部分来自于碳水化合物(Carb),而牛肉(Beef)则不同。对于其他食物,计算方法类似。首先,按列求和,计算每种食物中(100g)三种营养成分总和,然后分别用不用营养成分的卡路里数量除以总和,计算百分比。

那么,能否在向量化的基础上用代码完成这样的一个计算过程呢?

当然是可以的,假设上图的表格是一个4行3列的矩阵 ,记为 ,接下来使用 Pythonnumpy 库完成这样的计算。使用两行代码就可以完成整个过程,第一行代码对每一列进行求和,第二行代码分别计算每种食物每种营养成分的百分比。

jupyter notebook 中输入如下代码,按 Ctrl + Enter 运行,输出如下:

下面再计算每列的和,可以看到输出是每种食物(100g)的卡路里总和。

其中 sum 的参数 axis=0 表示求和运算按列执行,之后会详细解释。

接下来计算百分比,这条指令将 的矩阵 除以一个 的矩阵,得到了一个 的结果矩阵,这个结果矩阵就是要求的百分比含量。

到这里问题就解决了,现在来解释一下 A.sum(axis = 0) 中的参数 axisaxis用来指明将要进行的运算是沿着哪个轴执行,在numpy中,0轴是垂直的,也就是列,而1轴是水平的,也就是行。 而第二个 A / cal.reshape(1, 4) 指令则调用了 numpy 中的广播机制。这里使用 的矩阵 除以 的矩阵 。技术上来讲,其实并不需要再将矩阵 reshape (重塑)成 ,因为矩阵 本身已经是 了。但是当我们写代码的过程中出现不确定矩阵维度的时候,通常会对矩阵进行重塑来确保得到想要的列向量或行向量。重塑操作 reshape 是一个常量时间的操作,时间复杂度是 ,它的调用代价极低,所以使用是没问题的,也推荐大家使用。

那么一个 的矩阵是怎么和 的矩阵做除法的呢?来看一些广播的例子:

numpy 中,当一个 的列向量与一个常数做加法时,实际上会将常数扩展为一个 的列向量,然后两者做逐元素加法。结果就是右边的这个向量。这种广播机制对于行向量和列向量均可以使用。

再看下一个例子。

用一个 的矩阵和一个 的矩阵相加,其泛化形式是 的矩阵和 的矩阵相加。在执行加法操作时,其实是将 的矩阵复制成为 的矩阵,然后两者做逐元素加法得到结果。针对这个具体例子,相当于在矩阵的第一列全部加100,第二列全部加200,第三列全部加300。这就是在前面例子中计算卡路里百分比的广播机制,只不过那里是除法操作,这里是加法操作(广播机制与执行的运算种类无关)。

下面是最后一个例子。

这里相当于是一个 的矩阵加上一个 的矩阵。在进行运算时,会先将 矩阵水平复制 次,变成一个 的矩阵,然后再执行逐元素加法。

广播机制的一般原则如下:

  • 首先是 numpy 广播机制

这里的广播和播音广播是完全不同的,它的要求是什么呢?什么样的条件下可以使用广播?

要求:如果两个数组的后缘维度的轴长度相符或其中一方的轴长度为1,则认为它们是广播兼容的。广播会在缺失维度和轴长度为1的维度上进行。

如何计算后缘维度的轴长度?可以使用代码 A.shape[-1] 即矩阵维度元组中的最后一个位置的值,就是矩阵维度的最后一个维度,比如卡路里计算的例子中,矩阵 后缘维度的轴长度是4,而矩阵 的后缘维度也是4,故满足了后缘维度轴长度相符的条件,可以进行广播。广播会在轴长度为1的维度上进行,轴长度为1的维度对应 axis=0,即垂直方向,矩阵 沿 axis=0 (垂直方向)复制成为 ,之后两者进行逐元素除法运算。

简单概括总结就是,先变成一样大,再逐元素除法。

  • 然后解释图中的例子

矩阵 和矩阵 进行四则运算,后缘维度轴长度相符,符合条件,可以广播,广播沿着轴长度为1的轴进行,即 广播成为 ,之后做逐元素四则运算。

矩阵 和矩阵 进行四则运算,后缘维度轴长度不相符,但其中一方轴长度为1,符合条件,可以广播,广播沿着轴长度为1的轴进行,即 广播成为 ,之后做逐元素四则运算。

矩阵 和常数 进行四则运算,后缘维度轴长度不相符,但其中一方轴长度为1,符合条件,可以广播,广播沿着缺失维度的轴进行,缺失维度就是 axis=0,轴长度为1的轴是 axis=1,即 广播成为 ,之后做逐元素四则运算。

最后总结一下 broadcasting,可以看看下面的图:

2、numpy向量

Python 的特性允许你使用 广播(broadcasting) 功能,这是 Pythonnumpy 程序语言库中最灵活的地方,但这是程序语言的优点,也是缺点。

  • 优点的原因,在于它们创造出语言的表达性,Python 语言巨大的灵活性使得你仅仅通过一行代码就能做很多事情。
  • 缺点的原因,由于广播巨大的灵活性,有时候对于广播的特点以及广播的工作原理这些细节不熟悉的话,可能会产生很细微或者看起来很奇怪的 bug

为了演示 Python-numpy 的一个容易被忽略的效果,特别是怎样在 Python-numpy 中构造向量,来做一个快速示范。

首先设置 ,这样会生成存储在数组 中的5个高斯随机数变量;然后输出 ,从屏幕上可以得知,此时 的 shape(形状) 是一个 的结构同样地, 的 shape 也是这样的。这在 Python 中被称作 一个一维数组。它既不是一个行向量也不是一个列向量,这也导致它有一些不是很直观的效果。

比如 和 的转置阵最终结果看起来一样,shape 也是一样的。但是输出 和 的转置阵的内积,你可能会想, 乘以 的转置,返回的可能会是一个矩阵。但如果这样做,你只会得到一个数。

所以在编写神经网络时,不要使用 shape(5,)(n,) 或者其他一维数组的数据结构。相反,设置 为 ,这样就是一个5行1列的向量。在先前的操作里 和 的转置看起来一样,而现在这样的 变成一个新的 的转置,并且它是一个行向量。当输出 的转置时有两对方括号,而之前只有一对方括号,所以这就是 1行5列的矩阵和一维数组的差别

如果这次再输出 和 的转置的乘积,会返回一个向量的外积,也就是一个矩阵。这就符合我们的预期了,也就是在可控范围内了,因为你知道自己的代码输出是什么了。

除了,输入确定维度的矩阵或向量之外,还有一件事,就是如果你不能完全确定一个向量的维度,建议你扔一个 断言语句(assertion statement) 进去。这样,就可以确保在这种情况下是否是一个 向量了,或者说是一个列向量。

如果不对的话,就会报一个叫做 AssertionError 的错误!!!

3、编程框架

这个我在 大话卷积神经网络CNN(干货满满) 中讲过,目前主流的是 Google的TensorFlowFacebook的pytorch 还有 百度的paddlepaddle,如果是研究的话,我建议使用TensorFlow,因为它更好理解一下基础原理,而不是单纯的调包侠,不过现在pytorch的使用要更热门一些,社区也更广,推荐学习。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-02-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员管小亮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档