Broadcasting in Python
在上一个视频中 我提到了 广播是另一种能使Python代码运行得更快的技术 在这个视频中 我们将深入研究Python中广播的运行机制 让我们用一个例子来解释广播 在这个矩阵中 我展示了各100克的4种不同食物中 碳水化合物 蛋白质 脂肪的卡路里(Calorie)含量 比如 在100克苹果中 有56大卡的热量来自碳水化合物 而来自蛋白质和脂肪的热量就少多了 相比之下 在100克的牛肉中 有104大卡的热量来自蛋白质 有135大卡的热量来自脂肪 现在 假设你的目标是计算每种食物的热量中 来自碳水化合物 蛋白质和脂肪的比例 举例来说 你看这一列 将其中的数字相加 你会得到100克苹果中 含有56+1.2+1.8=59大卡 所以 苹果所含的热量中 来自碳水化合物的百分比 应该是56/59 大约是94.9% 所以苹果中大部分的热量都来自碳水化合物 与之相反 牛肉中大部分的热量来自蛋白质和脂肪 所以你需要做的计算是 分别对矩阵的四列求和 得到100克的苹果 牛肉 鸡蛋和土豆中 含有的总热量 并将矩阵的每个元素都除以对应列的和
以得到每种食物中 来自碳水化合物 蛋白质和脂肪的 热量的百分比 问题在于 你能不用显式的for循环来完成这一操作吗? 让我们看看应该怎么做
我将向你展示如何做到 比如说这个3乘4的矩阵A 我们可以用一行Python代码对每列求和 我们将会得到四个数字 分别对应100克的 4种不同食物中的总热量 接着我用第二行Python代码 使每一列都除以对应的列的和 如果这些口头说明不是很清晰 希望你在看到Python代码时会更加清楚 现在我们进入Jupyter笔记本 我已经写好了第一段代码 向矩阵A填充了前面的数值 按下Shift+Enter运行 可以看到这就是矩阵A 接着是两行Python代码 首先计算 cal=A.sum(axis=0) axis=0的意思是沿垂直方向求和 我们很快还会提到它 接着 print(cal) 可以看到已经按列求和了 这里的59是苹果的总大卡数 239是牛肉热量的大卡数 还有鸡蛋和土豆的 然后计算百分比 percentage=A/cal.reshape(1,4) 实际上我们要的是百分比数值 所以乘以100
然后 print(percentage)
运行一下 在这个命令中 我们用矩阵A 除以了这个1乘4的矩阵 从而得到了百分比矩阵 就像我们刚才手算得出的 苹果中有94.9%的热量来自碳水化合物 回到幻灯片来 把刚才的两行代码重写如下 就是我们刚在Jupyter笔记本上写的 需要说明的是 这个axis=0的参数 表示着你想让Python沿垂直方向求和 如果axis=0 意味着垂直相加 反之 水平轴的axis是1 所以写axis=1就可以水平求和 而不是垂直求和 接下来 对于这个命令 这是一个Python广播的例子 用一个3乘4的矩阵A 除以一个1乘4的矩阵 严格地说 在第一行代码执行完毕之后 cal已经是一个1乘4的矩阵 所以严格地说 你不需要再在这里调用reshape 这实际上有些多余 但当我写Python代码时 如果我不确定某个矩阵的维数 我通常会调用reshape 以确保它是正确的列向量或者行向量 或者任何你想要的维数 reshape消耗常量的时间 是一个O(1)的操作 调用的成本很低 所以不要怕用reshape来确保 矩阵是你想要的尺寸
现在 我将深入解释这种操作的机制 我们用3乘4的矩阵除以1乘4的矩阵 怎么能用3乘4的矩阵除以1乘4的矩阵呢? 或者说 除以1乘4的向量?
我们再看几个广播的例子 如果你有一个4乘1的向量 让它加一个数字 Python会自动将这个数字 扩展成这样一个4乘1的向量 例如对于向量[1 2 3 4] 加上数字100 就会得到右边那个向量 你给每个数字都加了100 实际上我们之前使用过这种广播 这里所加的常数就是前面视频中的参数b 这种广播适用于行向量和列向量 实际上 我们之前已经使用过了类似形式的广播 之前在逻辑回归中的参数b 就相当于我们这里为向量加上的常量 再来看一个例子 假设有一个2乘3的矩阵 让它加上这个1乘n的矩阵
一般情况而言 如果你让一个m乘n的矩阵 加上一个1乘n的矩阵 Python会将后者复制m次 使其变为一个m乘n的矩阵 所以在这个例子中 这个1乘3的矩阵会被复制两次 成为一个2乘3的矩阵 然后相加得到右边的和 所以 你对第一列加了100 对第二列加了200 对第三列加了300 这基本上就是我们在前一页中所做的 只不过当时我们用的是除法操作 而这里是加法操作
再举最后一个例子 假设你有一个m乘n的矩阵 让它加上一个m乘1的向量 或者说m乘1的矩阵 7:47 后者会在水平方向复制n次 所以你会得到一个m乘n的矩阵 你可以想象它被水平地复制了三次 然后相加 相加后得到这个结果 我们给第一行加了100 第二行加了200 8:08 以下是Python广播的一些通用规则 如果你有一个m乘n的矩阵 让它加减乘除以一个1乘n的矩阵 后者会被复制m次 成为一个m乘n的矩阵 然后再逐元素地进行 加减乘除操作 8:37 反之 如果你让一个m乘n的矩阵 加减乘除以一个m乘1的矩阵 后者也会复制n次 成为一个m乘n的矩阵 然后再逐元素地进行运算操作 广播的另一种形式是 如果你有一个m乘1的矩阵 它实际上是一个列向量 比如[1 2 3] 然后让它加减乘除以一个实数 也就是一个1乘1的矩阵 比如加上100 那么这个实数会被复制m次 得到一个m乘1的矩阵 然后再逐元素地进行运算 例如这个例子中的加法操作 类似地 这也可以用于行向量 9:38 广播的全部功能比这里介绍的还要多 如果你感兴趣 可以去阅读NumPy的相关文档 并查看其中关于广播的部分 那里会给出更广泛的广播的定义 这节课的幻灯片中给出的是 你在实现神经网络时 需要用到的广播的主要形式
结束之前 我最后插一句 对于习惯使用MATLAB或Octave编程的同学 如果你在神经网络编程中 用过MATLAB或Octave的bsxfun函数 其实bsxfun做的事情类似 但并不完全一样 它与我们在Python中使用广播的目的是一致的 这只是对于非常高端的 MATLAB和Octave用户而言 如果你没听说过 不用担心 当你在Python中编写神经网络时 并不需要知道它 以上就是Python的广播机制 我希望当你在做编程作业时 广播不仅能让你的程序跑得更快 也帮助你用更少的代码达到目的 10:50 在你进行编程练习之前 我还想再和大家分享一些点子 也就是一些能帮我减少Python代码中的bug的技巧 希望也能帮到你 那么 我们下个视频见
Last updated
Was this helpful?