当前位置: 首页 > news >正文

NumPy 2.x 完全指南【十九】广播机制

文章目录

  • 1. 概述
  • 2. 广播规则
    • 2.1 补齐维度
    • 2.2 扩展大小为 1 的轴
  • 3. 案例演示
    • 3.1 算数运算
      • 3.1.1 加法运算
      • 3.1.2 除法运算
    • 3.2 比较运算
    • 3.3 逻辑运算

1. 概述

广播Broadcasting机制:在满足特定条件的情况下,较小的数组会在较大的数组上进行自动扩展,使它们的形状兼容,从而允许不同形状的数组之间进行数值运算。

如果没有广播机制,在 NumPy 中是对两个数组进行运算时,它们必须具有完全相同的形状,比如进行乘法运算:

a = np.array([1.0, 2.0, 3.0])  # 形状 (3,)
b = np.array([2.0, 2.0, 2.0])  # 形状 (3,)
result = a * b
print(result)  # 输出: [2., 4., 6.]

运算过程是逐元素进行的,数学公式表示如下:
a ∗ b = [ 1.0 2.0 3.0 ] ∗ [ 2.0 2.0 2.0 ] = [ 1.0 ∗ 2.0 2.0 ∗ 2.0 3.0 ∗ 2.0 ] = [ 2.0 4.0 6.0 ] \mathbf{a} * \mathbf{b} = \begin{bmatrix} 1.0 \\ 2.0 \\ 3.0 \end{bmatrix} * \begin{bmatrix} 2.0 \\ 2.0 \\ 2.0 \end{bmatrix}= \begin{bmatrix} 1.0 * 2.0 \\ 2.0 * 2.0 \\ 3.0 * 2.0 \end{bmatrix} = \begin{bmatrix} 2.0 \\ 4.0 \\ 6.0 \end{bmatrix} ab= 1.02.03.0 2.02.02.0 = 1.02.02.02.03.02.0 = 2.04.06.0

NumPy 中一个数组可以直接和一个标量值进行运算:

a = np.array([1.0, 2.0, 3.0])
b = 2.0
print(a * b)
# array([2.,  4.,  6.])

当运算中的 2 个数组的形状不同时,会自动触发广播机制,标量 b 在算术操作过程中自动扩展为与 a 具有相同形状的数组,从而使它们在逐元素乘法时的形状兼容:
在这里插入图片描述

🔨 提示: 扩展的类比只是概念性的,实际没有真的复制数据,而是虚拟复制(无实际内存开销),从而使广播操作在内存和计算效率上尽可能高效。

2. 广播规则

广播遵循两个规则,确保不同形状的数组能够兼容:

  • 补齐维度:若数组维度数不同,在形状较小的数组前面补 1,直到所有数组维度数相同。
  • 扩展大小为 1 的轴:若数组在某一维度上的大小为 1,则沿该维度复制数据,使其大小与其他数组对应的维度保持一致。

2.1 补齐维度

在对两个数组进行操作时,输入数组不需要具有相同的维度数。NumPy 会从尾部(即最右边的)维度开始,逐元素比较它们的形状,对于维度数少的数组,并用 1 补齐。

例如,有一个 (256x256x3)RGB 图像数据,用不同的值来缩放每个通道的颜色:

image = np.ones((256, 256, 3))  #      形状 (256, 256, 3)
scaling = np.array([0.5, 1.0, 1.5])  #          形状 (3,)
result = image * scaling # 形状 (256, 256, 3)

从右到左比较,维度对齐过程如下:

  • 3 维中 image=3scaling=3 ,值相等表示形状兼容。
  • 21 维中 image=256scaling 维度不足,进行补 1 操作, 自动广播为 (1, 1, 3) 的形状。

补齐后,需要确保每个维度满足以下条件之一:

  • 维度相等​:两个数组在该维度上的大小相同。
  • 维度为 1 ​:其中一个数组在该维度上的大小为 1

示例,若任意维度不满足上述条件,表示数组的形状不兼容,则抛出 ValueError: operands could not be broadcast together

a = np.ones((2, 3))  # 形状 (2,3) 和  (1, 2) 不兼容
b = np.ones((2,))     # 形状 (2,) → 补齐为 (1, 2)(左侧补1)
try:
result = a + b
except ValueError as e:
print(e)  # 输出: operands could not be broadcast together...

结果数组的维度数是输入数组中维度数的最大值,每个维度的大小按以下规则确定:

  • 若两个数组在该维度上的大小相同 → 结果维度大小不变。
  • 若其中一个数组在该维度上的大小为 1 → 结果维度大小为另一个数组的维度大小。
  • 若某一数组在该维度不存在(维度数不足) → 默认为大小为 1 ,再按上述规则处理。

2.2 扩展大小为 1 的轴

进行维度补齐后,会扩展大小为 1 的轴,仅仅是逻辑上的扩展,实际上并不复制数据。

例如,上面示例中图像和缩放因子的形状在维度补齐后为:

  • image=256(256, 256, 3)
  • scaling(1, 1, 3)

其中,只有 scaling 在第一、二轴上的大小为 1 ,那么就需要进行扩展,扩展为另外一个数组同轴大小,即:

  • 0 轴: 扩展为 256
  • 1 轴: 扩展为 256

最终 scaling 扩展后的形状为 (256, 256, 3) ,和 image 是形状兼容的同型数组,接下来就可以进行逐元素运算了。

3. 案例演示

3.1 算数运算

3.1.1 加法运算

如果一维数组的元素数量与二维数组的列数相匹配,将一维数组加到二维数组上会导致广播。

示例 1 ,二维数组和一维数组相加,其中 b 的维度会补齐为 (1,3) ,然后第一个维度的 1 会被扩展为 a 对应位置的维度大小 4 ,最终 b 的形状被扩展为 (4,3) ,与 a 兼容:

a = np.array([[ 0.0,  0.0,  0.0],[10.0, 10.0, 10.0],[20.0, 20.0, 20.0],[30.0, 30.0, 30.0]]) # (4,3)b = np.array([1.0, 2.0, 3.0])# (3)
print(a + b)
# [[ 1.  2.  3.]
#  [11. 12. 13.]
#  [21. 22. 23.]
#  [31. 32. 33.]]

过程图示:
在这里插入图片描述

当数组的尾部维度不相等时,广播会失败,因为无法将第一个数组的行中的值与第二个数组的元素对齐进行逐元素相加:
在这里插入图片描述

3.1.2 除法运算

图像归一化(Image Normalization)是一种将图像像素值调整到统一范围或分布的数据预处理技术,主要用于消除量纲差异、加速模型训练并提升算法稳定性。

常用的归一化方法有:

  • Min-Max 归一化(最小-最大值归一化)
  • Z-Score 标准化(均值-方差归一化)

Min-Max归一化通过线性变换将原始数据缩放到指定的区间,通常为 [0, 1][-1, 1] 。在深度学习图像任务中,一般需要将图像像素值从 [0, 255] 缩放到 [0, 1],便于卷积操作。

基础公式:
X norm = X − X min X max − X min X_{\text{norm}} = \frac{X - X_{\text{min}}}{X_{\text{max}} - X_{\text{min}}} Xnorm=XmaxXminXXmin

符号定义:

  • X X X: 原始数据。
  • X min X_{\text{min}} Xmin: 数据的最小值。
  • X max X_{\text{max}} Xmax: 数据的最大值。
  • X norm X_{\text{norm}} Xnorm: 归一化后的数据。

X_minX_max 通常是数据集中每个特征的最小和最大值,对于 8 位无符号整型图像来说,像素范围固定为 [0, 255]归一化时直接使用:
X norm = X 255 (等价于  X min = 0 , X max = 255 ) X_{\text{norm}} = \frac{X}{255} \quad \text{(等价于 } X_{\text{min}}=0,\ X_{\text{max}}=255 \text{)} Xnorm=255X(等价于 Xmin=0, Xmax=255

这样,我们直接使用图像数据除以 255 就能实现归一化,示例代码:

# 创建一个形状为 (224, 224, 3) 的随机 RGB 图像
image = np.random.randint(0, 256, size=(224, 224, 3)).astype(np.float32)# 归一化
normalized = image / 255  # 广播到 (224,224,3)
print(normalized) # shape (224,224,3)
# [[[0.8        0.27450982 0.37254903]
#   [0.3137255  0.29803923 0.36862746]
#   [0.4627451  0.5254902  0.        ]......

其中,标量 255 会补齐维度为(1,1,1),然后扩展为 (224,224,3),再执行逐元素计算。

3.2 比较运算

示例 1 ,一维数组与标量比较:

a = np.array([1, 2, 3])  # 形状 (3,)
result = a > 2            # 标量 2 广播到形状 (3,)
print(result)             # [False False  True]

示例 2 ,一维数组与二维数组比较:

a = np.array([[1, 2],[3, 4]])  # 形状 (2,2)b = np.array([2, 3])    # 形状 (2,)
result = a >= b         # b 广播为(1,2) → 扩展为(2,2)
print(result)
# [[False False]
#  [ True  True]]

3.3 逻辑运算

示例 1 ,一维数组与标量的逻辑运算:

# 生成布尔数组
a = np.array([True, False, True])  # 形状 (3,)
b = True  # 标量result_and = np.logical_and(a, b)  # 标量广播到形状(3,)
result_or = np.logical_or(a, b)print("AND:", result_and)  # [True False True]
print("OR:", result_or)  # [True  True True]

示例 2 ,一维数组与二维数组逻辑运算:

a = np.array([[True, False],[False, True]])  # 形状 (2,2)
b = np.array([True, False])    # 形状 (2,)result = np.logical_and(a, b)  # b广播为(1,2) → 扩展为(2,2)
print(result)
# [[ True False]
#  [False False]]
http://www.xdnf.cn/news/661753.html

相关文章:

  • Windows 拓展Path环境变量
  • uniapp 搭配uviwe u-picker 实现地区联栋
  • ETL 工具与数据中台的关系与区别
  • 1.6 如何使用命令行执行 TypeScript 文件
  • Transformer,多头注意力机制 隐式学习子空间划分
  • JAVA Zip导入导出实现
  • 20250526给荣品PRO-RK3566的Android13单独编译boot.img
  • Python程序中字符串与JSON转换的最佳实践详解
  • Java 杂谈
  • 记一个小问题:Cookie 作用域规则
  • Dify中的Agent策略插件开发例子:以Function Calling为例
  • 重磅升级!Docusign IAM 2025 V1 版本上线,重塑智能协议新体验
  • Windows逆向工程提升之IMAGE_RUNTIME_FUNCTION_ENTRY
  • 按键状态机
  • FFmpeg 4.3 H265 二十二.3,avformat_open_input 支持打开的协议
  • 07-多线程案例-任务调度
  • NoteGen 如何使用 AI 进行记录
  • set和map简单模拟实现
  • TCP 三次握手过程详解
  • 【Java学习笔记】抽象类
  • 时间的基本概念及相关技术
  • 通用寄存器 专用寄存器
  • 大模型训练中的GPU作用解析
  • 项目三 - 任务8:实现词频统计功能
  • 基于Geotools的Worldpop世界人口tif解析-以中国2020年数据为例
  • 北京大学肖臻老师《区块链技术与应用》公开课:02-BTC-密码学原理
  • Excel快捷键大全
  • 深入理解Java装饰器模式:动态扩展对象功能的优雅之道
  • USB设备状态
  • pyhton基础【5】循环