张量是一种特殊的数据结构,与数组和矩阵非常相似。类似于Numpy 的ndarray。 在 PyTorch 中,我们使用张量对模型的输入和输出以及模型的参数进行编码。 张量都可以通过Numpy来定义、操作,通常存储在Nunpy数组,所以这就需要我们把数据转换为Numpy数组,目的就是把所有的输入数据转变为一个统一的标准,以便能够容易的处理。
张量是根据一共具有多少坐标轴来定义。比如可以把二维张量看作为一个带有行和列的数字网格。这个行和列表示两个坐标轴,一个矩阵就是二维张量,矩阵的每一行或每一列,都可以视为一维张量(向量)。如果把一系列的二维张量存储在列表中,这就形成了三维张量。你也可以把三维张量视为一个有长宽高立方体,张量能够被转换和操作,使列变为行或者行变为列。
维度是指在一个数据轴上的许多点,也就是样本的个数或者特征的个数。
张量的每一个数据轴,统称为阶。因此说一阶(1D)向量,二阶向量,三阶向量,而不是说维。
0D张量/标量 标量是一个数字
1D张量/向量 称为“向量”。只有一个坐标轴。 可以把向量视为一个单列的数字。
2D张量 2维张量称为矩阵,也就是有两个坐标轴的张量。
3D张量 公用数据存储在张量 字符串文本,视频, 彩色图片(RGB),三维张量有三个坐标轴
仅包含一个数字的张量叫做标量,标量的功能主要在于程序流程控制、设置参数值等。
import torch
import numpy as np
#data = [[1, 2],[3, 4]]
x_data = torch.tensor(8)
print(f"X的值:{x_data}")
print(f"X的阶:{x_data.ndim}") #ndim属性显示张量轴的个数
print(f"Shape of tensor: {x_data.shape}")# shape属性显示张量形状
print(f"Datatype of tensor: {x_data.dtype}")# dtype属性显示张量数据类型
print(f"Device tensor is stored on: {x_data.device}")#存储它们的设备
torch.Size([])此处标量的形状为(),既标量的阶为0
X的值:8
X的阶:0
Shape of tensor: torch.Size([])
Datatype of tensor: torch.int64
Device tensor is stored on: cpu
一阶张量可以理解为一个向量,由一组数字组成的数组叫做向量(vector),也就是一阶张量,或称1D张量。一阶张量只有一个轴。
import torch
import numpy as np
data = [1, 2,3, 4]
np_array = np.array(data)
x_data = torch.from_numpy(np_array)
print(f"X的值:{x_data}")
print(f"X的阶:{x_data.ndim}") #ndim属性显示张量轴的个数
print(f"Shape of tensor: {x_data.shape}")# shape属性显示张量形状
torch.Size([4])代表的data是一个4维向量(也是1D张量)。
X的值:tensor([1, 2, 3, 4], dtype=torch.int32)
X的阶:1
Shape of tensor: torch.Size([4])
二阶张量可以理解为矩阵,形状为(samples,features),数据集中的每一行或每一列,都可以视为向量,但是数据集整体是一个矩阵。
from keras.datasets import boston_housing # 波士顿房价数据集
(X_train, y_train), (X_test, y_test) = boston_housing.load_data()
print(f"X_train的形状:{X_train.shape}")
print(f"X_train中第一个样本的形状:{X_train[0].shape}")
print(f"X_train的阶:{X_train.ndim}") #ndim属性显示张量轴的个数
print(f"y_train的形状:{y_train.shape}")
这个是Keras内置的波士顿房价数据集,是一个2D的普通数值数据集。X_train是一个2D矩阵,是404个样本数据的集合。X_train[0]代表的是X_train训练集的第一行数据,是一个13维向量(也是1D张量)。也就是说,训练集的每行数据都包含13个特征。
X_train的形状:(404, 13)
X_train中第一个样本的形状:(13,)
X_train的阶:2
y_train的形状:(404,)
在机器学习中,3D张量可用于存储时间序列。在矩阵数据的基础上再增加一个阶,就形成了3D张量。
import torch
shape = (2,3,2)
rand_tensor = torch.rand(shape)
print(f"Random Tensor: \n {rand_tensor} \n")
print(f"X的阶:{rand_tensor.ndim}") #ndim属性显示张量轴的个数
print(f"X_train中第一个样本的形状:{rand_tensor[0].shape}")
print(f"Shape of tensor: {rand_tensor.shape}")
rand_tensor是一个3D张量,是2个样本数据的集合。rand_tensor[0]代表的是rand_tensor第一个样本数据是一个形状为(3,2)的2D张量(也是矩阵)。
Random Tensor:
tensor([[[0.5826, 0.3287],
[0.3100, 0.6388],
[0.8254, 0.8289]],
[[0.6451, 0.7861],
[0.6652, 0.4813],
[0.7998, 0.3282]]])
X的阶:3
X_train中第一个样本的形状:torch.Size([3, 2])
Shape of tensor: torch.Size([2, 3, 2])
4D张量中的第四维表示存储样本量,比如图像数据包括高度、宽度,颜色深度,对图像数据集来说,再加上数据集大小 。用4D张量表示,如cifar10特征数据集的形状(50000,32,32,3)
from keras.datasets import cifar10
(train_images, train_labels), (test_images, test_labels) = cifar10.load_data()
print("train_images:", train_images.shape)
print("train_images中第一个样本的形状:", train_images[0].shape)
print("train_labels的形状:",train_labels.shape)
这个是Keras内置的cifar10数据集图像分类,是一个4D的普通数值数据集,其中train_image是一个4D矩阵,是50000个样本数据的集合。X_train[0]代表的是X_train训练集的第一行数据,是一个3D张量。train_labels是一个2D矩阵,也就是说是50000个样本数据都有一个标签。
train_images: (50000, 32, 32, 3)
train_images中第一个样本的形状: (32, 32, 3)
train_labels的形状: (50000, 1)
视频可以看作是由一帧一帧的彩色图像组成的数据集。
每一帧都保存在一个形状为(高度、宽度、颜色深度)的3D张量中。
一系列帧则保存在一个形状为(帧、高度、宽度、颜色深度)的4D张量中。
因此,视频数据集需要5D张量才放得下,其形状为(样本、帧、高度、宽度、颜色深度)。
5D张量可以用来存储视频数据。如果有10段视频,一段30秒,(1920 x 1080像素),每秒15帧(总共450帧),深度为3的视频:(视频数据的数据量是非常大的。)
(10,450,1920,1080,3)
超过 100 种张量运算,包括算术、线性代数、矩阵操作(转置、 索引,切片),采样等等
直接从数据,张量可以直接从数据中创建。 数据类型是自动推断的。
data = [[1, 2],[3, 4]]
x_data = torch.tensor(data)
来自 NumPy 数组,张量可以从 NumPy 数组创建
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
从另一个张量:新张量保留参数张量的属性(形状、数据类型),除非显式覆盖。
x_ones = torch.ones_like(x_data)
print(f"Ones Tensor: \n {x_ones} \n")
x_rand = torch.rand_like(x_data, dtype=torch.float)
print(f"Random Tensor: \n {x_rand} \n")
对自定义的二维矩阵进行操作
import torch
import numpy as np
array1=np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
print(f"First column: {array1[1:2]},{array1[1:2].shape}")
print(f"First column: {array1[1:2][0]},{array1[1:2][0].shape}")
tensor = torch.from_numpy(array1)
print(f"First row: {tensor[1:2]}")
print(f"First column: {tensor[:,0]}")
print(f"Last column: {tensor[:,-1]},{tensor[:,-1].shape}")
tensor[:1] = 0
print(tensor)
First column: [[4 5 6]],(1, 3)
First column: [4 5 6],(3,)
First row: tensor([[4, 5, 6]], dtype=torch.int32)
First column: tensor([ 1, 4, 7, 10], dtype=torch.int32)
Last column: tensor([ 3, 6, 9, 12], dtype=torch.int32),torch.Size([4])
tensor([[ 0, 0, 0],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]], dtype=torch.int32)
对keras中的数据集进行操作
from keras.datasets import mnist #需要打开internet选项)
(X_train, y_train), (X_test, y_test) = mnist.load_data()
print (X_train.shape)
X_train_slice = X_train[10000:15000,:,:]
print (X_train_slice.shape)
(60000, 28, 28)
(5000, 28, 28)
可以使用 torch.cat
沿给定维度连接一系列张量。
import torch
import numpy as np
array2=np.array([[1,2,3],[4,5,6]])
x = torch.from_numpy(array2)
t1 = torch.cat([x,x], dim=0)
t2 = torch.cat([x,x,x], dim=1)
print(t1)
print(t2)
tensor([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]], dtype=torch.int32)
tensor([[1, 2, 3, 1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6, 4, 5, 6]], dtype=torch.int32)
import numpy as np
array2=np.array([[1,2,3],[4,5,6]])
array2+=1
print(array2)
for i in range(array2.shape[0]):
for j in range(array2.shape[1]):
array2[i,j] += 1
print(array2)
[[2 3 4]
[5 6 7]]
[[3 4 5]
[6 7 8]]
import numpy as np
array3 = np.arange(6)
print (array3,'形状是', array3.shape,'阶为', array3.ndim)
array4 = array3.reshape(6,1)
print (array4,'形状是', array4.shape,'阶为', array4.ndim)
array5 = array4.T # 矩阵的转置
print (array5,'形状是', array5.shape,'阶为', array5.ndim)
print (array5[0],'形状是', array5[0].shape,'阶为', array5[0].ndim)
[0 1 2 3 4 5] 形状是 (6,) 阶为 1
[[0]
[1]
[2]
[3]
[4]
[5]] 形状是 (6, 1) 阶为 2
[[0 1 2 3 4 5]] 形状是 (1, 6) 阶为 2
[0 1 2 3 4 5] 形状是 (6,) 阶为 1
在pytorch中对张量tensor
维度及维度数目的获取可以有以下方法:ndimension
方法可以获取张量的维数,nelement
方法可以获取张量总的元素个数。。想要获得张量的每个维度的大小,也就是张量的形状信息,可以通过tensor.size()
或者tensor.shape
得到。想要获得特定维度的大小可以在使用size方法时输入想要的维度。
import torch
tensor0=torch.randn(1,3,28,28)
print(tensor0.ndimension(),tensor0.nelement())
print(tensor0.size(),tensor0.size(1))
4 2352
torch.Size([1, 3, 28, 28]) 3
CPU 和 NumPy 数组上的张量可以共享它们的底层内存 位置,改变一个会改变另一个。
import torch
import numpy as np
t = torch.ones(5)
print(f"t: {t}")
n = t.numpy()
print(f"n: {n}")
t.add_(1)
print(f"t: {t}")
print(f"n: {n}")
张量的变化反映在 NumPy 数组中
t: tensor([1., 1., 1., 1., 1.])
n: [1. 1. 1. 1. 1.]
t: tensor([2., 2., 2., 2., 2.])
n: [2. 2. 2. 2. 2.]
import torch
import numpy as np
n = np.ones(5)
t = torch.from_numpy(n)
np.add(n, 1, out=n)
print(f"t: {t}")
print(f"n: {n}")
NumPy 数组的变化反映在张量中。
t: tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
n: [2. 2. 2. 2. 2.]
总结:
机器学习中的数据结构称为张量,下面是几种重要的张量格式,用于处理不同类型的数据集。
·普通向量数据集结构:2D张量,形状为(样本,标签)
·时间序列数据集或序列数据集:3D张量,形状为(样本,时戳,特征)
·图像数据集:4D 张量,形状为(样本量、高度、宽度、颜色深度)
Python语句操作方面,NumPy数组的操作都是重点内容。
·张量的切片操作
·用reshape进行张量变形
·加入张量、张量的整体运算
·张量维度大小与数目的获取
·张量的变形和转置