探秘TensorFlow 和 NumPy 的 Broadcasting 机制
作者:文哥的学习日记 发布时间:2023-07-22 06:09:50
在使用Tensorflow的过程中,我们经常遇到数组形状不同的情况,但有时候发现二者还能进行加减乘除的运算,在这背后,其实是Tensorflow的broadcast即广播机制帮了大忙。而Tensorflow中的广播机制其实是效仿的numpy中的广播机制。本篇,我们就来一同研究下numpy和Tensorflow中的广播机制。
1、numpy广播原理
1.1 数组和标量计算时的广播
标量和数组合并时就会发生简单的广播,标量会和数组中的每一个元素进行计算。
举个例子:
arr = np.arange(5)
arr * 4
得到的输出为:
array([ 0, 4, 8, 12, 16])
这个是很好理解的,我们重点来研究数组之间的广播
1.2 数组之间计算时的广播
用书中的话来介绍广播的规则:两个数组之间广播的规则:如果两个数组的后缘维度(即从末尾开始算起的维度)的轴长度相等或其中一方的长度为1,则认为他们是广播兼容的,广播会在缺失和(或)长度为1的维度上进行。
上面的规则挺拗口的,我们举几个例子吧:
二维的情况
假设有一个二维数组,我们想要减去它在0轴和1轴的均值,这时的广播是什么样的呢。
我们先来看减去0轴均值的情况:
arr = np.arange(12).reshape(4,3)
arr-arr.mean(0)
输出的结果为:
array([[-4.5, -4.5, -4.5],
[-1.5, -1.5, -1.5],
[ 1.5, 1.5, 1.5],
[ 4.5, 4.5, 4.5]])
0轴的平均值为[4.5,5.5,6.5],形状为(3,),而原数组形状为(4,3),在进行广播时,从后往前比较两个数组的形状,首先是3=3,满足条件而继续比较,这时候发现其中一个数组的形状数组遍历完成,因此会在缺失轴即0轴上进行广播。
可以理解成将均值数组在0轴上复制4份,变成形状(4,3)的数组,再与原数组进行计算。
书中的图形象的表示了这个过程(数据不一样请忽略):
我们再来看一下减去1轴平均值的情况,即每行都减去该行的平均值:
arr - arr.mean(1)
此时报错了:
我们再来念叨一遍我们的广播规则,均值数组的形状为(4,),而原数组形状为(4,3),按照比较规则,4 != 3,因此不符合广播的条件,因此报错。
正确的做法是什么呢,因为原数组在0轴上的形状为4,我们的均值数组必须要先有一个值能够跟3比较同时满足我们的广播规则,这个值不用多想,就是1。因此我们需要先将均值数组变成(4,1)的形状,再去进行运算:
arr-arr.mean(1).reshape((4,1))
得到正确的结果:
array([[-1., 0., 1.],
[-1., 0., 1.],
[-1., 0., 1.],
[-1., 0., 1.]])
三维的情况
理解了二维的情况,我们也就能很快的理解三维数组的情况。
首先看下图:
根据广播原则分析:arr1的shape为(3,4,2),arr2的shape为(4,2),它们的后缘轴长度都为(4,2),所以可以在0轴进行广播。因此,arr2在0轴上复制三份,shape变为(3,4,2),再进行计算。
不只是0轴,1轴和2轴也都可以进行广播。但形状必须满足一定的条件。举个例子来说,我们arr1的shape为(8,5,3),想要在0轴上广播的话,arr2的shape是(1,5,3)或者(5,3),想要在1轴上进行广播的话,arr2的shape是(8,1,3),想要在2轴上广播的话,arr2的shape必须是(8,5,1)。
我们来写几个例子吧:
arr2 = np.arange(24).reshape((2,3,4))
arr3_0 = np.arange(12).reshape((3,4))
print("0轴广播")
print(arr2 - arr3_0)
arr3_1 = np.arange(8).reshape((2,1,4))
print("1轴广播")
print(arr2 - arr3_1)
arr3_2 = np.arange(6).reshape((2,3,1))
print("2轴广播")
print(arr2 - arr3_2)
输出为:
0轴广播
[[[ 0 0 0 0]
[ 0 0 0 0]
[ 0 0 0 0]][[12 12 12 12]
[12 12 12 12]
[12 12 12 12]]]
1轴广播
[[[ 0 0 0 0]
[ 4 4 4 4]
[ 8 8 8 8]][[ 8 8 8 8]
[12 12 12 12]
[16 16 16 16]]]
2轴广播
[[[ 0 1 2 3]
[ 3 4 5 6]
[ 6 7 8 9]][[ 9 10 11 12]
[12 13 14 15]
[15 16
17 18]]]
如果我们想在两个轴上进行广播,那arr2的shape要满足什么条件呢?
arr1.shape | 广播轴 | arr2.shape |
---|---|---|
(8,5,3) | 0,1 | (3,),(1,3),(1,1,3) |
(8,5,3) | 0,2 | (5,1),(1,5,1) |
(8,5,3) | 1,2 | (8,1,1) |
具体的例子就不给出啦,嘻嘻。
2、Tensorflow 广播举例
Tensorflow中的广播机制和numpy是一样的,因此我们给出一些简单的举例:
二维的情况
sess = tf.Session()
a = tf.Variable(tf.random_normal((2,3),0,0.1))
b = tf.Variable(tf.random_normal((2,1),0,0.1))
c = a - b
sess.run(tf.global_variables_initializer())
sess.run(c)
输出为:
array([[-0.1419442 , 0.14135399, 0.22752595],
[ 0.1382471 , 0.28228047, 0.13102233]], dtype=float32)
三维的情况
sess = tf.Session()
a = tf.Variable(tf.random_normal((2,3,4),0,0.1))
b = tf.Variable(tf.random_normal((2,1,4),0,0.1))
c = a - b
sess.run(tf.global_variables_initializer())
sess.run(c)
输出为:
array([[[-0.0154749 , -0.02047186, -0.01022427, -0.08932371],
[-0.12693939, -0.08069084, -0.15459496, 0.09405404],
[ 0.09730847, 0.06936138, 0.04050628, 0.15374713]],[[-0.02691782, -0.26384184, 0.05825682, -0.07617196],
[-0.02653179, -0.01997554, -0.06522765, 0.03028341],
[-0.07577246, 0.03199019, 0.0321 , -0.12571403]]], dtype=float32)
错误示例
sess = tf.Session()
a = tf.Variable(tf.random_normal((2,3,4),0,0.1))
b = tf.Variable(tf.random_normal((2,4),0,0.1))
c = a - b
sess.run(tf.global_variables_initializer())
sess.run(c)
输出为:
ValueError: Dimensions must be equal, but are 3 and 2 for 'sub_2' (op: 'Sub') with input shapes: [2,3,4], [2,4].
来源:https://www.jianshu.com/p/550c90dfffa0


猜你喜欢
- orm查询优化1)only与referonly方法返回的是一个queryset对象,本质就是列表套数据对象该对象内只含有only括号所指定的
- <!DOCTYPE HTML> <html> <head> <title>test1<
- --创建测试数据库 CREATE DATABASE Db GO --对数据库进行备份 BACKUP DATABASE Db TO DISK=
- 前言:stored procedure 完成特定功能的SQL语句集,存储在数据库中,经过第一次编译之后再次调用不需要编译(效率较高)1、存储
- 这篇文章主要介绍了简单了解python字符串前面加r,u的含义,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,
- 一、无组件上传的原理我还是一点一点用一个实例来说明的吧,客户端HTML如下。要浏览上传附件,我们通过<input type="
- 当我们建好数据库及表后,首先想到的就是向数据库的表中输入数据.下面我们就来探讨一下如何向数据库增加数据:1.常用的方法是insert语句in
- 突如其来想知道一下 python 如何修改文件的属性(创建、修改、访问时间),于是就去网上搜集了可行方案,也就有了这篇博客方案一from w
- 前言本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。闲来无事听听歌,听
- 整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,0的阶乘为1。即:n!=1×2×3×...×n。首先导入math模块
- pytorch中为什么要用 zero_grad() 将梯度清零调用backward()函数之前都要将梯度清零,因为如果梯度不清零,pytor
- 本文详细讲述了Python使用MySQLdb for Python操作数据库的方法,分享给大家供大家参考。具体如下:一般来说网站就是要和数据
- 今天萌发一个想法,用css来实现透视效果。起初,我想到的是我们常见的添加阴影效果的方法,用多个div通过偏移来实现,但这需要很多 div,不
- 1、安装MSSQL时使用混合模式,当然SA密码最好不能为空,在SQL2005中,可以对SA这个超级用户名进行修改或删除。use master
- 最近,我有机会在一个真实的 Golang 场景中使用泛型,同时寻找与 Stream filter(Predicate<? super
- 如下所示:d = { 'a': '0.0000', 'b':
- 设置密码保护SqlServer数据库备份文件! 备份SqlServer数据库 Backup Database [数据库] To disk=&
- 背景介绍PyTorch 训练的模型,需要在Jetson nano 上部署,jetson 原生提供了TensorRT 的支持,所以一个比较好的
- 近来在做数据库设计,有时候真弄不清SQL2000里的数据类型,所以摘了这篇文章。 (1)char、varchar、text和nchar、nv
- django-debug-toolbar介绍django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试