Tensor基础实践
Tensor基础实践
飞桨(PaddlePaddle,以下简称Paddle)和其他深度学习框架一样,使用Tensor来表示数据,在神经网络中传递的数据均为Tensor。
Tensor可以将其理解为多维数组,其可以具有任意多的维度,不同Tensor可以有不同的数据类型 (dtype) 和形状 (shape)。
同一Tensor的中所有元素的dtype均相同。如果对 Numpy 熟悉,Tensor是类似于 Numpy array 的概念。
Tensor的创建
首先,让开始创建一个 Tensor , 并用 ndim 表示 Tensor 维度的数量:
1. 创建类似于vector的1-D Tensor,其 ndim 为1
# 可通过dtype来指定Tensor数据类型,否则会创建float32类型的Tensor
ndim_1_tensor = paddle.to_tensor([2.0, 3.0, 4.0], dtype='float64')
print(ndim_1_tensor)
Tensor(shape=[3], dtype=float64, place=CUDAPlace(0), stop_gradient=True,
[2., 3., 4.])
特殊地,如果仅输入单个scalar类型数据(例如float/int/bool类型的单个元素),则会创建shape为[1]的Tensor
paddle.to_tensor(2)
paddle.to_tensor([2])
上述两种创建方式完全一致,shape均为[1],输出如下:
Tensor(shape=[1], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
[2])
2. 创建类似于matrix的2-D Tensor,其 ndim 为2
ndim_2_tensor = paddle.to_tensor([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
print(ndim_2_tensor)
Tensor(shape=[2, 3], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
[[1., 2., 3.],
[4., 5., 6.]])
3. 同样地,还可以创建 ndim 为3、4...N等更复杂的多维Tensor
# Tensor可以有任意数量的轴(也称为维度)
ndim_3_tensor = paddle.to_tensor([[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]])
print(ndim_3_tensor)
Tensor(shape=[2, 2, 5], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
[[[1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]]])
上述不同ndim的Tensor可以可视化的表示为:
图1 不同ndim的Tensor可视化表示
可以通过 Tensor.numpy() 方法方便地将 Tensor 转化为 Numpy array:
ndim_2_tensor.numpy()
array([[1., 2., 3.],
[4., 5., 6.]], dtype=float32)
Tensor不仅支持 floats、ints 类型数据,也支持 complex numbers数据:
ndim_2_complex_tensor = paddle.to_tensor([[1+1j, 2+2j],
[3+3j, 4+4j]])
如果输入为复数数据,则Tensor的dtype为 complex64 或 complex128 ,其每个元素均为1个复数:
Tensor(shape=[2, 2], dtype=complex64, place=CUDAPlace(0), stop_gradient=True,
[[(1+1j), (2+2j)],
[(3+3j), (4+4j)]])
Tensor必须形状规则,类似于“矩形”的概念,也就是,沿任何一个轴(也称作维度)上,元素的数量都是相等的,如果为以下情况:
ndim_2_tensor = paddle.to_tensor([[1.0, 2.0],
[4.0, 5.0, 6.0]])
该情况下将会抛出异常:
ValueError:
Faild to convert input data to a regular ndarray :
- Usually this means the input data contains nested lists with different lengths.
上面介绍了通过Python数据来创建Tensor的方法,也可以通过 Numpy array 来创建Tensor:
ndim_1_tensor = paddle.to_tensor(numpy.array([1.0, 2.0]))
ndim_2_tensor = paddle.to_tensor(numpy.array([[1.0, 2.0],
[3.0, 4.0]]))
ndim_3_tensor = paddle.to_tensor(numpy.random.rand(3, 2))
创建的 Tensor 与原 Numpy array 具有相同的 shape 与 dtype。
如果要创建一个指定shape的Tensor,Paddle也提供了一些API:
paddle.zeros([m, n]) # 创建数据全为0,shape为[m, n]的Tensor
paddle.ones([m, n]) # 创建数据全为1,shape为[m, n]的Tensor
paddle.full([m, n], 10) # 创建数据全为10,shape为[m, n]的Tensor
paddle.arange(start, end, step) # 创建从start到end,步长为step的Tensor
paddle.linspace(start, end, num) # 创建从start到end,元素个数固定为num的Tensor
Tensor的shape
基本概念
查看一个Tensor的形状可以通过 Tensor.shape,shape是 Tensor 的一个重要属性,以下为相关概念:
- shape:描述了tensor的每个维度上元素的数量
- ndim: tensor的维度数量,例如vector的 ndim 为1,matrix的 ndim 为2.
- axis或者dimension:指tensor某个特定的维度
- size:指tensor中全部元素的个数
让来创建1个4-D Tensor,并通过图形来直观表达以上几个概念之间的关系;
ndim_4_tensor = paddle.ones([2, 3, 4, 5])
图2 Tensor的shape、axis、dimension、ndim之间的关系
print("Data Type of every element:", ndim_4_tensor.dtype)
print("Number of dimensions:", ndim_4_tensor.ndim)
print("Shape of tensor:", ndim_4_tensor.shape)
print("Elements number along axis 0 of tensor:", ndim_4_tensor.shape[0])
print("Elements number along the last axis of tensor:", ndim_4_tensor.shape[-1])
Data Type of every element: VarType.FP32
Number of dimensions: 4
Shape of tensor: [2, 3, 4, 5]
Elements number along axis 0 of tensor: 2
Elements number along the last axis of tensor: 5
对shape进行操作
重新定义Tensor的shape在实际编程中具有重要意义。
ndim_3_tensor = paddle.to_tensor([[[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]],
[[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]],
[[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30]]])
print("the shape of ndim_3_tensor:", ndim_3_tensor.shape)
the shape of ndim_3_tensor: [3, 2, 5]
Paddle提供了reshape接口来改变Tensor的shape:
ndim_3_tensor = paddle.reshape(ndim_3_tensor, [2, 5, 3])
print("After reshape:", ndim_3_tensor.shape)
After reshape: [2, 5, 3]
在指定新的shape时存在一些技巧:
1. -1 表示这个维度的值是从Tensor的元素总数和剩余维度推断出来的。因此,有且只有一个维度可以被设置为-1。 2.0 表示实际的维数是从Tensor的对应维数中复制出来的,因此shape中0的索引值不能超过x的维度。
有一些例子可以很好解释这些技巧:
origin:[3, 2, 5] reshape:[3, 10] actual: [3, 10]
origin:[3, 2, 5] reshape:[-1] actual: [30]
origin:[3, 2, 5] reshape:[0, 5, -1] actual: [3, 5, 2]
可以发现,reshape为[-1]时,会将tensor按其在计算机上的内存分布展平为1-D Tensor。
print("Tensor flattened to Vector:", paddle.reshape(ndim_3_tensor, [-1]).numpy())
Tensor flattened to Vector: [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30]
Tensor其他属性
Tensor的dtype
Tensor的数据类型,可以通过 Tensor.dtype 来查看,dtype支持:'bool','float16','float32','float64','uint8','int8','int16','int32','int64'。
- 通过Python元素创建的Tensor,可以通过dtype来进行指定,如果未指定:
- 对于python整型数据,则会创建int64型Tensor
- 对于python浮点型数据,默认会创建float32型Tensor,并且可以通过set_default_type来调整浮点型数据的默认类型。
- 通过Numpy array创建的Tensor,则与其原来的dtype保持相同。
print("Tensor dtype from Python integers:", paddle.to_tensor(1).dtype)
print("Tensor dtype from Python floating point:", paddle.to_tensor(1.0).dtype)
Tensor dtype from Python integers: VarType.INT64
Tensor dtype from Python floating point: VarType.FP32
Paddle提供了cast接口来改变dtype:
float32_tensor = paddle.to_tensor(1.0)
float64_tensor = paddle.cast(float32_tensor, dtype='float64')
print("Tensor after cast to float64:", float64_tensor.dtype)
int64_tensor = paddle.cast(float32_tensor, dtype='int64')
print("Tensor after cast to int64:", int64_tensor.dtype)
Tensor after cast to float64: VarType.FP64
Tensor after cast to int64: VarType.INT64
Tensor的place
初始化Tensor时可以通过place来指定其分配的设备位置,可支持的设备位置有三种:CPU/GPU/固定内存,其中固定内存也称为不可分页内存或锁页内存,其与GPU之间具有更高的读写效率,并且支持异步传输,这对网络整体性能会有进一步提升,但其缺点是分配空间过多时可能会降低主机系统的性能,因为其减少了用于存储虚拟内存数据的可分页内存。
- 创建CPU上的Tensor:
cpu_tensor = paddle.to_tensor(1, place=paddle.CPUPlace())
print(cpu_tensor)
Tensor(shape=[1], dtype=int64, place=CPUPlace, stop_gradient=True,
[1])
- 创建GPU上的Tensor:
gpu_tensor = paddle.to_tensor(1, place=paddle.CUDAPlace(0))
print(gpu_tensor)
Tensor(shape=[1], dtype=int64, place=CUDAPlace(0), stop_gradient=True,
[1])
- 创建固定内存上的Tensor:
pin_memory_tensor = paddle.to_tensor(1, place=paddle.CUDAPinnedPlace())
print(pin_memory_tensor)
Tensor(shape=[1], dtype=int64, place=CUDAPinnedPlace, stop_gradient=True,
[1])
Tensor的name
Tensor的name是其唯一的标识符,为python 字符串类型,查看一个Tensor的name可以通过Tensor.name属性。默认地,在每个Tensor创建时,Paddle会自定义一个独一无二的name。
print("Tensor name:", paddle.to_tensor(1).name)
Tensor name: generated_tensor_0
Tensor的操作
索引和切片
可以通过索引或切片方便地访问或修改 Tensor。Paddle 使用标准的 Python 索引规则与 Numpy 索引规则,与 Indexing a list or a string in Python类似。具有以下特点:
- 基于 0-n 的下标进行索引,如果下标为负数,则从尾部开始计算
- 通过冒号: 分隔切片参数 start:stop:step 来进行切片操作,其中 start、stop、step 均可缺省
访问 Tensor
- 针对1-D Tensor,则仅有单个轴上的索引或切片:
ndim_1_tensor = paddle.to_tensor([0, 1, 2, 3, 4, 5, 6, 7, 8])
print("Origin Tensor:", ndim_1_tensor.numpy())
print("First element:", ndim_1_tensor[0].numpy())
print("Last element:", ndim_1_tensor[-1].numpy())
print("All element:", ndim_1_tensor[:].numpy())
print("Before 3:", ndim_1_tensor[:3].numpy())
print("From 6 to the end:", ndim_1_tensor[6:].numpy())
print("From 3 to 6:", ndim_1_tensor[3:6].numpy())
print("Interval of 3:", ndim_1_tensor[::3].numpy())
print("Reverse:", ndim_1_tensor[::-1].numpy())
Origin Tensor: [0 1 2 3 4 5 6 7 8])
First element: [0]
Last element: [8]
All element: [0 1 2 3 4 5 6 7 8]
Before 3: [0 1 2]
From 6 to the end: [6 7 8]
From 3 to 6: [3 4 5]
Interval of 3: [0 3 6]
Reverse: [8 7 6 5 4 3 2 1 0]
- 针对2-D及以上的 Tensor,则会有多个轴上的索引或切片:
ndim_2_tensor = paddle.to_tensor([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]])
print("Origin Tensor:", ndim_2_tensor.numpy())
print("First row:", ndim_2_tensor[0].numpy())
print("First row:", ndim_2_tensor[0, :].numpy())
print("First column:", ndim_2_tensor[:, 0].numpy())
print("Last column:", ndim_2_tensor[:, -1].numpy())
print("All element:", ndim_2_tensor[:].numpy())
print("First row and second column:", ndim_2_tensor[0, 1].numpy())
Origin Tensor: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
First row: [0 1 2 3]
First row: [0 1 2 3]
First column: [0 4 8]
Last column: [ 3 7 11]
All element: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
First row and second column: [1]
索引或切片的第一个值对应 axis 0,第二个值对应 axis 1,以此类推,如果某个 axis 上未指定索引,则默认为 : 。例如:
ndim_2_tensor[1]
ndim_2_tensor[1, :]
这两种操作的结果是完全相同的。
Tensor(shape=[4], dtype=int64, place=CPUPlace, stop_gradient=True,
[4, 5, 6, 7])
修改 Tensor
注意:
通过索引或切片修改 Tensor,该操作会原地修改该 Tensor 的数值,且原值不会被保存。如果被修改的 Tensor 参与梯度计算,将仅会使用修改后的数值,这可能会给梯度计算引入风险。Paddle 之后将会对具有风险的操作进行检测和报错。
与访问 Tensor 类似,修改 Tensor 可以在单个或多个轴上通过索引或切片操作。同时,支持将多种类型的数据赋值给该 Tensor,当前支持的数据类型有:int, float, numpy.ndarray, Tensor。
import paddle
import numpy as np
x = paddle.to_tensor(np.ones((2, 3)).astype(np.float32)) # [[1., 1., 1.], [1., 1., 1.]]
x[0] = 0 # x : [[0., 0., 0.], [1., 1., 1.]] id(x) = 4433705584
x[0:1] = 2.1 # x : [[2.1, 2.1, 2.1], [1., 1., 1.]] id(x) = 4433705584
x[...] = 3 # x : [[3., 3., 3.], [3., 3., 3.]] id(x) = 4433705584
x[0:1] = np.array([1,2,3]) # x : [[1., 2., 3.], [3., 3., 3.]] id(x) = 4433705584
x[1] = paddle.ones([3]) # x : [[1., 2., 3.], [1., 1., 1.]] id(x) = 4433705584
同时,Paddle 还提供了丰富的 Tensor 操作的 API,包括数学运算符、逻辑运算符、线性代数相关等100余种 API,这些 API 调用有两种方法:
x = paddle.to_tensor([[1.1, 2.2], [3.3, 4.4]], dtype="float64")
y = paddle.to_tensor([[5.5, 6.6], [7.7, 8.8]], dtype="float64")
print(paddle.add(x, y), "\n")
print(x.add(y), "\n")
Tensor(shape=[2, 2], dtype=float64, place=CUDAPlace(0), stop_gradient=True,
[[6.60000000, 8.80000000],
[ 11., 13.20000000]])
Tensor(shape=[2, 2], dtype=float64, place=CUDAPlace(0), stop_gradient=True,
[[6.60000000, 8.80000000],
[ 11., 13.20000000]])
可以看出,使用 Tensor 类成员函数 和 Paddle API 具有相同的效果,由于 类成员函数 操作更为方便,以下均从 Tensor 类成员函数 的角度,对常用 Tensor 操作进行介绍。
数学运算符
x.abs() #逐元素取绝对值
x.ceil() #逐元素向上取整
x.floor() #逐元素向下取整
x.round() #逐元素四舍五入
x.exp() #逐元素计算自然常数为底的指数
x.log() #逐元素计算x的自然对数
x.reciprocal() #逐元素求倒数
x.square() #逐元素计算平方
x.sqrt() #逐元素计算平方根
x.sin() #逐元素计算正弦
x.cos() #逐元素计算余弦
x.add(y) #逐元素相加
x.subtract(y) #逐元素相减
x.multiply(y) #逐元素相乘
x.divide(y) #逐元素相除
x.mod(y) #逐元素相除并取余
x.pow(y) #逐元素幂运算
x.max() #指定维度上元素最大值,默认为全部维度
x.min() #指定维度上元素最小值,默认为全部维度
x.prod() #指定维度上元素累乘,默认为全部维度
x.sum() #指定维度上元素的和,默认为全部维度
Paddle对python数学运算相关的魔法函数进行了重写,以下操作与上述结果相同。
x + y -> x.add(y) #逐元素相加
x - y -> x.subtract(y) #逐元素相减
x * y -> x.multiply(y) #逐元素相乘
x / y -> x.divide(y) #逐元素相除
x % y -> x.mod(y) #逐元素相除并取余
x ** y -> x.pow(y) #逐元素幂运算
逻辑运算符
x.isfinite() #判断tensor中元素是否是有限的数字,即不包括inf与nan
x.equal_all(y) #判断两个tensor的全部元素是否相等,并返回shape为[1]的bool Tensor
x.equal(y) #判断两个tensor的每个元素是否相等,并返回shape相同的bool Tensor
x.not_equal(y) #判断两个tensor的每个元素是否不相等
x.less_than(y) #判断tensor x的元素是否小于tensor y的对应元素
x.less_equal(y) #判断tensor x的元素是否小于或等于tensor y的对应元素
x.greater_than(y) #判断tensor x的元素是否大于tensor y的对应元素
x.greater_equal(y) #判断tensor x的元素是否大于或等于tensor y的对应元素
x.allclose(y) #判断tensor x的全部元素是否与tensor y的全部元素接近,并返回shape为[1]的bool Tensor
同样地,Paddle对python逻辑比较相关的魔法函数进行了重写,以下操作与上述结果相同。
x == y -> x.equal(y) #判断两个tensor的每个元素是否相等
x != y -> x.not_equal(y) #判断两个tensor的每个元素是否不相等
x < y -> x.less_than(y) #判断tensor x的元素是否小于tensor y的对应元素
x <= y -> x.less_equal(y) #判断tensor x的元素是否小于或等于tensor y的对应元素
x > y -> x.greater_than(y) #判断tensor x的元素是否大于tensor y的对应元素
x >= y -> x.greater_equal(y) #判断tensor x的元素是否大于或等于tensor y的对应元素
以下操作仅针对bool型Tensor:
x.logical_and(y) #对两个bool型tensor逐元素进行逻辑与操作
x.logical_or(y) #对两个bool型tensor逐元素进行逻辑或操作
x.logical_xor(y) #对两个bool型tensor逐元素进行逻辑亦或操作
x.logical_not(y) #对两个bool型tensor逐元素进行逻辑非操作
线性代数相关
x.cholesky() #矩阵的cholesky分解
x.t() #矩阵转置
x.transpose([1, 0]) #交换axis 0 与axis 1的顺序
x.norm('fro') #矩阵的Frobenius 范数
x.dist(y, p=2) #矩阵(x-y)的2范数
x.matmul(y) #矩阵乘法
需要注意,Paddle中Tensor的操作符均为非inplace操作,即 x.add(y) 不会在tensor x上直接进行操作,而会返回一个新的Tensor来表示运算结果。
Tensor基础实践的更多相关文章
- Linux课程实践一:Linux基础实践(SSH)
一.SSH服务 1. 安装SSH (1)查看是否已经安装过ssh服务 rpm -qa |grep ssh (2)进行安装 sudo apt-get install openssh-server Ubu ...
- Linux课程实践一:Linux基础实践(基础操作)
一.软件源维护 1. 基本操作 (1)查看源列表 sudo vim /etc/apt/sources.list deb:二进制软件安装包 deb-src:源码包 (2)备份软件源列表 sudo cp ...
- 实践一:Linux基础实践
一.Linux基础实践 1.1 1. 掌握软件源的维护方法,配置系统使用软件源镜像.掌握通过软件源来查找,安装,卸载,更新软件的方法. 这部分内容在许多学长学姐的报告里都有很详细的讲解,我在此就不赘述 ...
- Linux及安全——Linux基础实践
Linux及安全——Linux基础实践 一.实践一:掌握软件源的维护方法,配置系统使用教育网内的软件源镜像.掌握通过软件源来查找,安装,卸载,更新软件的方法. 1.软件源的维护方法 Ubuntu的软件 ...
- Ansible - 简介和应用自动化基础实践
installAnsible简介和应用自动化基础实践 一.引入: 1.1 如官方定义,Ansible is The simplest way to automate apps and IT infr ...
- 20155324《网络对抗技术》web安全基础实践
20155324<网络对抗技术>web安全基础实践 实验内容 使用webgoat进行XSS攻击.CSRF攻击.SQL注入 实验问答 SQL注入攻击原理,如何防御 ①SQL注入攻击是攻击者在 ...
- 20155326《网络对抗》Web安全基础实践
20155326<网络对抗>Web安全基础实践 实验后回答的问题 SQL注入攻击原理,如何防御? 原理:SQL注入攻击指的是在Web应用对后台数据库查询语句处理存在的安全漏洞,通过构建特殊 ...
- 20155326《网路对抗》Exp8 WEB基础实践
20155326<网路对抗>Exp8 WEB基础实践 实践内容 (1).Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写 ...
- 网络对抗实验一 逆向及Bof基础实践
网络对抗实验一 逆向及Bof基础实践 一.实验目的 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. ...
随机推荐
- php文件夹下文件批量重命名
php文件夹下文件批量重命名 <?php header("Content-type:text/html;charset=utf-8"); $dir = __DIR__.'./ ...
- Mysql Char 和 Varchar的区别
CHAR和VARCHAR都是字符串类型,它们的具体区别为: 长度大小区别: CHAR(M)定义的列的长度为固定的,M取值可以为0-255之间: VARCHAR(M)定义的列的长度为可变长,M取值可以为 ...
- Hexo 博客Next 搭建与美化主题
========================================================================================将页面部署到GitHub ...
- html单页面中用angular js
1.引入angluar js文件 2.html页面应用区域中加入(ng-app="myApp" ng-controller="myController"),区域 ...
- 将本地代码上传到云效git存放
前提已开通云效账号,然后进行云效首页的研发---代码 创建git组 创建git库 生成https://code.aliyun.com/test-demo1/v1的git库 准备将本地的test-dem ...
- Django(3)pycharm创建项目
创建项目 我们创建django项目有两种方式,命令行方式和使用pycharm工具创建,本文就介绍常用的pycharm工具创建 首先点击django,输入项目的名称,选择创建好的虚拟环境,最后点击c ...
- apache common pool2原理与实战
完整源码,请帮我点个star哦! 原文地址为https://www.cnblogs.com/haixiang/p/14783955.html,转载请注明出处! 简介 对象池顾名思义就是存放对象的池,与 ...
- ES6学习-5 解构赋值(2)对象的解构赋值
啥也不说,先举个栗子: 1 let { myname, myage } = { myage: 18, myname: "郭郭" }; 2 console.log(myname) / ...
- laravel 伪静态实现
Route::get('show{id}.html',['as'=>'products.detail','uses'=>'companyController@show']) ->wh ...
- MySQL优化|一分钟带你了解单表优化
在开始前,分享给大家我看过觉得讲数据库讲的算是很不错的,也在B站拥有百万播放量的教程. 这个MySQL视频是动力节点的老杜讲解,个人也很喜欢老杜的教学风格,老杜真的是从MySQL基础一点点带我入门,基 ...