Pytorch之张量的基本操作

张量创建操作

复制代码
    # 从标量创建张量
    t1 = torch.tensor(10)
    print(f"t1: {t1}, type: {type(t1)}")

    # 二维列表创建张量
    data = [[1, 2], [3, 4]]
    t2 = torch.tensor(data)
    print(f"t2: {t2}, type: {type(t2)}")

    # 从numpy数组创建张量
    np_array = np.array([[5, 6], [7, 8]])
    t3 = torch.tensor(np_array)
    print(f"t3: {t3}, type: {type(t3)}")

    # 直接创建指定维度的张量 ,Tensor,不指定数据类型,默认是float32
    t4 = torch.Tensor(2, 3)  # 创建一个2行3列的张量,元素未初始化
    print(f"t4: {t4}, type: {type(t4)}")

def demo02():

    t1 = torch.IntTensor(10)
    print(f"t1: {t1}, type: {type(t1)}")

    data = [[1, 2], [3, 4]]
    t2 = torch.IntTensor(data)
    print(f"t2: {t2}, type: {type(t2)}")

    np_array = np.array([[5, 6], [7, 8]])
    t3 = torch.FloatTensor(np_array)
    print(f"t3: {t3}, type: {type(t3)}")

    t4 = torch.FloatTensor(2, 3)  # 创建一个2行3列的Float32类型张量,元素未初始化
    print(f"t4: {t4}, type: {type(t4)}")

创建全0,全1和全为某个值的张量

复制代码
def demo03():
    #创建全0张量
    t1 = torch.zeros(2, 3)
    t2 = torch.zeros_like(t1)
    print(f"t1: {t1}")
    print(f"t2: {t2}")
    # 创建全1张量
    t3 = torch.ones(2, 3)
    t4 = torch.ones_like(t3)
    print(f"t3: {t3}")
    print(f"t4: {t4}")
    # 创建全为某个值的张量
    t5 = torch.full((2, 3), 5)
    t6 = torch.full_like(t5, 10)
    print(f"t5: {t5}")
    print(f"t6: {t6}")

创建线性和随机张量

复制代码
def demo04():
    # 创建线性张量 start:起始值 end:结束值 steps:生成的元素个数
    t1 = torch.linspace(0, 10, steps=5)  # 从0到10 等间隔生成5个数
    print(f"t1: {t1}")
    # start:起始值 end:结束值 step:步长
    t2 = torch.arange(0, 10, step=2)  # 从0到10步长为2生成数
    print(f"t2: {t2}")

    # 创建随机张量
    # 设置随机种子,保证每次运行生成的随机数相同
    # torch.initial_seed() # 采用系统的时间戳作为当前随机种子
    torch.manual_seed(42)  # 设置随机种子为42
    t3 = torch.rand(2, 3)  # 均匀分布
    t4 = torch.randn(2, 3)  # 标准正态分布
    print(f"t3: {t3}")
    print(f"t4: {t4}")

张量类型转换

复制代码
def demo05():
    # 张量类型转换
    t1 = torch.tensor([1, 2, 3], dtype=torch.float32)
    print(f"t1: {t1}, dtype: {t1.dtype}")
    # data.half() 转换为半精度浮点数/double() 转换为双精度浮点数/float() 转换为单精度浮点数/int() 转换为整数类型/long() 转换为长整数类型

    t2 = t1.int()  # 转换为整数类型
    print(f"t2: {t2}, dtype: {t2.dtype}")
    # type() 方法可以直接指定目标数据类型, 推荐掌握
    t3 = t1.type(torch.int32)  # 转换为32位整数类型
    print(f"t3: {t3}, dtype: {t3.dtype}")

张量转换为NumPy数组

python 复制代码
import torch
import numpy as np


# 张量转换成numpy数组
# tensor.numpy(): 共享内存, 修改一个另外一个也跟着变, 可以通过copy()函数不共享内存
def dm01():
	t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
	print('t1->', t1)
	# 转换成numpy数组
	# n1 = t1.numpy()
	n1 = t1.numpy().copy()
	print('n1->', n1)
	print('n1的类型->', type(n1))
	# 修改n1的第一个值
	# [0][0]->第一行第一列的元素
	n1[0][0] = 100
	print('n1修改后->', n1)
	print('t1->', t1)

NumPy数组转换为张量

python 复制代码
# numpy数组转换成张量
# torch.from_numpy(ndarray): 共享内存, 对ndarray数组进行copy()
# torch.tensor(data=ndarray): 不共享内存
def dm02():
	n1 = np.array([[1, 2, 3], [4, 5, 6]])
	# 转换成张量
	# 共享内存
	t1 = torch.from_numpy(n1)
	# 不共享内存
	# t1 = torch.from_numpy(n1.copy())
	# t1 = torch.tensor(data=n1)
	print('t1->', t1)
	print('t1类型->', type(t1))
	# 修改张量元素
	t1[0][0] = 8888
	print('t1修改后->', t1)
	print('n1->', n1)

提取标量张量的数值

python 复制代码
import torch


# tensor.item(): 提取单个元素张量的数值, 张量可以是标量张量/一维张量/二维张量...只要是单个元素即可
def dm01():
	# 数值转换成张量
	# 标量
	t1 = torch.tensor(data=10)
	# 一维
	# t1 = torch.tensor(data=[10])
	# 二维
	# t1 = torch.tensor(data=[[10]])
	print('t1->', t1)
	print('t1形状->', t1.shape)
	# 单个元素张量转换成数值, 提取数值
	print('t1.item()->', t1.item())


if __name__ == '__main__':
	dm01()

张量数值计算

基本运算

  • + - * / -

  • tensor/torch.add() sub() mul() div() neg()

  • tensor/torch.add_() sub_() mul_() div_() neg_()

    python 复制代码
    import torch
    
    
    # 运算: 张量和数值之间运算, 张量和张量之间运算
    # + - * / -
    # add(other=) sub() mul() div() neg()  不修改原张量
    # add_() sub_() mul_() div_() neg_()  修改原张量
    
    def dm01():
    	# 创建张量
    	t1 = torch.tensor(data=[1, 2, 3, 4])
    	# 张量和数值运算
    	t2 = t1 + 10
    	print('t2->', t2)
    	# 张量之间运算, 对应位置的元素进行计算
    	t3 = t1 + t2
    	print('t3->', t3)
    
    	# add() 不修改原张量
    	t1.add(other=100)
    	t4 = torch.add(input=t1, other=100)
    	print('t4->', t4)
    
    	# neg_() 修改原张量, 负号
    	t5 = t1.neg_()
    	print('t1->', t1)
    	print('t5->', t5)
    
    
    if __name__ == '__main__':
    	dm01()

点乘运算

  • 对应位置的元素进行乘法计算, 一般要求张量形状相同

    python 复制代码
    import torch
    
    
    # 点乘: 又称为阿达玛积, 张量元素级乘法, 对应位置的元素进行点乘, 一般要求两个张量形状相同  *  mul()
    def dm01():
    	# t1 = torch.tensor(data=[[1, 2], [3, 4]])
    	# (2, )
    	t1 = torch.tensor(data=[1, 2])
    	# (2, 2)
    	t2 = torch.tensor(data=[[5, 6], [7, 8]])
    	t3 = t1 * t2
    	print('t3->', t3)
    	t4 = torch.mul(input=t1, other=t2)
    	print('t4->', t4)
    
    
    if __name__ == '__main__':
    	dm01()

矩阵乘法运算

  • 第一个矩阵的行数据和第二个矩阵的列数据相乘

    python 复制代码
    import torch
    
    
    # 矩阵乘法: (n, m) * (m, p) = (n, p)  第一个矩阵的行和第二个矩阵的列相乘  @  torch.matmul(input=, ohter=)
    def dm01():
    	# (2, 2)
    	t1 = torch.tensor(data=[[1, 2],
    							[3, 4]])
    	# (2, 3)
    	t2 = torch.tensor(data=[[5, 6, 7],
    							[8, 9, 10]])
    
    	# @
    	t3 = t1 @ t2
    	print('t3->', t3)
    	# torch.matmul(): 不同形状, 只要后边维度符合矩阵乘法规则即可
    	t4 = torch.matmul(input=t1, other=t2)
    	print('t4->', t4)
    
    
    if __name__ == '__main__':
    	dm01()

张量运算函数

  • mean()

  • sum()

  • min()/max()

  • dim: 按不同维度计算

  • exp(): 指数

  • sqrt(): 平方根

  • pow(): 幂次方

  • log()/log2()/log10(): 对数

    python 复制代码
    import torch
    
    
    def dm01():
    	# 创建张量
    	t1 = torch.tensor(data=[[1., 2, 3, 4],
    							[5, 6, 7, 8]])
    
    	# dim=0 按列
    	# dim=1 按行
    	# 平均值
    	print('所有值平均值->', t1.mean()) #tensor(4.5000)
    	print('按列平均值->', t1.mean(dim=0))
    	print('按行平均值->', t1.mean(dim=1)) #tensor([2.5000, 6.5000])
    
    	# 求和
    	print('所有值求和->', t1.sum())
    	print('按列求和->', t1.sum(dim=0))
    	print('按行求和->', t1.sum(dim=1))
    	# sqrt: 开方 平方根
    	print('所有值开方->', t1.sqrt())
    	# pow: 幂次方  x^n
    	# exponent:几次方
    	print('幂次方->',torch.pow(input=t1, exponent=2))
    	# exp: 指数 e^x  张量的元素值就是x
    	print('指数->', torch.exp(input=t1))
    	# log: 对数  log(x)->以e为底  log2()  log10()
    	print('以e为底对数->', torch.log(input=t1))
    	print('以2为底对数->', t1.log2())
    	print('以10为底对数->', t1.log10())
    
    
    if __name__ == '__main__':
    	dm01()

张量索引操作

python 复制代码
import torch

# 下标从左到右从0开始(0->第一个值), 从右到左从-1开始
# data[行下标, 列下标]
# data[0轴下标, 1轴下标, 2轴下标]

def dm01():
	# 创建张量
	torch.manual_seed(0)
	data = torch.randint(low=0, high=10, size=(4, 5))
	print('data->', data)
	# 根据下标值获取对应位置的元素
	# 行数据 第一行
	print('data[0] ->', data[0])
	# 列数据 第一列
	print('data[:, 0]->', data[:, 0])
	# 根据下标列表取值
	# 第二行第三列的值和第四行第五列值,[行索引],[列索引]
	print('data[[1, 3], [2, 4]]->', data[[1, 3], [2, 4]])
	# [[1], [3]: 第二行第三列 第二行第五列值   第四行第三列 第四行第五列值
	print('data[[[1], [3]], [2, 4]]->', data[[[1], [3]], [2, 4]])
    
    # 所有奇数行,偶数列
    t2 = t1[::2, 1::2]
	# 根据布尔值取值
	# 第二列大于6的所有行数据
	print(data[:, 1] > 6)
	print('data[data[:, 1] > 6]->', data[data[:, 1] > 6])
	# 第三行大于6的所有列数据
	print('data[:, data[2]>6]->', data[:, data[2] > 6])
	# 根据范围取值  切片  [起始下标:结束下标:步长]
	# 第一行第三行以及第二列第四列张量
	print('data[::2, 1::2]->', data[::2, 1::2])

    
	# 创建三维张量
	data2 = torch.randint(0, 10, (3, 4, 5))
	print("data2->", data2)
	# 0轴第一个值
	print(data2[0, :, :])
	# 1轴第一个值
	print(data2[:, 0, :])
	# 2轴第一个值
	print(data2[:, :, 0])


if __name__ == '__main__':
	dm01()

张量形状操作

reshape

元素个数不能变

python 复制代码
import torch


# reshape(shape=(行,列)): 修改连续或非连续张量的形状, 不改数据
# -1: 表示自动计算行或列   例如:  (5, 6) -> (-1, 3) -1*3=5*6 -1=10  (10, 3)
def dm01():
	torch.manual_seed(0)
	t1 = torch.randint(0, 10, (5, 6))
	print('t1->', t1)
	print('t1的形状->', t1.shape)
	# 形状修改为 (2, 15)
	t2 = t1.reshape(shape=(2, 15))
	t3 = t1.reshape(shape=(2, -1))
	print('t2->', t2)
	print('t2的形状->', t2.shape)
	print('t3->', t3)
	print('t3的形状->', t3.shape)



if __name__ == '__main__':
	dm01()

squeeze和unsqueeze

python 复制代码
# squeeze(dim=): 删除值为1的维度, dim->指定维度, 维度值不为1不生效  不设置dim,删除所有值为1的维度
# 例如: (3,1,2,1) -> squeeze()->(3,2)  squeeze(dim=1)->(3,2,1)
# unqueeze(dim=): 在指定维度上增加值为1的维度  dim=-1:最后维度
def dm02():
	torch.manual_seed(0)
	# 四维
	t1 = torch.randint(0, 10, (3, 1, 2, 1))
	print('t1->', t1)
	print('t1的形状->', t1.shape)
	# squeeze: 降维,删除值为1的维度
	t2 = torch.squeeze(t1)
	print('t2->', t2)
	print('t2的形状->', t2.shape) #  (3, 2)
	# dim: 指定维度
	t3 = torch.squeeze(t1, dim=1)
	print('t3->', t3)
	print('t3的形状->', t3.shape) # (3, 2, 1)
	# unsqueeze: 升维
	t4 = t2.unsqueeze(dim=-1)
	print('t4->', t4)
	print('t4的形状->', t4.shape)
	# (3, 2)->(1, 3, 2)
	# t4 = t2.unsqueeze(dim=0)
	# 最后维度 (3, 2)->(3, 2, 1)

if __name__ == '__main__':
	dm02()

transpose和permute

python 复制代码
# 调换维度
# torch.permute(input=,dims=): 改变张量任意维度顺序
# input: 张量对象
# dims: 改变后的维度顺序, 传入轴下标值 (1,2,3)->(3,1,2)
# torch.transpose(input=,dim0=,dim1=): 改变张量两个维度顺序
# dim0: 轴下标值, 第一个维度
# dim1: 轴下标值, 第二个维度
# (1,2,3)->(2,1,3) 一次只能交换两个维度
def dm03():
	torch.manual_seed(0)
	t1 = torch.randint(low=0, high=10, size=(3, 4, 5))
	print('t1->', t1)
	print('t1形状->', t1.shape)
	# 交换0维和1维数据
	# t2 = t1.transpose(dim0=1, dim1=0) # transpose只能交换两个维度
	t2 = t1.permute(dims=(1, 0, 2)) # 使用抽象的位置编码来换位
	print('t2->', t2)
	print('t2形状->', t2.shape)
	# t1形状修改为 (5, 3, 4)
	t3 = t1.permute(dims=(2, 0, 1))
	print('t3->', t3)
	print('t3形状->', t3.shape)


if __name__ == '__main__':
	dm03()

view和contiguous

python 复制代码
# tensor.view(shape=): 修改连续张量的形状, 操作等同于reshape() 都是连续的
# tensor.is_contiugous(): 判断张量是否连续, 返回True/False  张量经过transpose/permute处理变成不连续
# tensor.contiugous(): 将张量转为连续张量
def dm04():
	torch.manual_seed(0)
	t1 = torch.randint(low=0, high=10, size=(3, 4))
	print('t1->', t1)
	print('t1形状->', t1.shape) # t1形状-> torch.Size([3, 4])
	print('t1是否连续->', t1.is_contiguous()) # t1是否连续-> True
	# 修改张量形状
	t2 = t1.view((4, 3)) 
	print('t2->', t2)
	print('t2形状->', t2.shape)#t2形状-> torch.Size([4, 3])
	print('t2是否连续->', t2.is_contiguous()) # t2是否连续-> True
	# 张量经过transpose操作
	t3 = t1.transpose(dim0=1, dim1=0)
	print('t3->', t3)
	print('t3形状->', t3.shape) #t3形状-> torch.Size([4, 3])
	print('t3是否连续->', t3.is_contiguous()) #t3是否连续-> False
	# 修改张量形状
	# view
	# contiugous(): 转换成连续张量
	t4 = t3.contiguous().view((3, 4))
	print('t4->', t4)
	t5 = t3.reshape(shape=(3, 4))
	print('t5->', t5)
	print('t5是否连续->', t5.is_contiguous()) #t5是否连续-> True


if __name__ == '__main__':
	dm04()

张量拼接操作

cat/concat

在 PyTorch 中,catconcat 本质上是同一个函数

python 复制代码
import torch


# torch.cat()/concat(tensors=, dim=): 在指定维度上进行拼接, 其他维度值必须相同, 不改变新张量的维度, 指定维度值相加
# tensors: 多个张量列表
# dim: 拼接维度
def dm01():
	torch.manual_seed(0)
	t1 = torch.randint(low=0, high=10, size=(2, 3))
	t2 = torch.randint(low=0, high=10, size=(2, 3))
	t3 = torch.cat(tensors=[t1, t2], dim=0) #(2,3)+(2,3) = (4,3)
	print('t3->', t3)
	print('t3形状->', t3.shape)
	t4 = torch.concat(tensors=[t1, t2], dim=1)
	print('t4->', t4)
	print('t4形状->', t4.shape)
    

if __name__ == '__main__':
	# dm01()

stack

python 复制代码
# torch.stack(tensors=, dim=): 根据指定维度进行堆叠,所有维度保持一致 在指定维度上新增一个维度(维度值张量个数), 新张量维度发生改变,
# tensors: 多个张量列表
# dim: 拼接维度
def dm02():
	torch.manual_seed(0)
	t1 = torch.randint(low=0, high=10, size=(2, 3))
	t2 = torch.randint(low=0, high=10, size=(2, 3))
	t3 = torch.stack(tensors=[t1, t2], dim=0) # 在第一个维度新增
	# t3 = torch.stack(tensors=[t1, t2], dim=1)
	print('t3->', t3)
	print('t3形状->', t3.shape) # t3形状-> torch.Size([2, 2, 3])


if __name__ == '__main__':
	dm02()

自动微分模块

梯度计算

python 复制代码
"""
梯度: 求导,求微分 上山下山最快的方向
梯度下降法: W1=W0-lr*梯度   lr是可调整已知参数  W0:初始模型的权重,已知  计算出W0的梯度后更新到W1权重
pytorch中如何自动计算梯度 自动微分模块
注意点: ①loss标量和w向量进行微分  ②梯度默认累加,计算当前的梯度, 梯度值是上次和当前次求和  ③梯度存储.grad属性中
"""
import torch


def dm01():
	# 创建标量张量 w权重
	# requires_grad: 是否自动微分,默认False
	# dtype: 自动微分的张量元素类型必须是浮点类型
	# w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
	# 创建向量张量 w权重
	w = torch.tensor(data=[10, 20], requires_grad=True, dtype=torch.float32)
	# 定义损失函数, 计算损失值
	loss = 2 * w ** 2
	print('loss->', loss)#loss-> tensor([200., 800.], grad_fn=<MulBackward0>)
	print('loss.sum()->', loss.sum()) #loss.sum()-> tensor(1000., grad_fn=<SumBackward0>) 保证loss是标量能够求导
	# 计算梯度 反向传播  loss必须是标量张量,否则无法计算梯度
	loss.sum().backward()
	# 获取w权重的梯度值
	print('w.grad->', w.grad)
	w.data = w.data - 0.01 * w.grad
	print('w->', w)


if __name__ == '__main__':
	dm01()

梯度下降法求最优解

python 复制代码
"""
① 创建自动微分w权重张量
② 自定义损失函数 loss=w**2+20  后续无需自定义,导入不同问题损失函数模块
③ 前向传播 -> 先根据上一版模型计算预测y值, 根据损失函数计算出损失值
④ 反向传播 -> 计算梯度
⑤ 梯度更新 -> 梯度下降法更新w权重
"""
import torch


def dm01():
	# ① 创建自动微分w权重张量
	w = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
	print('w->', w)
	# ② 自定义损失函数 后续无需自定义, 导入不同问题损失函数模块
	loss = w ** 2 + 20
	print('loss->', loss)
	# 0.01 -> 学习率
	print('开始 权重x初始值:%.6f (0.01 * w.grad):无 loss:%.6f' % (w, loss))
	for i in range(1, 1001):
		# ③ 前向传播 -> 先根据上一版模型计算预测y值, 根据损失函数计算出损失值
		loss = w ** 2 + 20
		# 梯度清零 -> 梯度累加, 没有梯度默认None
		if w.grad is not None:
			w.grad.zero_()
		# ④ 反向传播 -> 计算梯度
		loss.sum().backward()
		# ⑤ 梯度更新 -> 梯度下降法更新w权重
		# W = W - lr * W.grad
		# w.data -> 更新w张量对象的数据, 不能直接使用w(将结果重新保存到一个新的变量中)
		w.data = w.data - 0.01 * w.grad
		print('w.grad->', w.grad)
		print('次数:%d 权重w: %.6f, (0.01 * w.grad):%.6f loss:%.6f' % (i, w, 0.01 * w.grad, loss))

	print('w->', w, w.grad, 'loss最小值', loss)


if __name__ == '__main__':
	dm01()

梯度计算注意点

python 复制代码
# 自动微分的张量不能转换成numpy数组, 可以借助detach()方法生成新的不自动微分张量
import torch

def dm01():
	x1 = torch.tensor(data=10, requires_grad=True, dtype=torch.float32)
	print('x1->', x1)
	# 判断张量是否自动微分 返回True/False
	print(x1.requires_grad) # True
	# 调用detach()方法对x1进行剥离, 得到新的张量,不能自动微分,数据和原张量共享
	x2 = x1.detach()
	print(x2.requires_grad) # False
	print(x1.data)
	print(x2.data)
	print(id(x1.data))
	print(id(x2.data))
	# 自动微分张量转换成numpy数组
	n1 = x2.numpy()
	print('n1->', n1)


if __name__ == '__main__':
	dm01()

自动微分模块应用

python 复制代码
import torch
import torch.nn as nn  # 损失函数,优化器函数,模型函数


def dm01():
	# todo:1-定义样本的x和y
	x = torch.ones(size=(2, 5))
	y = torch.zeros(size=(2, 3))
	print('x->', x)
	print('y->', y)
	# todo:2-初始模型权重 w b 自动微分张量
	w = torch.randn(size=(5, 3), requires_grad=True)
	b = torch.randn(size=(3,), requires_grad=True) # 一维的三个元素
	print('w->', w)
	print('b->', b)
	# todo:3-初始模型,计算预测y值
	y_pred = torch.matmul(x, w) + b
	print('y_pred->', y_pred)
	# todo:4-根据MSE损失函数计算损失值
	# 创建MSE对象, 类创建对象
	criterion = nn.MSELoss()
	loss = criterion(y_pred, y)
	print('loss->', loss)
	# todo:5-反向传播,计算w和b梯度
	loss.sum().backward()
	print('w.grad->', w.grad)
	print('b.grad->', b.grad)


if __name__ == '__main__':
	dm01()
相关推荐
reset20212 小时前
安防监控中目标检测方案探讨
人工智能·yolo·目标检测·目标跟踪
weixin_668898642 小时前
Bert解读
人工智能·机器学习·bert
wuxuand2 小时前
读顶刊综述:新兴技术下深度学习入侵检测的现状、鸿沟与未来
人工智能·深度学习
神奇小汤圆2 小时前
OpenClaw:让 AI 真正"干活"的私有智能体平台
人工智能
云原生指北3 小时前
命令行四件套:fd / rg / fzf / bat
人工智能
冰西瓜6003 小时前
深度学习的数学原理(二十三)—— Transformer开篇:从迷你模型到核心逻辑
人工智能·深度学习·transformer
仙女修炼史3 小时前
CNN可视化工具 CAM的理解
人工智能·神经网络·cnn
self_correction3 小时前
Python工具
网络·python·安全