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

【AI】Pytorch基础与张量计算入门

目录

一、Pytorch

1.1 简介

1.2 Pytorch安装

二、张量的创建与数值计算

2.1 张量创建

基本创建方式

创建线性和随机张量

创建01张量

张量元素类型转换

2.2 张量计算

基本运算

阿达玛积

点积运算

指定运算设备

三、张量类型转换

3.1 张量转换为numpy数组

3.2 numpy转换为张量

3.3 标量张量和数字的转换

四、张量拼接操作

4.1 torch.cat 函数的使用

4.2 torch.stack 函数的使用


一、Pytorch

1.1 简介

  • 在2017年1⽉,Facebook的⼈⼯智能研究院 (FAIR) 向世界推出了PyTorch,这个基于Torch的框架, 以其Python语⾔作为前端, 同时为深度学习研究者和开发者提供了两⼤核⼼优势:
    • ⼀是强⼤的GPU加速张量计算能⼒, 其并⾏计算能⼒在当时与NumPy相媲美。
    • ⼆是内置的⾃动微分系统, 使得构建深度神经⽹络变得更加直观和⾼效。

  • 2018年10月,在NeuriPS 2018会议上,Facebook宣布了PyTorch 1.0的发布。这个版本的推出标志着PyTorch在商业化进程中取得了重要进展。
  • 在2019年前,TensorFlow一直作为深度学习系统中的领头存在。而以2019年为分界线,PyTorch异军突起,逐渐成为了开发者和研究人员最为喜爱的框架。随着PyTorch的不断普及和完善,其生态也越发蓬勃。
  • 在AI领域,Hugging Face社区的开源Transformers库使用PyTorch实现了市面上绝大多数开源的预测模型。微软的分布式训练框架DeepSpeed也支持PyTorch。由于PyTorch备受研究人员的青睐,近年来绝大多数开源神经网络架构都采用PyTorch实现。

1.2 Pytorch安装

pip install torch==2.2.2

二、张量的创建与数值计算

2.1 张量创建

PyTorch 是⼀个 Python 深度学习框架,它将数据封装成张量(Tensor)来进⾏运算。PyTorch 中的张量就是元素为同⼀种数据类型的多维矩阵。在 PyTorch 中,张量以 "类" 的形式封装起来,对张量的⼀些运算、处理的⽅法被封装在类中。

基本创建方式

1. torch.tensor 根据指定数据创建张量
2. torch.Tensor 根据形状创建张量, 其也可⽤来创建指定数据的张量
3. torch.IntTensor、torch.FloatTensor、torch.DoubleTensor 创建指定类型的张量

import torch
import numpy as np
import random

# 1. 根据已有数据创建张量
def test01():
    # 1. 创建张量标量
    data = torch.tensor(10)
    print(data)
    # 2. numpy 数组, 由于 data 为 float64, 下⾯代码也使⽤该类型
    data = np.random.randn(2, 3)
    data = torch.tensor(data)
    print(data)
    # 3. 列表, 下⾯代码使⽤默认元素类型 float32
    data = [[10., 20., 30.], [40., 50., 60.]]
    data = torch.tensor(data)
    print(data)

# 2. 创建指定形状的张量
def test02():
    # 1. 创建2⾏3列的张量, 默认 dtype 为 float32
    data = torch.Tensor(2, 3)
    print(data)
    # 2. 注意: 如果传递列表, 则创建包含指定元素的张量
    data = torch.Tensor([10])
    print(data)
    data = torch.Tensor([10, 20])
    print(data)

# 3. 使⽤具体类型的张量
def test03():
    # 1. 创建2⾏3列, dtype 为 int32 的张量
    data = torch.IntTensor(2, 3)
    print(data)
    # 2. 注意: 如果传递的元素类型不正确, 则会进⾏类型转换
    data = torch.IntTensor([2.5, 3.3])
    print(data)
    # 3. 其他的类型
    data = torch.ShortTensor()  # int16
    data = torch.LongTensor()  # int64
    data = torch.FloatTensor()  # float32
    data = torch.DoubleTensor()  # float64

if __name__ == '__main__':
    test01()

程序输出结果:

tensor(10)
tensor([[ 0.1345, 0.1149, 0.2435],
 [ 0.8026, -0.6744, -1.0918]], dtype=torch.float64)
tensor([[10., 20., 30.],
 [40., 50., 60.]])
tensor([[0.0000e+00, 3.6893e+19, 2.2018e+05],
 [4.6577e-10, 2.4158e-12, 1.1625e+33]])
tensor([10.])
tensor([10., 20.])
tensor([[ 0, 1610612736, 1213662609],
 [ 805308409, 156041223, 1]], dtype=torch.int32)
tensor([2, 3], dtype=torch.int32)

创建线性和随机张量

1. torch.arange 和 torch.linspace 创建线性张量
2. torch.random.init_seed 和 torch.random.manual_seed 随机种⼦设置
3. torch.randn 创建随机张量

import torch

# 1. 创建线性空间的张量
def test01():
    # 1. 在指定区间按照步⻓⽣成元素 [start, end, step)
    data = torch.arange(0, 10, 2)
    print(data)
    # 2. 在指定区间按照元素个数⽣成
    data = torch.linspace(0, 11, 10)
    print(data)

# 2. 创建随机张量
def test02():
    # 1. 创建随机张量
    data = torch.randn(2, 3) # 创建2⾏3列张量
    print(data)
    # 2. 随机数种⼦设置
    print('随机数种⼦:', torch.random.initial_seed())
    torch.random.manual_seed(100)
    print('随机数种⼦:', torch.random.initial_seed())

if __name__ == '__main__':
    test02()

程序输出结果:

tensor([0, 2, 4, 6, 8])
tensor([ 0.0000, 1.2222, 2.4444, 3.6667, 4.8889, 6.1111, 7.3333, 8.5556,
9.7778, 11.0000])
tensor([[-0.5209, -0.2439, -1.1780],
 [ 0.8133, 1.1442, 0.6790]])
随机数种⼦: 4508475192273306739
随机数种⼦: 100

创建01张量

1. torch.ones 和 torch.ones_like 创建全1张量
2. torch.zeros 和 torch.zeros_like 创建全0张量
3. torch.full 和 torch.full_like 创建全为指定值张量

import torch

# 1. 创建全0张量
def test01():
    # 1. 创建指定形状全0张量
    data = torch.zeros(2, 3)
    print(data)
    # 2. 根据张量形状创建全0张量
    data = torch.zeros_like(data)
    print(data)

# 2. 创建全1张量
def test02():
    # 1. 创建指定形状全0张量
    data = torch.ones(2, 3)
    print(data)
    # 2. 根据张量形状创建全0张量
    data = torch.ones_like(data)
    print(data)

# 3. 创建全为指定值的张量
def test03():
    # 1. 创建指定形状指定值的张量
    data = torch.full([2, 3], 10)
    print(data)
    # 2. 根据张量形状创建指定值的张量
    data = torch.full_like(data, 20)
    print(data)

if __name__ == '__main__':
    test01()
    test02()
    test03()

程序输出结果:

tensor([[0., 0., 0.],
        [0., 0., 0.]])
tensor([[0., 0., 0.],
        [0., 0., 0.]])
tensor([[1., 1., 1.],
        [1., 1., 1.]])
tensor([[1., 1., 1.],
        [1., 1., 1.]])
tensor([[10, 10, 10],
        [10, 10, 10]])
tensor([[20, 20, 20],
        [20, 20, 20]])

张量元素类型转换

1. tensor.type(torch.DoubleTensor)
2. torch.double()

import torch

def test():
    data = torch.full([2, 3], 10)
    print(data.dtype)
    # 将 data 元素类型转换为 float64 类型
    # 1. 第⼀种⽅法
    data = data.type(torch.DoubleTensor)
    print(data.dtype)
    # 转换为其他类型
    # data = data.type(torch.ShortTensor)
    # data = data.type(torch.IntTensor)
    # data = data.type(torch.LongTensor)
    # data = data.type(torch.FloatTensor)

    # 2. 第⼆种⽅法
    data = data.double()
    print(data.dtype)
    # 转换为其他类型
    # data = data.short()
    # data = data.int()
    # data = data.long()
    # data = data.float()

if __name__ == '__main__':
    test()

 程序输出结果:

torch.int64
torch.float64
torch.float64

2.2 张量计算

PyTorch 计算的数据都是以张量形式存在, 我们需要掌握张量各种运算. 并且, 我们可以在 CPU 中运算, 也可以在 GPU 中运算。

基本运算

基本运算中,包括 add、sub、mul、div、neg 等函数, 以及这些函数的带下划线的版本 add、sub、mul、div、neg_,其中带下划线的版本为修改原数据。

import numpy as np
import torch

def test():
    data = torch.randint(0, 10, [2, 3])
    print(data)
    print('-' * 50)
    # 1. 不修改原数据
    new_data = data.add(10) # 等价 new_data = data + 10
    print(new_data)
    print('-' * 50)
    # 2. 直接修改原数据
    # 注意: 带下划线的函数为修改原数据本身
    data.add_(10) # 等价 data += 10
    print(data)
    # 3. 其他函数
    print(data.sub(100))
    print(data.mul(100))
    print(data.div(100))
    print(data.neg())

if __name__ == '__main__':
    test()

 程序输出结果: 

tensor([[3, 2, 0],
        [6, 0, 0]])
--------------------------------------------------
tensor([[13, 12, 10],
        [16, 10, 10]])
--------------------------------------------------
tensor([[13, 12, 10],
        [16, 10, 10]])
tensor([[-87, -88, -90],
        [-84, -90, -90]])
tensor([[1300, 1200, 1000],
        [1600, 1000, 1000]])
tensor([[0.1300, 0.1200, 0.1000],
        [0.1600, 0.1000, 0.1000]])
tensor([[-13, -12, -10],
        [-16, -10, -10]])

阿达玛积

阿达玛积指的是矩阵对应位置的元素相乘。

import numpy as np
import torch

def test():
    data1 = torch.tensor([[1, 2], [3, 4]])
    data2 = torch.tensor([[5, 6], [7, 8]])
    # 第⼀种⽅式
    data = torch.mul(data1, data2)
    print(data)
    print('-' * 50)
    
    # 第⼆种⽅式
    data = data1 * data2
    print(data)
    print('-' * 50)

if __name__ == '__main__':
    test()

 程序输出结果: 

tensor([[ 5, 12],
        [21, 32]])
--------------------------------------------------
tensor([[ 5, 12],
        [21, 32]])
--------------------------------------------------

点积运算

点积运算要求第⼀个矩阵 shape: (n, m),第⼆个矩阵 shape: (m, p), 两个矩阵点积运算 shape 为: (n, p)。

  1. 运算符 @ ⽤于进⾏两个矩阵的点乘运算
  2. torch.mm ⽤于进⾏两个矩阵点乘运算, 要求输⼊的矩阵为2维
  3. torch.bmm ⽤于批量进⾏矩阵点乘运算, 要求输⼊的矩阵为3维
  4. torch.matmul 对进⾏点乘运算的两矩阵形状没有限定.
    1. 对于输⼊都是⼆维的张量相当于 mm 运算
    2. 对于输⼊都是三维的张量相当于 bmm 运算
    3. 对数输⼊的 shape 不同的张量, 对应的最后⼏个维度必须符合矩阵运算规则

import numpy as np
import torch

# 1. 点积运算
def test01():
    data1 = torch.tensor([[1, 2], [3, 4], [5, 6]])
    data2 = torch.tensor([[5, 6], [7, 8]])

    # 第⼀种⽅式
    data = data1 @ data2
    print(data)
    print('-' * 50)

    # 第⼆种⽅式
    data = torch.mm(data1, data2)
    print(data)
    print('-' * 50)

    # 第三种⽅式
    data = torch.matmul(data1, data2)
    print(data)
    print('-' * 50)

# 2. torch.mm 和 torch.matmull 的区别
def test02():
    # matmul 可以两个维度可以不同
    # 第⼀个张量: (3, 4, 5)
    # 第⼆个张量: (5, 4)
    # torch.mm 不可以相乘,⽽ matmul 则可以相乘
    print(torch.matmul(torch.randn(3, 4, 5), torch.randn(5, 4)).shape)
    print(torch.matmul(torch.randn(5, 4), torch.randn(3, 4, 5)).shape)
    # 3. torch.mm 函数的⽤法
def test03():
    # 批量点积运算
    # 第⼀个维度为 batch_size
    # 矩阵的⼆三维要满⾜矩阵乘法规则
    data1 = torch.randn(3, 4, 5)
    data2 = torch.randn(3, 5, 8)
    data = torch.bmm(data1, data2)
    print(data.shape)

if __name__ == '__main__':
    test01()
    test02()
    test03()

 程序输出结果: 

tensor([[19, 22],
        [43, 50],
        [67, 78]])
--------------------------------------------------
tensor([[19, 22],
        [43, 50],
        [67, 78]])
--------------------------------------------------
tensor([[19, 22],
        [43, 50],
        [67, 78]])
--------------------------------------------------
torch.Size([3, 4, 4])
torch.Size([3, 5, 5])
torch.Size([3, 4, 8])

指定运算设备

PyTorch 默认会将张量创建在 CPU 控制的内存中,即:默认的运算设备为 CPU。我们也可以将张量创建在GPU 上, 能够利用对于矩阵计算的优势加快模型训练。将张量移动到 GPU 上有两种方法:

  1. 使用 cuda 方法
  2. 直接在 GPU 上创建张量
  3. 使用 to 方法指定设备
import torch

# 1. 使⽤ cuda ⽅法
def test01():
    data = torch.tensor([10, 20 ,30])
    print('存储设备:', data.device)
    # 如果安装的不是 gpu 版本的 PyTorch
    # 或电脑本身没有 NVIDIA 卡的计算环境
    # 下⾯代码可能会报错
    data = data.cuda()
    print('存储设备:', data.device)
    # 使⽤ cpu 函数将张量移动到 cpu 上
    data = data.cpu()
    print('存储设备:', data.device)
    # 输出结果:
    # 存储设备: cpu
    # 存储设备: cuda:0
    # 存储设备: cpu

# 2. 直接将张量创建在 GPU 上
def test02():
    data = torch.tensor([10, 20, 30], device='cuda:0')
    print('存储设备:', data.device)
    # 使⽤ cpu 函数将张量移动到 cpu 上
    data = data.cpu()
    print('存储设备:', data.device)
    # 输出结果:
    # 存储设备: cuda:0
    # 存储设备: cpu

# 3. 使⽤ to ⽅法
def test03():
    data = torch.tensor([10, 20, 30])
    print('存储设备:', data.device)
    data = data.to('cuda:0')
    print('存储设备:', data.device)
    # 输出结果:
    # 存储设备: cpu
    # 存储设备: cuda:0
    # 4. 存储在不同设备的张量不能运算

def test04():
    data1 = torch.tensor([10, 20, 30], device='cuda:0')
    data2 = torch.tensor([10, 20, 30])
    print(data1.device, data2.device)
    # RuntimeError: Expected all tensors to be on the same device,
    # but found at least two devices, cuda:0 and cpu!
    data = data1 + data2
    print(data)

if __name__ == '__main__':
    test01()

三、张量类型转换

张量的类型转换也是经常使⽤的⼀种操作,是必须掌握的知识点。在本小节,我们主要学习如何将 numpy数组和 PyTorch Tensor 的转化⽅法。

3.1 张量转换为numpy数组

使用 Tensor.numpy 函数可以将张量转换为 ndarray 数组,但是共享内存,可以使⽤ copy 函数避免共享。

import torch

# 1. 将张量转换为 numpy 数组
def test01():
    data_tensor = torch.tensor([2, 3, 4])
    # 使⽤张量对象中的 numpy 函数进⾏转换
    data_numpy = data_tensor.numpy()
    print(type(data_tensor))
    print(type(data_numpy))
    # 注意: data_tensor 和 data_numpy 共享内存
    # 修改其中的⼀个,另外⼀个也会发⽣改变
    # data_tensor[0] = 100
    data_numpy[0] = 100
    print(data_tensor)
    print(data_numpy)

if __name__ == '__main__':
    test01()

 程序输出结果:  

<class 'torch.Tensor'>
<class 'numpy.ndarray'>
tensor([100,   3,   4])
[100   3   4]

3.2 numpy转换为张量

1. 使用 from_numpy 可以将 ndarray 数组转换为 Tensor,默认共享内存,使用 copy 函数避免共享。
2. 使用 torch.tensor 可以将 ndarray 数组转换为 Tensor,默认不共享内存。

import torch
import numpy as np

# 1. 使⽤ from_numpy 函数
def test01():
    data_numpy = np.array([2, 3, 4])
    # 将 numpy 数组转换为张量类型
    # 1. from_numpy
    # 2. torch.tensor(ndarray)
    # 浅拷⻉
    data_tensor = torch.from_numpy(data_numpy)
    # nunpy 和 tensor 共享内存
    # data_numpy[0] = 100
    data_tensor[0] = 100
    print(data_tensor)
    print(data_numpy)

# 2. 使⽤ torch.tensor 函数
def test02():
    data_numpy = np.array([2, 3, 4])
    data_tensor = torch.tensor(data_numpy)
    # nunpy 和 tensor 不共享内存
    # data_numpy[0] = 100
    data_tensor[0] = 100
    print(data_tensor)
    print(data_numpy)

if __name__ == '__main__':
    test01()
    test02()

 程序输出结果: 

tensor([100,   3,   4], dtype=torch.int32)
[100   3   4]
tensor([100,   3,   4], dtype=torch.int32)
[2 3 4]

3.3 标量张量和数字的转换

对于只有⼀个元素的张量,使用 item ⽅法将该值从张量中提取出来。

import torch
import numpy as np

# 3. 标量张量和数字的转换
def test03():
    # 当张量只包含⼀个元素时, 可以通过 item 函数提取出该值
    data = torch.tensor([30,])
    print(data.item())
    data = torch.tensor(30)
    print(data.item())

if __name__ == '__main__':
    test03()

 程序输出结果: 

30
30

四、张量拼接操作

张量的拼接操作在神经网络搭建过程中是非常常⽤的⽅法,例如: 在后面将要学习到的残差网络、注意力机制中都使用到了张量拼接。

4.1 torch.cat 函数的使用

torch.cat 函数可以将两个张量根据指定的维度拼接起来。

import torch
import numpy as np

def test():
    data1 = torch.randint(0, 10, [3, 5, 4])
    data2 = torch.randint(0, 10, [3, 5, 4])
    print(data1)
    print(data2)
    print('-' * 50)
    # 1. 按0维度拼接
    new_data = torch.cat([data1, data2], dim=0)
    print(new_data.shape)
    print('-' * 50)
    # 2. 按1维度拼接
    new_data = torch.cat([data1, data2], dim=1)
    print(new_data.shape)
    print('-' * 50)
    # 3. 按2维度拼接
    new_data = torch.cat([data1, data2], dim=2)
    print(new_data.shape)

if __name__ == '__main__':
    test()

 程序输出结果:  

tensor([[[9, 6, 4, 9],
         [3, 2, 2, 6],
         [1, 8, 1, 4],
         [9, 4, 8, 2],
         [4, 2, 6, 1]],

        [[2, 2, 4, 7],
         [6, 2, 4, 7],
         [0, 2, 4, 6],
         [0, 6, 2, 8],
         [3, 8, 6, 5]],

        [[4, 9, 9, 8],
         [6, 1, 0, 6],
         [1, 5, 0, 5],
         [7, 1, 9, 7],
         [6, 5, 7, 0]]])
tensor([[[6, 3, 4, 4],
         [4, 4, 5, 1],
         [8, 4, 0, 9],
         [6, 3, 7, 9],
         [5, 8, 4, 7]],

        [[2, 9, 9, 5],
         [0, 2, 9, 0],
         [4, 5, 6, 5],
         [2, 6, 4, 5],
         [1, 1, 4, 4]],

        [[5, 5, 7, 4],
         [6, 8, 0, 8],
         [2, 7, 7, 2],
         [5, 2, 7, 5],
         [9, 0, 4, 4]]])
--------------------------------------------------
torch.Size([6, 5, 4])
--------------------------------------------------
torch.Size([3, 10, 4])
--------------------------------------------------
torch.Size([3, 5, 8])

4.2 torch.stack 函数的使用

torch.stack 函数可以将两个张量根据指定的维度叠加起来。

import torch
import numpy as np

def test():
    data1= torch.randint(0, 10, [2, 3])
    data2= torch.randint(0, 10, [2, 3])
    print(data1)
    print(data2)
    new_data = torch.stack([data1, data2], dim=0)
    print(new_data.shape)
    new_data = torch.stack([data1, data2], dim=1)
    print(new_data.shape)
    new_data = torch.stack([data1, data2], dim=2)
    print(new_data.shape)
    
if __name__ == '__main__':
    test()

 程序输出结果:  

tensor([[8, 2, 4],
        [4, 7, 2]])
tensor([[2, 7, 4],
        [4, 0, 6]])
torch.Size([2, 2, 3])
torch.Size([2, 2, 3])
torch.Size([2, 3, 2])

http://www.kler.cn/a/552277.html

相关文章:

  • C++ queue:数据结构的“排队哲学”与“先进先出法则
  • python爬虫系列课程3:解决爬虫过程中遇到的编码问题
  • Excel如何实现行分级,以及如何用Python 3实现Excel行分级
  • C++(23):unreachable
  • 深入解析 Flutter 高级路由管理:使用 go_router 和 auto_route 实现复杂路由与拦截
  • Mermaid绘图技巧:如何在节点文本中实现换行
  • 力扣 跳跃游戏 II
  • 从WebRTC到EasyRTC:嵌入式适配的视频通话SDK实现低延迟、高稳定性音视频通信
  • springboot024-玩具租赁系统
  • Java-数据结构-(HashMap HashSet)
  • 阶段 1:Kafka基础认知
  • WPF高级 | WPF 自定义控件开发:从需求分析到完整实现
  • MoE硬件部署
  • el-table已经选中的项,通过selectable属性不可以再次选择
  • 视频编解码标准中的 Profile 和 Level
  • QT实战-qt各种菜单样式实现2
  • sql server查询IO消耗大的排查sql诊断语句
  • 【产品资料】陀螺匠·企业助手v1.8 产品介绍
  • 豪越科技:消防安全重点单位一体化安全管控
  • 基于SSM框架的宠物之家系统(有源码+论文!!!)