张量(tensor)的广播

博客介绍了使用numpy对张量操作时,不同形状张量间通过广播实现运算。广播目的是将不同形状张量变为相同形状,先对小张量添加轴,再沿新轴重复。同时说明了广播的限制条件,并给出计算过程示例及图片辅助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用numpy 对张量(数组)进行操作时,两个形状相同的张量进行加减等运算很容易理解,那么不同形状的张量之间的运算是通过广播来实现的。广播实际上很简单,但是弄清楚是也花了不小功夫,这里记录一下。

广播的目的是将两个不同形状的张量 变成两个形状相同的张量,即先对小的张量添加轴(使其ndim与较大的张量相同),在把较小的张量沿着新轴重复(使其shape与较大的相同)

广播的的限制条件为:两个张量的 trailing dimension(从后往前算起的维度)的轴长相等 或 其中一个的长度为1

import numpy as np
a=np.arange(0,12)
a=a.reshape(3,4)
b=np.arange(0,4)
print(a)
#[[ 0  1  2  3]
#  [ 4  5  6  7]
# [ 8  9 10 11]]

print(b)
#[0 1 2 3]

print(a.shape)
#(3, 4)

print(b.shape)
#(4,)

print(a.ndim)
#2
print(b.ndim)
#1

a+b          

#array([[ 0,  2,  4,  6],
#       [ 4,  6,  8, 10],
#       [ 8, 10, 12, 14]])  

上述 a+b 的计算过程等价为:

(1)先将b添加一个轴 即

(2)在将b沿着 新加的轴进行重复  

 b.reshape(1,4)
#array([[0, 1, 2, 3]])

c=np.array([b,b,b])
#array([[0, 1, 2, 3],
#      [0, 1, 2, 3],
#      [0, 1, 2, 3]])

a+c

#array([[ 0,  2,  4,  6],
#       [ 4,  6,  8, 10],
#       [ 8, 10, 12, 14]])

 

其他几个例子

x=np.arange(0,12)
x=x.reshape(3,4,1)
x
y=np.arange(0,8)
y=y.reshape(4,2)
y
q=x+y
q.shape
#(3,4,2)
x=np.arange(0,12)
x=x.reshape(3,4,1)
x
z=np.arange(0,2)
z=z.reshape(1,2)
z
q=x+z
q.shape
#(3,4,2)

x  :      y z  x+y    x+z  

 

 

 

最后放上几个图片便于理解

 

转载于:https://www.cnblogs.com/Assist/p/11158028.html

<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提供了与Python版PyTorch类似的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支持哪些张量操作?与Python版PyTorch有何差异? 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风格的维度扩展规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值