[代码学习]einsum详解

2023-10-11 12:01
文章标签 代码 学习 详解 einsum

本文主要是介绍[代码学习]einsum详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

einsum详解

该函数用于对一组输入 Tensor 进行 Einstein 求和,该函数目前仅适用于paddle的动态图。

Einstein 求和是一种采用 Einstein 标记法描述的 Tensor 求和,输入单个或多个 Tensor,输出单个 Tensor。

在这里插入图片描述

paddle.einsum(equation, *operands)

参数

  • equation (str):求和标记
  • operands (Tensor, [Tensor, …]):输入 Tensor

返回

  • Tensor:输出 Tensor

求和特例

  • 单操作数

    • 迹:trace

    • 对角元:diagonal

    • 转置:transpose

    • 求和:sum

  • 双操作数

    • 内积:dot

    • 外积:outer

    • 广播乘积:mul,*

    • 矩阵乘:matmul

    • 批量矩阵乘:bmm

  • 多操作数

    • 广播乘积:mul,*

    • 多矩阵乘:A.matmul(B).matmul(C)

关于求和标记的约定

  • 维度分量下标:Tensor 的维度分量下标使用英文字母表示,不区分大小写,如’ijk’表示 Tensor 维度分量为 i,j,k

  • 下标对应输入操作数:维度下标以`,`分段,按顺序 1-1 对应输入操作数

  • 广播维度:省略号`…`表示维度的广播分量,例如,'i…j’表示首末分量除外的维度需进行广播对齐

  • 自由标和哑标:输入标记中仅出现一次的下标为自由标,重复出现的下标为哑标,哑标对应的维度分量将被规约消去

  • 输出:输出 Tensor 的维度分量既可由输入标记自动推导,也可以用输出标记定制化

  • 自动推导输出

    • 广播维度分量位于维度向量高维位置,自由标维度分量按字母顺序排序,位于维度向量低纬位置,哑标维度分量不输出
  • 定制化输出

    • 维度标记中`->`右侧为输出标记

    • 若输出包含广播维度,则输出标记需包含`…`

    • 输出标记为空时,对输出进行全量求和,返回该标量

    • 输出不能包含输入标记中未出现的下标

    • 输出下标不可以重复出现

    • 哑标出现在输出标记中则自动提升为自由标

    • 输出标记中未出现的自由标被降为哑标

例子

  • ‘…ij, …jk’,该标记中 i,k 为自由标,j 为哑标,输出维度’…ik’

  • ‘ij -> i’,i 为自由标,j 为哑标

  • ‘…ij, …jk -> …ijk’,i,j,k 均为自由标

  • ‘…ij, …jk -> ij’,若输入 Tensor 中的广播维度不为空,则该标记为无效标记

求和规则

Einsum 求和过程理论上等价于如下四步,但实现中实际执行的步骤会有差异。

  • 第一步,维度对齐:将所有标记按字母序排序,按照标记顺序将输入 Tensor 逐一转置、补齐维度,使得处理后的所有 Tensor 其维度标记保持一致

  • 第二步,广播乘积:以维度下标为索引进行广播点乘

  • 第三步,维度规约:将哑标对应的维度分量求和消除

  • 第四步,转置输出:若存在输出标记,则按标记进行转置,否则按广播维度+字母序自由标的顺序转置,返回转之后的 Tensor 作为输出

关于 trace 和 diagonal 的标记约定(待实现功能)

  • 在单个输入 Tensor 的标记中重复出现的下标称为对角标,对角标对应的坐标轴需进行对角化操作,如’i…i’表示需对首尾坐标轴进行对角化

  • 若无输出标记或输出标记中不包含对角标,则对角标对应维度规约为标量,相应维度取消,等价于 trace 操作

  • 若输出标记中包含对角标,则保留对角标维度,等价于 diagonal 操作

实例实践

首先,看一下一维度简单实验:

import paddle# 定义两个输入矩阵
# paddle.seed(102)
# x = paddle.rand([4])
# y = paddle.rand([5])
x = paddle.to_tensor([1,2,], dtype='float32')
y = paddle.to_tensor([3,4,5], dtype='float32')# sum
sum_x = paddle.einsum('i->', x).numpy()# dot
dox_x = paddle.einsum('i,i->', x, x).numpy()# outer
outer_xy = paddle.einsum("i,j->ij", x, y).numpy()print(f"x: {x.numpy()}, shape: {x.shape}")
print(f"y: {y.numpy()}, shape: {y.shape}")
print(f"sum_x: {sum_x}, shape: {sum_x.shape}")
print(f"dox_x: {dox_x}, shape: {dox_x.shape}")
print(f"outer_xy: {outer_xy}, shape: {outer_xy.shape}")

结果输出为:

x: [1. 2.], shape: [2]
y: [3. 4. 5.], shape: [3]
sum_x: 3.0, shape: ()
dox_x: 5.0, shape: ()
outer_xy: [[ 3.  4.  5.][ 6.  8. 10.]], shape: (2, 3)

然后,看一下高纬度的实验:

import paddle# A = paddle.rand([2, 3, 2])
# B = paddle.rand([2, 2, 3])
A = paddle.to_tensor([[[1,2],[1,2],[1,2]], [[1,2],[1,2],[1,2]]], dtype='float32')
B = paddle.to_tensor([[[3,4,5],[3,4,5]], [[3,4,5],[3,4,5]]], dtype='float32')# transpose
transpose_A = paddle.einsum('ijk->kji', A)# batch matrix multiplication
BMM_AB = paddle.einsum('ijk, ikl->ijl', A,B)# Ellipsis transpose
ET_A = paddle.einsum('...jk->...kj', A)# Ellipsis batch matrix multiplication
EBMM_AB = paddle.einsum('...jk, ...kl->...jl', A,B)print(f"A: {A.numpy()}, shape: {A.shape}")
print(f"B: {B.numpy()}, shape: {B.shape}")
print(f"transpose_A: {transpose_A.numpy()}, shape: {transpose_A.shape}")
print(f"BMM_AB: {BMM_AB.numpy()}, shape: {BMM_AB.shape}")
print(f"ET_A: {ET_A.numpy()}, shape: {ET_A.shape}")
print(f"EBMM_AB: {EBMM_AB.numpy()}, shape: {EBMM_AB.shape}")

结果输出为:

A: [[[1. 2.][1. 2.][1. 2.]][[1. 2.][1. 2.][1. 2.]]], shape: [2, 3, 2]
B: [[[3. 4. 5.][3. 4. 5.]][[3. 4. 5.][3. 4. 5.]]], shape: [2, 2, 3]
transpose_A: [[[1. 1.][1. 1.][1. 1.]][[2. 2.][2. 2.][2. 2.]]], shape: [2, 3, 2]
BMM_AB: [[[ 9. 12. 15.][ 9. 12. 15.][ 9. 12. 15.]][[ 9. 12. 15.][ 9. 12. 15.][ 9. 12. 15.]]], shape: [2, 3, 3]
ET_A: [[[1. 1. 1.][2. 2. 2.]][[1. 1. 1.][2. 2. 2.]]], shape: [2, 2, 3]
EBMM_AB: [[[ 9. 12. 15.][ 9. 12. 15.][ 9. 12. 15.]][[ 9. 12. 15.][ 9. 12. 15.][ 9. 12. 15.]]], shape: [2, 3, 3]

reference

关于matmul可以查看:https://blog.csdn.net/orDream/article/details/133744368
官方链接:
@misc{BibEntry2023Oct,
title = {{einsum-API文档-PaddlePaddle深度学习平台}},
year = {2023},
month = oct,
urldate = {2023-10-10},
language = {chinese},
note = {[Online; accessed 10. Oct. 2023]},
url = {https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/einsum_cn.html}
}

这篇关于[代码学习]einsum详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/187911

相关文章

利用Python调试串口的示例代码

《利用Python调试串口的示例代码》在嵌入式开发、物联网设备调试过程中,串口通信是最基础的调试手段本文将带你用Python+ttkbootstrap打造一款高颜值、多功能的串口调试助手,需要的可以了... 目录概述:为什么需要专业的串口调试工具项目架构设计1.1 技术栈选型1.2 关键类说明1.3 线程模

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

Java中的@SneakyThrows注解用法详解

《Java中的@SneakyThrows注解用法详解》:本文主要介绍Java中的@SneakyThrows注解用法的相关资料,Lombok的@SneakyThrows注解简化了Java方法中的异常... 目录前言一、@SneakyThrows 简介1.1 什么是 Lombok?二、@SneakyThrows

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Redis Pipeline(管道) 详解

《RedisPipeline(管道)详解》Pipeline管道是Redis提供的一种批量执行命令的机制,通过将多个命令一次性发送到服务器并统一接收响应,减少网络往返次数(RTT),显著提升执行效率... 目录Redis Pipeline 详解1. Pipeline 的核心概念2. 工作原理与性能提升3. 核

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组