Pytorch基础知识Ⅱ之张量Tensor操作(很全面)

一、基本张量操作

torch.tensor()

torch.tensor() 会拷贝数据

torch.tensor(12)
torch.tensor([0123])
torch.tensor([[1,2,3,4][5,6,7,8],
              [9,10,11,12]])
# --------------------------
np_array = np.array([1, 2, 3])
tensor = torch.tensor(np_array)
  
tensor[0] = 999
print(np_array)   # [1 2 3]

torch.from_numpy()

NumPy Array 转化成 Torch Tensor
内存共享,零拷贝,只能用于CPU

np_array = np.array([1, 2, 3])
tensor = torch.from_numpy(np_array)
  
tensor[0] = 999
print(np_array)  # [999 2 3]
print(tensor)    # tensor([999, 2, 3])

torch.as_tensor()

from_numpy = 强制共享(零拷贝)
as_tensor = 尽量共享,dtype 不同就拷贝,不共享内存了
as_tensor + GPU = 一定拷贝

"""
情况一,零拷贝,双向同步
"""
np_array = np.array([1, 2, 3])
tensor = torch.as_tensor(np_array) # 行为和 from_numpy() 一样
  
tensor[0] = 999
print(np_array)  # [999 2 3]
print(tensor)    # tensor([999, 2, 3], dtype=torch.int32)
"""
情况二
"""
np_array = np.array([1, 2, 3], dtype=np.int32)
tensor = torch.as_tensor(np_array, dtype=torch.float32) 
  
tensor[0] = 999
print(np_array)  # [1 2 3],与numpy一样
print(tensor)    # tensor([999., 2., 3.])
"""
情况三,NumPy 只能在 CPU,GPU Tensor 一定重新分配内存
"""
np_array = np.array([1, 2, 3])
tensor = torch.as_tensor(np_array, device="cuda") 
  
tensor[0] = 999
print(np_array)  # [1 2 3]
print(tensor)    # tensor([999, 2, 3], device='cuda:0')

torch.zeros()

torch.zeros((2, 3, 4))
tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],

        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])

torch.randn()

随机初始化参数的值,其中的每个元素都从均值为0、标准差为1的标准高斯分布(正态分布)中随机采样

torch.randn(3, 4)  
tensor([[-0.0135,  0.0665,  0.0912,  0.3212],
        [ 1.4653,  0.1843, -1.6995, -0.3036],
        [ 1.7646,  1.0450,  0.2457, -0.7732]])

torch.arange()

tensor = torch.arange(12) # tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

tensor.shape()/reshape()

reshape() 尽量返回 view,但在非连续内存时会自动拷贝

tensor.shape()

tensor.reshape(-1,1) #  -1 根据剩下的维度计算出数组的另外一个shape属性值
tensor.reshape(-1,2) #  -1 表示自动计算维度,而 2 表示将数组调整为两列

tensor = tensor.reshape(3,4)
tensor.shape()
torch.Size([12])
tensor([[ 0],
        [ 1],
        [ 2],
        [ 3],
        [ 4],
        [ 5],
        [ 6],
        [ 7],
        [ 8],
        [ 9],
        [10],
        [11]])
tensor([[ 0,  1],
        [ 2,  3],
        [ 4,  5],
        [ 6,  7],
        [ 8,  9],
        [10, 11]])
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
torch.Size([3,4])

tensor.numel()

张量中元素的总数,即形状的所有元素乘积

tensor.numel()  # 12

tensor.item()

item()函数用于从只包含单个元素的张量中提取Python数值,将张量转换为标量值

import torch
# 创建一个只包含一个元素的张量
tensor = torch.tensor([3.14])
value = tensor.item()
print(value)  # 3.140000104904175

二、重要的张量处理方法

torch.t(A)

用于计算矩阵的转置

A = torch.arange(12).reshape(3,4)
torch.t(A)
tensor([[ 0,  4,  8],
        [ 1,  5,  9],
        [ 2,  6, 10],
        [ 3,  7, 11]])

torch.mm(A,B)

用于计算两个矩阵的乘积

A = torch.arange(12).reshape(3,4)
B = torch.arange(12).reshape(4,3)
torch.mm(A,B)
tensor([[ 42,  48,  54],
        [114, 136, 158],
        [186, 224, 262]])

torch.mv(A,x)

用于计算矩阵-向量积

A = torch.arange(9).reshape(3,3) # tensor([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
x = torch.arange(3) #tensor([0, 1, 2])
torch.mv(A,x)
tensor([ 5, 14, 23])

torch.mul()

用于执行两个张量的元素级乘法

tensor1 = torch.tensor([[1, 2], [3, 4]])
tensor2 = torch.tensor([[5, 6], [7, 8]])
torch.mul(tensor1, tensor2)
tensor([[ 5, 12],
        [21, 32]])

torch.sum()

用于计算张量元素的和

tensor = torch.tensor([[1, 2], [3, 4]])
torch.sum(tensor)
tensor(10)

torch.mean()

用于计算张量元素的平均值

tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
torch.mean(tensor)
tensor(2.5000)

torch.norm(x)

计算向量L2L_2L2的范数

x = torch.tensor([1.0,2.0,3.0])
torch.norm(x)
tensor(3.7417)

torch.abs(x).sum()

计算向量L1L_1L1的范数

x = torch.tensor([1.0,2.0,3.0])
torch.abs(x).sum()
tensor(6.)

三、运算操作

torch.cat()

沿现有指定维度拼接张量

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [ 2.,  1.,  4.,  3.],
         [ 1.,  2.,  3.,  4.],
         [ 4.,  3.,  2.,  1.]]),
 tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
         [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
         [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))

torch.stack()

在不改变原始张量内容的情况下,在特定维度上创建更高维度的张量。所有张量必须具有相同的大小。
应用场景:
在自然语言处理(NLP)和图像卷积神经网络(CV)中非常常见,因为它可以保留序列信息和张量矩阵信息。例如,在循环神经网络(RNN)中,输出数据通常是一个包含多个形状为 [batchsize,outputsize][batch_{size}, output_{size}][batchsize,outputsize] 的张量的列表。为了便于计算,需要使用 torch.stacktorch.stacktorch.stack 进行拼接,以保留时间步长和张量属性信息。

m = torch.tensor([[1, 2, 3], [4, 5, 6]]) 
n = torch.tensor([[7, 8, 9], [10, 11, 12]]) 
v = torch.tensor([[13, 14, 15], [16, 17, 18]])
torch.stack((m, n, v), dim=0) 
tensor([[[ 1,  2,  3],
         [ 4,  5,  6]],

        [[ 7,  8,  9],
         [10, 11, 12]],

        [[13, 14, 15],
         [16, 17, 18]]])
shape: (3,2,3)

torch.transpose(tensor,dim0,dim1) / tensor.transpose(dim0,dim1)

交换张量的两个维度

x = torch.arange(12).reshape(2,6)
torch.transpose(x,0,1).shape
torch.transpose(x,1,0).shape
x.transpose(0,1).shape
y = torch.arange(24).reshape(2,4,3)
torch.transpose(y,0,2).shape
torch.transpose(y,2,1).shape
y.transpose(0,1).shape
torch.Size([6, 2])
torch.Size([6, 2])
torch.Size([6, 2])
torch.Size([3, 4, 2])
torch.Size([2, 3, 4])
torch.Size([4, 2, 3])

tensor.permute(∗*dims)

用于重新排列张量的所有维度,可以一次操作多维数据,且必须传入所有维度数

y.permute(2,0,1)
y.permute(2,0,1).shape
tensor([[[ 0,  3,  6,  9],
         [12, 15, 18, 21]],

        [[ 1,  4,  7, 10],
         [13, 16, 19, 22]],

        [[ 2,  5,  8, 11],
         [14, 17, 20, 23]]])
shape:(3,2,4)

tensor.squeeze()

用于移除张量中维度为 1 的维度的函数。默认会移除所有维度为 1 的维度,也可指定要移除的维度,但指定的维度大小必须为 1 。它可以简化张量的形状,常用于数据预处理或模型输入调整。

z = torch.arange(24).reshape(2,4,3,1)
z.squeeze().shape
z.squeeze()
z.squeeze(3).shape
torch.Size([2, 4, 3])
tensor([[[ 0,  1,  2],
         [ 3,  4,  5],
         [ 6,  7,  8],
         [ 9, 10, 11]],

        [[12, 13, 14],
         [15, 16, 17],
         [18, 19, 20],
         [21, 22, 23]]])
torch.Size([2, 4, 3])

torch.unsqueeze(tensor, dim)

用于在指定的维度上为张量新增一个大小为 1 的维度。这对于调整张量形状以适应特定操作或模型需求非常有帮助
应用场景
计算机视觉:将单通道图像数据从 [H,W][H, W][H,W] 转换为 [1,1,H,W][1, 1, H, W][1,1,H,W] ,以适应卷积神经网络的输入格式。
自然语言处理:将一维文本序列数据从 [T][T][T] 转换为 [1,T,1][1, T, 1][1,T,1] ,以便进行批量处理或适应特定模型需求。

a = torch.tensor([[1, 2, 3], [4, 5, 6]])
torch.unsqueeze(a, 0).shape
torch.unsqueeze(a, -1).shape
torch.unsqueeze(a, 1).shape
torch.Size([1, 2, 3])
torch.Size([2, 3, 1])
torch.Size([2, 1, 3])

tensor.expand()

将一个张量(Tensor)的单个维度扩展到更大的尺寸。扩展张量不会分配新的内存,只是在存在的张量上创建一个新的视图(view),其中尺寸为 1 的维度被扩展到更大的尺寸,通过将步长(stride)设置为0来实现。
应用场景
expand函数常用于广播操作,例如在卷积神经网络(CNN)中全局平均池化(GAP)后的操作。它允许将具有较小尺寸的张量扩展到与另一个张量相匹配的尺寸,以便进行元素间的操作,如加法或乘法。

e = torch.tensor([[1], [2], [3]])
e.expand(3, 4)
e.expand(4, 1)
f = torch.Tensor([[[[1,2], [2,3], [3,4],[4,5]]]])
f.expand(2, 1, 4, 2)
f.expand(1, 2, 4, 2)
tensor([[1, 1, 1, 1],
        [2, 2, 2, 2],
        [3, 3, 3, 3]])
RuntimeError: The expanded size of the tensor (4) must match the existing size (3) at non-singleton dimension 0. Target sizes: [4, 1]. Tensor sizes: [3, 1]
tensor([[[[1., 2.],
          [2., 3.],
          [3., 4.],
          [4., 5.]]],

        [[[1., 2.],
          [2., 3.],
          [3., 4.],
          [4., 5.]]]])
tensor([[[[1., 2.],
          [2., 3.],
          [3., 4.],
          [4., 5.]],

         [[1., 2.],
          [2., 3.],
          [3., 4.],
          [4., 5.]]]])

torch.floor()

用于将张量元素向下取整,得到不超过每个元素的最大整数

tensor = torch.tensor([[1.2,2.8],[3.5,4.1]])
torch.floor(tensor)
tensor([[1., 2.],
[3., 4.]])

torch.ceil()

用于将张量元素向上取整,得到不小于每个元素的最小整数

tensor = torch.tensor([[1.2,2.8],[3.5,4.1]])
torch.ceil(tensor)
tensor([[2., 3.],
[4., 5.]])

四、数学和统计操作

torch.std()

用于计算张量元素的标准差

tensor = torch.tensor([1.0,2.0,4.0])
torch.std(tensor)
tensor(1.5275)

torch.max()

用于找到张量中的最大值及其索引

tensor = torch.arange(1,13).reshape(2,6)
torch.max(tensor)
torch.max(tensor,dim=1)
tensor(12)
torch.return_types.max(
values=tensor([ 6, 12]),
indices=tensor([5, 5]))

torch.min()

用于找到张量中的最小值及其索引

tensor = torch.arange(1,13).reshape(2,6)
torch.min(tensor)
torch.min(tensor,dim=1)
torch.return_types.min(
values=tensor([1, 7]),
indices=tensor([0, 0]))

torch.abs()

用于计算张量元素的绝对值

tensor = torch.tensor([[-1, 2], [-3, 4]])
torch.abs(tensor)
tensor([[1, 2],
        [3, 4]])

torch.exp()

用于计算张量元素的指数

tensor = torch.tensor([[-1, 2], [-3, 4]])
torch.exp(tensor)
tensor([[3.6788e-01, 7.3891e+00],
        [4.9787e-02, 5.4598e+01]])

torch.log()

用于计算张量元素的自然对数

tensor = torch.tensor([[1, 2], [3, 4]])
torch.log(tensor)
tensor([[0.0000, 0.6931],
        [1.0986, 1.3863]])

torch.argmax()

用于返回输入张量(Tensor)中最大值的索引

import torch
tensor1 = torch.tensor([[0.1,0.2],
						[0.3,0.4]])
tensor.argmax(1) # dim=1,在行里面找
tensor2 = torch.tensor([[0.1,0.2],
						[0.05,0.4]])
tensor.argmax(0) # dim=0,在列里面找
tensor([1, 1])
tensor([0, 1])

五、重要的深度学习操作

1.随机性控制(可复现性)

torch.manual_seed()

设置 CPU 上随机数生成器的种子,使得随机操作(如 randn、初始化权重)结果可复现

torch.manual_seed(42)
torch.cuda.manual_seed_all()

设置所有 GPU 上的随机种子,多卡训练必须设置

torch.cuda.manual_seed_all(42)

2.设备迁移(CPU / GPU)

tensor.to(device)

将张量 / 模型迁移到指定设备,返回一个新 tensor(不是原地)
Tensor 永远“属于”某一个 device(CPU / GPU),运算双方必须在同一device

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tensor = tensor.to(device)
model = model.to(device)

3.计算图相关操作

tensor.requires_grad_(True/False)

决定这个 Tensor 是否参与反向传播
参数默认 True,数据默认 False

x = torch.randn(3, requires_grad=True)
y = x * 2
x.requires_grad_(False)
y.backward()   # 会报错,因为一旦 Tensor 已经参与计算图,修改 requires_grad 会破坏 Autograd 对计算图的假设
tensor.detach()

返回一个共享数据、但不共享计算图的新 tensor,不会影响原计算图,不计算梯度

y = x.detach()

detach()和clone()对比:

clone()  : 拷贝数据 + 保留梯度历史
detach() : 共享数据 + 切断梯度
detach().clone() : 拷贝数据 + 切断梯度(最安全) → 实战中最常用的组合
torch.no_grad()

关闭梯度计算,推理 / 验证阶段必须用

with torch.no_grad():
    output = model(x)

4.内存与拷贝

tensor.clone()

真正的深拷贝,打断“视图”关系

tensor.numpy()
tensor.numpy()  # CPU tensor:共享内存
tensor.cpu().numpy()

CPU tensor:共享内存 GPU tensor:必须先 .cpu()

六、改变元数据的操作

在pytorch中,Tensor = 数据块(storage) + 元数据(shape / stride / offset)
只有很少几个操作是不改变tensor的内容本身,而只是重新定义下标与元素的对应关系的。换句话说,这种操作不进行数据拷贝和数据的改变,变的是元数据,即不动底层数据,只改:shape、stride、offset。
下面几个操作会改变元数据:

torch.contiguous()

方法用于确保张量的内存布局是连续的,下面view的例子中有提及

view()

改变shape,前提:内存必须是连续的

x = torch.arange(12)   # x在内存中是连续的
y = x.view(3, 4)       # view()只需要重新计算 stride,不需要拷贝数据
print(y)
print(y.is_contiguous())
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])
True

错误用法(非连续内存)

x = torch.arange(12).reshape(3, 4)
y = x.transpose(0, 1)   # 改变 stride,不连续
print(y.is_contiguous())
z = y.view(6, 2)

False
RuntimeError: view size is not compatible with input tensor's size and stride

报错原因:transpose() 只改 stride,不拷贝数据,得到的 y 在物理内存中是“跳着走的”,view() 要求内存连续,stride 对不上,PyTorch 直接拒绝
正确修复方式

z = y.contiguous().view(6, 2)  # contiguous():强制拷贝一份连续内存

transpose()

transpose()看起来变了,其实没拷贝,得到的是视图(view),不是新 tensor

x = torch.arange(6).reshape(2, 3)
y = x.transpose(0, 1)
print(x)
print(y)
print(x.storage().data_ptr() == y.storage().data_ptr())
tensor([[0, 1, 2],
        [3, 4, 5]])
tensor([[0, 3],
        [1, 4],
        [2, 5]])
True

在使用transpose()进行转置操作时,pytorch并不会创建新的、转置后的tensor,而是修改了tensor中的一些属性(也就是元数据),使得此时的offset和stride是与转置tensor相对应的。转置的tensor和原tensor的内存是共享的

narrow(input, dim, start, length)

和transpose类似,不拷贝,得到的是view,常用于大tensor的局部窗口。
返回一个经过裁剪的 input 张量的新张量。维度 dim 从 start 到 start + length。返回的张量和 input 张量共享相同的底层存储。

x = torch.tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# y = torch.narrow(x, 0, 0, 2)
# y = torch.narrow(x, 1, 1, 2)
y = torch.narrow(x, -1, torch.tensor(-1), 1)

y[0] = 999
print(x)
print(y)
tensor([[1, 2, 3],
        [4, 5, 6]])
tensor([[2, 3],
        [5, 6],
        [8, 9]])
tensor([[3],
        [6],
        [9]])
tensor([[  1,   2, 999],
        [  4,   5,   6],
        [  7,   8,   9]])
tensor([[999],
        [  6],
        [  9]])

写操作会影响原tensor

expand()

没有拷贝,扩展维度的stride=0,适合做广播计算

x = torch.tensor([[1], [2], [3]])
x.expand(3, 4)
x.expand(-1, 5)  # -1 means not changing the size of that dimension
tensor([[1, 1, 1, 1],
        [2, 2, 2, 2],
        [3, 3, 3, 3]])
tensor([[1, 1, 1, 1, 1],
        [2, 2, 2, 2, 2],
        [3, 3, 3, 3, 3]])

不能对 expand 后的 tensor 做写操作,因为expand 后的多个位置指向同一个物理内存,写一个 = 写多个,PyTorch 禁止这种歧义写操作

报错:
RuntimeError: a view of a leaf Variable that requires grad is being used in an in-place operation
在无梯度情况下:
RuntimeError: unsupported operation: more than one element of the written-to tensor refers to a single memory location

正确做法应该是先clone,再去对clone后的tensor做写操作

总结

🧠 PyTorch Tensor 操作的三条铁律
①是否拷贝数据,不看“函数名”,看 storage 是否共享
view / transpose / narrow / expand → 改的是 元数据(shape / stride),不是数据
③ 只要出现以下任意一个,几乎一定会拷贝:

  • dtype 改变
  • device 改变
  • contiguous()
  • 明确的 clone()
<think>我们已知在PyTorch中,张量Tensor)是其核心数据结构,提供了高效的数值计算和自动求导功能。现在,我们需要在C++中实现类似的功能。由于PyTorch本身是用C++编写的(其核心库为libtorch),我们可以直接使用PyTorch的C++前端(LibTorch)来实现。 ### 步骤1:设置开发环境 首先,需要下载LibTorch库。可以从PyTorch官网下载预编译的LibTorch库(根据操作系统和是否需要CUDA支持选择合适版本)。 ### 步骤2:创建C++项目并配置 假设使用CMake构建项目,需要配置CMakeLists.txt以链接LibTorch库。 #### 示例CMakeLists.txt ```cmake cmake_minimum_required(VERSION 3.0 FATAL_ERROR) project(example) # 设置C++标准 set(CMAKE_CXX_STANDARD 14) # 查找LibTorch库,假设LibTorch的路径已经设置(或通过环境变量指定) find_package(Torch REQUIRED) # 添加可执行文件 add_executable(example example.cpp) # 链接LibTorch库 target_link_libraries(example "${TORCH_LIBRARIES}") ``` ### 步骤3:编写C++代码 以下是一个简单的示例,展示如何在C++中创建张量、进行基本操作和自动求导。 ```cpp #include <torch/torch.h> #include <iostream> int main() { // 创建两个张量 torch::Tensor a = torch::tensor({1.0, 2.0, 3.0}); torch::Tensor b = torch::tensor({4.0, 5.0, 6.0}); // 加法操作 torch::Tensor c = a + b; std::cout << "Tensor c: " << c << std::endl; // 创建一个需要梯度的张量 torch::Tensor x = torch::ones({2, 2}, torch::requires_grad()); torch::Tensor y = x + 2; torch::Tensor z = y * y * 3; torch::Tensor out = z.mean(); // 反向传播 out.backward(); // 输出梯度 d(out)/dx std::cout << "Gradient of x: \n" << x.grad() << std::endl; return 0; } ``` ### 步骤4:编译和运行 使用CMake构建项目并运行: ```bash mkdir build cd build cmake -DCMAKE_PREFIX_PATH=/path/to/libtorch .. cmake --build . --config Release ./example ``` ### 说明 1. **张量创建**:使用`torch::tensor`函数从初始化列表创建张量,也可以使用`torch::ones`、`torch::zeros`等函数。 2. **自动求导**:通过设置`torch::requires_grad()`来标记需要计算梯度的张量,然后进行前向计算,调用`backward()`进行反向传播。 3. **操作**:支持常见的数学操作(如加、减、乘、除)和矩阵运算(如矩阵乘法)。 ### 高级操作 LibTorch提供了与PythonPyTorch类似的API,包括: - 索引和切片 - 形状变换(view, reshape) - 数据类型转换 - 设备切换(CPU/GPU) - 神经网络模块(通过`torch::nn`模块) 例如,构建一个简单的神经网络: ```cpp #include <torch/torch.h> struct Net : torch::nn::Module { torch::nn::Linear fc1{nullptr}, fc2{nullptr}; Net() { fc1 = register_module("fc1", torch::nn::Linear(784, 64)); fc2 = register_module("fc2", torch::nn::Linear(64, 10)); } torch::Tensor forward(torch::Tensor x) { x = torch::relu(fc1->forward(x.view({x.size(0), 784}))); x = torch::log_softmax(fc2->forward(x), 1); return x; } }; int main() { auto net = std::make_shared<Net>(); torch::Tensor input = torch::randn({1, 1, 28, 28}); torch::Tensor output = net->forward(input); std::cout << output << std::endl; return 0; } ``` ### 注意事项 - 确保下载的LibTorch版本与系统兼容(例如,Linux、Windows、Mac)。 - 在CMake配置中,正确设置LibTorch路径(可以通过设置`CMAKE_PREFIX_PATH`环境变量或在CMake命令中指定)。 - LibTorch库较大,编译时需要足够内存。 通过以上步骤,可以在C++中实现类似于PyTorch张量操作。 ### 相关问题 1. 如何在C++中使用LibTorch进行张量的GPU加速计算? 2. LibTorch支持哪些张量操作?与PythonPyTorch有何差异? 3. 如何在C++中实现自定义的自动求导函数? 4. 使用LibTorch构建神经网络模型的基本步骤是什么? 5. 如何将训练好的PyTorch模型(Python)加载到C++中进行推理?</think>在C++中实现类似于PyTorch张量操作,最直接的方式是使用PyTorch的官方C++前端库**LibTorch**。以下是具体实现步骤和关键概念: ### 一、环境配置 1. **安装LibTorch** 从PyTorch官网下载预编译的LibTorch库(支持CPU/GPU版本): ```bash # 示例:Linux CPU版本 wget https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.3.0%2Bcpu.zip unzip libtorch.zip ``` 2. **CMake配置** 创建`CMakeLists.txt`: ```cmake cmake_minimum_required(VERSION 3.18) project(tensor_demo) set(CMAKE_CXX_STANDARD 17) # 指定LibTorch路径 set(TORCH_PATH /path/to/libtorch) find_package(Torch REQUIRED PATHS ${TORCH_PATH}) add_executable(main main.cpp) target_link_libraries(main "${TORCH_LIBRARIES}") ``` ### 二、核心张量操作实现 #### 1. 张量创建与属性查看 ```cpp #include <torch/torch.h> int main() { // 创建张量 auto tensor = torch::tensor({{1, 2}, {3, 4}}, torch::kFloat32); // 查看属性 std::cout << "形状: " << tensor.sizes() << "\n"; std::cout << "数据类型: " << tensor.dtype() << "\n"; std::cout << "设备: " << tensor.device() << "\n"; return 0; } ``` #### 2. 数学运算(支持广播机制) ```cpp auto a = torch::ones({2, 3}); // [[1,1,1],[1,1,1]] auto b = torch::arange(1, 4); // [1,2,3] (自动广播到[2,3]) auto c = a * b + 5; // [[6,7,8],[6,7,8]] ``` #### 3. 自动微分(Autograd) ```cpp auto x = torch::ones({2}, torch::requires_grad()); auto y = x * 2 + x.pow(2); // y = 2x + x² auto loss = y.sum(); // loss = Σy loss.backward(); // 自动计算梯度 std::cout << "梯度: " << x.grad(); // dy/dx = 2 + 2x → [4,4] ``` #### 4. 设备切换(CPU/GPU) ```cpp auto cpu_tensor = torch::randn({3,3}); auto gpu_tensor = cpu_tensor.to(torch::kCUDA); // 转移到GPU ``` #### 5. 与Eigen库互操作(可选) ```cpp #include <Eigen/Dense> #include <ATen/Functions.h> // Torch Tensor → Eigen Matrix auto torch_tensor = torch::eye(3); Eigen::MatrixXf eigen_mat = at::tensor(torch_tensor).to(torch::kFloat).matrix<float>(); // Eigen → Torch auto new_tensor = torch::from_blob(eigen_mat.data(), {3,3}); ``` ### 三、关键特性实现原理 1. **动态计算图** 通过`torch::autograd::Function`实现自定义反向传播逻辑。 2. **内存管理** 使用`torch::Tensor`的引用计数机制自动管理内存。 3. **广播机制** 内部实现基于张量形状的自动维度扩展算法: ```cpp auto a = torch::randn({3,1,2}); auto b = torch::randn({4,2}); auto c = a + b; // 自动广播为[3,4,2] ``` 4. **GPU加速** 调用CUDA内核实现并行计算(LibTorch已封装)。 ### 四、编译与运行 ```bash mkdir build && cd build cmake -DCMAKE_PREFIX_PATH=/absolute/path/to/libtorch .. make ./main ``` ### 五、自定义扩展建议 1. **实现新算子** 继承`torch::autograd::Function`并重写`forward()`/`backward()`方法。 2. **优化性能** 使用`torch::TensorAccessor`进行元素级高效访问: ```cpp auto accessor = tensor.accessor<float, 2>(); for (int i=0; i<accessor.size(0); i++) { for (int j=0; j<accessor.size(1); j++) { accessor[i][j] *= 2; } } ``` ### 六、替代方案(无LibTorch依赖) 若需完全独立实现,需构建张量类: ```cpp class Tensor { public: Tensor(std::vector<int> shape) : shape_(shape), strides_(calculate_strides(shape)), data_(calculate_size(shape)) {} // 实现运算符重载 + - * / 等 Tensor operator+(const Tensor& other) { ... } // 实现广播 void broadcast(const std::vector<int>& target_shape) { ... } private: std::vector<int> shape_; std::vector<int> strides_; std::vector<float> data_; }; ``` 但此方案需自行实现自动微分、GPU支持等复杂功能,推荐优先使用LibTorch。 ### 相关问题 1. LibTorch与PyTorch Python API的主要差异有哪些? 2. 如何在C++中实现自定义的自动微分函数? 3. 如何优化LibTorch张量操作的性能? 4. 在嵌入式设备上部署LibTorch有哪些限制? 5. 如何实现TorchScript模型在C++中的推理? > 引用说明: > [^1]: LibTorch通过`torch::Tensor`类提供与Python相似的张量操作接口,隐藏底层实现细节。 > [^2]: 张量属性查看(形状/数据类型/设备)是调试的基础能力。 > [^3]: 自动微分功能通过`torch::autograd`子系统实现。 > [^4]: 广播机制遵循NumPy风格的维度扩展规则。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值