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

深度学习编译器的演进:从计算图到跨硬件部署的自动化之路

第一章 问题的诞生——深度学习部署的硬件困境

1.1 计算图的理想化抽象

什么是计算图?

想象你正在组装乐高积木。每个积木块代表一个数学运算(如加法、乘法),积木之间的连接代表数据流动。深度学习框架正是用这种"积木拼接"的方式构建神经网络,这种形式化表达称为计算图(Computational Graph)。

代码解析:一个真实的神经网络

# 导入PyTorch深度学习框架
import torch
import torch.nn as nn# 定义卷积神经网络类(继承自nn.Module基类)
class CNN(nn.Module):def __init__(self):super().__init__()  # 初始化父类# 定义网络层(类似乐高积木的组件)self.conv1 = nn.Conv2d(   # 2D卷积层in_channels=3,        # 输入通道数(RGB图像为3通道)out_channels=64,      # 输出通道数(即卷积核数量)kernel_size=3         # 卷积核尺寸3x3)self.relu = nn.ReLU()     # 激活函数层(使网络具有非线性)self.fc = nn.Linear(      # 全连接层(即Dense层)in_features=512,      # 输入特征维度out_features=10       # 输出类别数(假设是10分类问题))# 定义数据前向传播路径(描述数据如何流过各层)def forward(self, x):x = self.conv1(x)    # 输入数据经过卷积层x = self.relu(x)     # 通过ReLU激活函数x = x.view(x.size(0), -1)  # 展平操作(将4D张量转为2D)x = self.fc(x)       # 通过全连接层return x             # 返回最终输出

对应的数据流图如下(括号内为张量形状):

输入图像(batch,3,224,224)↓
Conv2D层 → 输出(batch,64,222,222) ↓
ReLU激活 → 输出(batch,64,222,222)↓
Flatten展平 → 输出(batch,64*222*222=3175072)↓
Dense全连接 → 输出(batch,10)

关键理解:计算图只描述"要做什么"(What to do),而不关心"如何做"(How to do)。

1.2 硬件现实的多样性挑战

硬件特性对比表(扩展解析)

硬件类型计算单元内存层次结构适合场景
GPU数千个流处理器全局内存(大容量高延迟)+共享缓存(低延迟小容量)并行处理大批量数据
CPU多核(通常4-64核)L1/L2/L3多级缓存(平衡延迟和容量)复杂逻辑控制流
NPU专用矩阵乘法单元片上内存(超低延迟但容量受限)特定神经网络运算加速
FPGA可编程逻辑门阵列分布式Block RAM(灵活但容量小)定制化计算加速

三大核心问题详解

问题1:算子实现差异

以卷积运算为例,不同硬件需要完全不同的实现方式:

GPU实现(CUDA伪代码)

__global__ void conv2d_gpu(float* input, float* kernel, float* output) {int bid = blockIdx.x;  // 批量索引int tid = threadIdx.x; // 线程索引// 每个线程计算输出特征图的一个像素float sum = 0;for(int c=0; c<in_channels; c++){for(int i=0; i<3; i++){for(int j=0; j<3; j++){sum += input[bid][c][tid_x+i][tid_y+j] * kernel[c][i][j];}}}output[bid][tid] = sum;
}

CPU优化实现(C++ SIMD伪代码)

void conv2d_cpu(float* input, float* kernel, float* output) {#pragma omp parallel for // 多核并行for(int b=0; b<batch; b++){for(int c=0; c<channels; c++){__m256 simd_accum; // AVX256向量寄存器for(int i=0; i<height; i+=8){ // 8元素向量处理simd_accum = _mm256_load_ps(&input[b][c][i]);// 向量化乘加运算simd_accum = _mm256_fmadd_ps(simd_accum, kernel_vec, simd_accum);_mm256_store_ps(&output[b][c][i], simd_accum);}}}
}
问题2:内存访问模式冲突

不同硬件对内存访问的敏感性:

  • GPU内存墙:RTX 3090显存带宽936GB/s,但需要连续访问才能达到峰值性能。若数据布局不合理,实际带宽利用率可能不足30%。

    # 不良内存布局(通道最后)
    tensor = torch.randn(224, 224, 3)  # HWC格式
    # GPU更偏好通道优先布局
    tensor = tensor.permute(2, 0, 1)   # CHW格式
    
  • CPU缓存行:现代CPU缓存行通常为64字节。假设处理float32数据(4字节/元素),每次缓存加载可获取16个连续元素。非连续访问会导致缓存频繁失效。

问题3:计算精度陷阱

常见精度问题案例:

# 训练时使用FP32精度
model.train()
output = model(fp32_input)# 部署时误用FP16
model.half()  # 转换为FP16
output = model(fp16_input)  # 可能溢出或精度不足

不同硬件的精度支持差异:

硬件类型FP32支持FP16支持INT8量化
GPU完整TensorCore加速需要特殊指令
NPU部分主要支持专用加速单元
手机SoC有限可选主流方案

1.3 早期解决方案的局限

人工优化库的工作流程

GPU
CPU
算法工程师
编写Python模型
选择目标硬件
调用cuDNN
调用MKL
部署

典型案例:卷积算子的多平台实现

假设需要新增一种Dilated Conv(空洞卷积):

平台开发工作内容耗时估算
NVIDIA GPU编写CUDA内核并优化内存访问3人周
Intel CPU实现AVX512向量化版本2人周
ARM Mali适配OpenCL内核2.5人周
华为NPU转换为AscendCL专用指令3人周

总成本:约10人周(2.5个月),且需持续维护多个代码库。

人工优化的两大缺陷

缺陷1:算子实现碎片化

假设某框架有200个算子,支持5种硬件平台:

总维护量 = 200算子 × 5平台 = 1000个实现版本

当新增一个算子时:

新增工作量 = 1算子 × 5平台 = 5个实现版本

缺陷2:跨算子优化缺失

考虑如下计算图:

Conv → ReLU → Add

人工优化可能得到:

# 三个独立内核
conv_out = cudnn.conv(input)
relu_out = cudnn.relu(conv_out)
output = cudnn.add(relu_out, residual)

而编译器可进行算子融合优化:

# 单个融合内核
output = cudnn.fused_conv_relu_add(input, residual)

优化后的收益:

  • 内核启动开销减少至1/3
  • 中间结果内存占用降低1/2
  • 数据访存次数减少至2/5

小结:编译器为何必须存在?

通过一个现实案例理解必要性:

场景:某公司开发人脸识别系统,需在以下设备部署:

  • 云端:NVIDIA A100 GPU
  • 边缘端:Intel i7-11800H CPU
  • 终端:华为Mate 40手机NPU

传统方式

同一PyTorch模型
为GPU重写cuDNN版本
为CPU优化OpenMP并行
为NPU转换OM模型
三个独立代码库

编译器方式

统一计算图描述
TVM编译器
自动生成GPU代码
自动生成CPU代码
自动生成NPU代码
单一代码库维护

这种自动化转型带来的收益:

  • 开发周期从3个月缩短至2周
  • 硬件利用率平均提升40%
  • 维护成本降低80%

至此我们理解了:为什么需要机器学习编译器,将统一的计算图描述转化为各硬件的高效实现。下一章将深入解析编译器的核心技术。

第二章 技术的演变——编译器架构的进化之路

2.1 第一代:模板化代码生成

2.1.1 Halide的核心思想

Halide将算法描述与调度策略分离,其核心思想可用以下公式表达:
程序 = 算法 + 调度 \text{程序} = \text{算法} + \text{调度} 程序=算法+调度

// 算法定义:3x3均值滤波
Func blur;
Var x, y;  // 定义二维迭代变量
blur(x, y) = (input(x-1, y) + input(x, y) + input(x+1, y)) / 3;// 调度策略配置
blur.tile(x, y, xo, yo, xi, yi, 256, 256)  // 分块:外层循环256x256.vectorize(xi, 8)  // 内层循环向量化,每次处理8个元素.parallel(yo);     // 外层循环并行执行
代码解析
代码片段功能解释优化目标
tile(256, 256)将计算划分为256x256的块提高缓存利用率
vectorize(xi, 8)对内层循环进行8元素向量化利用SIMD指令
parallel(yo)外层循环并行执行多核并行加速

2.1.2 工作流程解析

算法描述
手工编写调度策略
代码生成
目标代码
性能测试案例

对3x3卷积进行不同调度策略的测试:

调度策略执行时间(ms)加速比
基线顺序执行1521.0x
分块+向量化682.24x
分块+向量化+并行236.6x

2.1.3 局限性分析

问题1:策略搜索空间爆炸
假设有5个调度原语(分块、向量化、并行化、循环展开等),每个有3种参数选择:

组合总数 = 3 5 = 243 \text{组合总数} = 3^5 = 243 组合总数=35=243

人工遍历所有组合需要至少243次实验。

问题2:硬件适配困难
同一调度在不同硬件的表现:

硬件平台最佳分块尺寸向量化宽度
Intel i7128x1288
ARM A7264x644
NVIDIA P100256x25616

问题3:跨算子优化缺失

// 两个独立算子
Func conv = ...;
Func relu = ...;// 无法进行融合优化
conv.compute_root();
relu.compute_root();

2.2 第二代:基于中间表示的优化

2.2.1 TVM的多级IR体系

图优化
算子拆分
调度优化
代码生成
Relay IR
优化后的Relay IR
TE表达式
TIR
目标代码
关键IR解析
IR层级抽象级别主要功能
Relay IR计算图级全局优化、算子融合
TE张量运算级算子实现定义
TIR低级循环优化硬件特定优化

2.2.2 Relay优化实例

原始计算图:

def original():conv = relay.nn.conv2d(x, w1)relu = relay.nn.relu(conv)bn = relay.nn.batch_norm(relu)pool = relay.nn.max_pool2d(bn)return pool

优化过程:

# 应用优化规则序列
with relay.transform.PassContext(opt_level=3):mod = relay.transform.Sequential([relay.transform.FoldConstant(),relay.transform.FuseOps(fuse_opt_level=2),relay.transform.AlterOpLayout()])(mod)

优化后计算图:

FusedConvReLUBN → MaxPool2D
优化效果对比
优化阶段算子数量内存占用(MB)执行时间(ms)
原始计算图41.215.3
常量折叠31.114.7
算子融合20.911.2
布局转换20.89.1

2.2.3 TE调度系统

矩阵乘法优化示例:

def te_matmul(A, B):m, k = A.shapek, n = B.shaperc = te.reduce_axis((0, k))return te.compute((m, n), lambda i, j: te.sum(A[i, rc] * B[rc, j], axis=rc))s = te.create_schedule(matmul.op)# 分块策略
xo, xi = s[matmul].split(matmul.op.axis[0], factor=32)
yo, yi = s[matmul].split(matmul.op.axis[1], factor=32)# 循环重排序
s[matmul].reorder(xo, yo, xi, yi)# 线程绑定
s[matmul].bind(xo, te.thread_axis("blockIdx.x"))
s[matmul].bind(yo, te.thread_axis("blockIdx.y"))
s[matmul].bind(xi, te.thread_axis("threadIdx.x"))# 生成CUDA代码
target = tvm.target.Target("cuda")
mod = tvm.build(s, [A, B, matmul], target)
调度策略影响
优化策略执行时间(ms)加速比
基线顺序12.51.0x
分块+重排序5.32.36x
线程绑定2.15.9x

2.3 混合式调度系统

2.3.1 MLIR基础设施解析

MLIR采用模块化的方言(Dialect)设计,核心架构如下:

在这里插入图片描述

前端语言 → 高层方言(如TensorFlow Graph) ↓ 渐进式Lowering
中间方言(如Affine Dialect) ↓
底层方言(如LLVM IR) ↓
硬件指令
关键机制详解
  1. 可扩展方言体系

    // TensorFlow Lite方言示例
    func @main(%input: tensor<1x224x224x3xf32>) -> tensor<1x1000xf32> {%0 = "tfl.conv_2d"(%input, %filter, %bias) {...} : (tensor<1x224x224x3xf32>, ...) -> tensor<1x112x112x64xf32>%1 = "tfl.relu"(%0) : (...) -> tensor<1x112x112x64xf32>return %1 : tensor<1x1000xf32>
    }
    
  2. 渐进式Lowering过程

    高层操作 → 循环嵌套 → 向量指令 → 硬件指令
    
  3. 多级IR共存机制

    module {func @mixed_ir(%arg: tensor<f32>) -> tensor<f32> {// 高层操作%0 = "tfl.custom_op"(%arg) : (...) -> tensor<f32>// 底层循环结构affine.for %i = 0 to 100 {%1 = load %0[%i] : memref<100xf32>%2 = "llvm.intr.fmul"(%1, %1) : (...) -> f32store %2, %0[%i] : memref<100xf32>}return %0 : tensor<f32>}
    }
    

2.3.2 架构对比分析

特性HalideTVMMLIR
优化抽象层次循环级计算图+循环级全层次
硬件扩展性需重写调度策略新增目标后端定义新方言
跨优化阶段集成有限原生支持
自动优化能力基于搜索基于规则+搜索

MLIR创新点

  1. 统一编译基础设施:支持从算法到硬件的全栈表达
  2. 方言可组合性:不同抽象层次的IR可以共存交互
  3. 形式化语义:每个方言都有严格定义的Operation和Type系统

第三章 解决方案的实现——TVM编译器的技术剖析

3.1 计算图优化阶段:全局视野的优化艺术

3.1.1 优化规则分类

TVM的计算图优化器包含四大类优化策略:

# 优化器配置示例
seq = tvm.transform.Sequential([# 基本优化relay.transform.EliminateCommonSubexpr(),relay.transform.FoldConstant(),# 算子级优化relay.transform.FuseOps(fuse_opt_level=2),relay.transform.CombineParallelDense(min_num_branches=3),# 内存优化relay.transform.AlterOpLayout(),relay.transform.CanonicalizeCast(),# 硬件特定优化relay.transform.ConvertLayout({"nn.conv2d": ["NHWC", "default"]})
])
典型优化案例:算子融合

原始计算图:

Conv2D → ReLU → BatchNorm → MaxPool2D

优化过程:

# 应用融合规则
mod = relay.transform.FuseOps(fuse_opt_level=3)(mod)

优化后计算图:

FusedConv2D_ReLU_BN → MaxPool2D

3.1.2 优化效果量化分析

在ResNet-50上的优化效果:

优化策略算子数量内存占用(MB)推理时延(ms)
无优化2171245152.3
常量折叠2031128144.7
算子融合98876112.4
布局转换9883297.6

3.2 张量表达式系统:硬件无关的算子定义

3.2.1 表达式定义范式

卷积算子的完整定义示例:

def conv2d_nchw(data, kernel, stride, padding):"""NCHW布局的卷积计算定义Args:data: 输入张量,形状[N,C,H,W]kernel: 卷积核,形状[O,C,Kh,Kw]stride: 步长padding: 填充"""N, C, H, W = data.shapeO, _, Kh, Kw = kernel.shape# 计算输出尺寸out_h = (H + 2*padding - Kh) // stride + 1out_w = (W + 2*padding - Kw) // stride + 1# 定义规约轴rc = te.reduce_axis((0, C), name="rc")rh = te.reduce_axis((0, Kh), name="rh")rw = te.reduce_axis((0, Kw), name="rw")# 填充计算padded = te.compute((N, C, H+2*padding, W+2*padding),lambda n, c, h, w: te.if_then_else(te.any(h < padding, h >= H+padding, w < padding, w >= W+padding),0.0,data[n, c, h-padding, w-padding]),name="padded")# 卷积计算return te.compute((N, O, out_h, out_w),lambda n, o, h, w: te.sum(padded[n, rc, h*stride + rh, w*stride + rw] * kernel[o, rc, rh, rw],axis=[rc, rh, rw]),name="conv2d")

3.2.2 自动微分实现

TVM支持自动微分功能:

# 定义计算
x = te.var("x")
y = te.var("y")
z = te.sin(x) * te.log(y)# 创建微分计算
[dz_dx, dz_dy] = te.differentiate(z, [x, y])# 生成计算代码
s = te.create_schedule([dz_dx.op, dz_dy.op])

微分结果:
∂ z ∂ x = cos ⁡ ( x ) ⋅ ln ⁡ ( y ) ∂ z ∂ y = sin ⁡ ( x ) y \frac{\partial z}{\partial x} = \cos(x) \cdot \ln(y) \\ \frac{\partial z}{\partial y} = \frac{\sin(x)}{y} xz=cos(x)ln(y)yz=ysin(x)

3.3 调度优化原语:性能调优的武器库

3.3.1 核心调度原语分类

类别原语示例优化目标
循环变换split, reorder, tile数据局部性优化
并行化parallel, vectorize多级并行加速
内存管理cache_read, double_buffer减少内存访问延迟
硬件适配bind, storage_align硬件特性匹配

3.3.2 矩阵乘法的完整优化

def optimize_matmul(s, C):"""矩阵乘法调度优化"""# 分块策略x, y = s[C].op.axisxo, xi = s[C].split(x, factor=32)yo, yi = s[C].split(y, factor=32)s[C].reorder(xo, yo, xi, yi)# 缓存写入优化CC = s.cache_write(C, "local")# 自动线程绑定s[C].bind(xo, te.thread_axis("blockIdx.x"))s[C].bind(yo, te.thread_axis("blockIdx.y"))s[C].bind(xi, te.thread_axis("threadIdx.x"))s[C].bind(yi, te.thread_axis("threadIdx.y"))# 向量化优化s[CC].vectorize(CC.op.axis[-1])# 循环展开ko, ki = s[CC].split(s[CC].op.reduce_axis[0], factor=4)s[CC].unroll(ki)

3.3.3 优化效果对比

在1024x1024矩阵乘法上的测试结果:

优化阶段执行时间(ms)GFLOPS加速比
基线实现12.5172.31.0x
分块+重排序5.3406.72.36x
线程绑定2.11024.85.95x
向量化+展开1.41536.08.93x

3.4 自动调优系统:机器学习的魔法

3.4.1 AutoTVM架构设计

搜索空间定义
特征提取
成本模型
参数生成
硬件测量
性能评估
组件详解:
  • 搜索空间定义:描述可调节的调度参数

    cfg = autotvm.get_config()
    cfg.define_knob("tile_size", [32, 64, 128])
    cfg.define_knob("vectorize", [4, 8, 16])
    
  • 成本模型:XGBoost预测性能
    y ^ = ∑ i = 1 n f i ( x ) , f i ∈ F \hat{y} = \sum_{i=1}^n f_i(x), \quad f_i \in \mathcal{F} y^=i=1nfi(x),fiF

  • 参数搜索:采用并行贝叶斯优化
    x n e x t = arg ⁡ max ⁡ x UCB ( x ) = μ ( x ) + κ σ ( x ) x_{next} = \arg\max_x \text{UCB}(x) = \mu(x) + \kappa \sigma(x) xnext=argxmaxUCB(x)=μ(x)+κσ(x)

3.4.2 调优收敛过程

  1. 随机采样阶段:探索全局空间
  2. 模型引导阶段:快速逼近最优
  3. 局部优化阶段:精细调整参数

3.4.3 实际调优案例

在NVIDIA T4 GPU上调优ResNet-50:

阶段时间消耗最佳时延(ms)加速比
初始实现015.21.0x
随机搜索100次2h9.81.55x
贝叶斯优化300次6h6.72.27x
专家手动优化40h6.52.34x

3.4.4 技术实现总结

TVM通过分层优化体系实现自动化编译:

计算图优化
全局内存优化
算子融合
张量表达式
调度优化
自动调优
高性能代码

关键创新点

  1. 跨层优化:在不同抽象层级实施针对性优化
  2. 可组合性:调度原语可任意组合产生新策略
  3. 可移植性:同一优化策略适配多硬件后端

实验数据显示,TVM在典型工作负载上可获得:

  • 相比手工优化库90%以上的性能
  • 比原生框架3-10倍的加速比
  • 跨硬件平台的一致优化效果

这种技术突破使得深度学习模型可以真正实现"一次开发,处处高效运行"。下一章将通过实际部署案例,展示TVM在不同场景中的实践效果。


第四部分:实践验证——跨硬件平台的性能对比

4.1 GPU平台测试

在NVIDIA T4上的ResNet-50推理:

方法时延(ms)内存使用(MB)功耗(W)
PyTorch原生15.2120372
TVM自动优化6.887465
手工CUDA实现6.583263

4.2 CPU平台测试

Intel Xeon Gold 6248上的BERT推理:

优化方法吞吐量(qps)时延(ms)加速比
ONNX Runtime7812.81.0x
TVM自动调优1427.041.82x
手工AVX512优化1556.451.99x

4.3 边缘设备测试

树莓派4B上的MobileNetV2:

部署方式时延(ms)内存峰值(MB)能耗(J)
TFLite143825.3
TVM+AutoTVM97643.8
手工NEON优化89583.5

第五部分:技术演进——编译器架构的未来方向

5.1 动态形状支持

传统静态编译与动态编译对比:

静态编译时间 = O ( 1 ) 动态编译开销 = O ( n ) \text{静态编译时间} = O(1) \\ \text{动态编译开销} = O(n) 静态编译时间=O(1)动态编译开销=O(n)

TVM的动态shape处理:

def dynamic_conv(data, weight):N = te.var("n")C = te.var("c")H = te.var("h")W = te.var("w")rc = te.reduce_axis((0, C))return te.compute((N, K, H-R+1, W-S+1),lambda n, k, h, w: te.sum(data[n, rc, h+rh, w+rw] * weight[k, rc, rh, rw],axis=[rc, rh, rw]))

5.2 异构计算协同

跨设备计算示例:

# GPU执行卷积
with tvm.target.cuda():conv_module = tvm.build(conv_sch, [data, weight, conv_out])# NPU执行全连接
with tvm.target.ascend():fc_module = tvm.build(fc_sch, [conv_out, fc_weight, output])# 数据流水线
gpu_stream = tvm.runtime.DeviceAPI.get_stream(0)
npudata = conv_module(data, weight)
gpu_stream.sync()
npuresult = fc_module(npudata)

5.3 自动化程度提升

未来编译器架构展望:

不达标
达标
计算图
自动算子切分
自动调度优化
自动代码生成
性能验证
部署

相关文章:

深度学习编译器的演进:从计算图到跨硬件部署的自动化之路

第一章 问题的诞生——深度学习部署的硬件困境 1.1 计算图的理想化抽象 什么是计算图&#xff1f; 想象你正在组装乐高积木。每个积木块代表一个数学运算&#xff08;如加法、乘法&#xff09;&#xff0c;积木之间的连接代表数据流动。深度学习框架正是用这种"积木拼接…...

【数据结构】_顺序表经典算法OJ(力扣版)

目录 1. 移除元素 1.1 题目描述及链接 1.2 解题思路 1.3 程序 2. 合并两个有序数组 1.1 原题链接及题目描述 1.2 解题思路 1.3 程序 1. 移除元素 1.1 题目描述及链接 原题链接&#xff1a;27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a…...

数据结构:队列篇

图均为手绘,代码基于vs2022实现 系列文章目录 数据结构初探: 顺序表 数据结构初探:链表之单链表篇 数据结构初探:链表之双向链表篇 链表特别篇:链表经典算法问题 数据结构:栈篇 文章目录 系列文章目录前言一.队列的概念和结构1.1概念一、动态内存管理优势二、操作效率与安全性…...

第05章 17 Contour 过滤器介绍与例子

vtkContourFilter 是 VTK&#xff08;Visualization Toolkit&#xff09;中的一个关键类&#xff0c;用于从输入数据生成等值线或等值面。它是基于阈值的过滤器&#xff0c;可以从标量字段中提取等值线或等值面。vtkContourFilter 的核心功能是根据用户指定的值生成等值线或等值…...

【落羽的落羽 数据结构篇】顺序表

文章目录 一、线性表二、顺序表1. 概念与分类2. 准备工作3. 静态顺序表4. 动态顺序表4.1 定义顺序表结构4.2 顺序表的初始化4.3 检查空间是否足够4.3 尾部插入数据4.4 头部插入数据4.5 尾部删除数据4.6 头部删除数据4.7 在指定位置插入数据4.8 在指定位置删除数据4.9 顺序表的销…...

AI编程:如何编写提示词

这是小卷对AI编程工具学习的第2篇文章&#xff0c;今天讲讲如何编写AI编程的提示词&#xff0c;并结合实际功能需求案例来进行开发 1.编写提示词的技巧 好的提示词应该是&#xff1a;目标清晰明确&#xff0c;具有针对性&#xff0c;能引导模型理解问题 下面是两条提示词的对…...

DeepSeek-R1 论文解读 —— 强化学习大语言模型新时代来临?

近年来&#xff0c;人工智能&#xff08;AI&#xff09;领域发展迅猛&#xff0c;大语言模型&#xff08;LLMs&#xff09;为通用人工智能&#xff08;AGI&#xff09;的发展开辟了道路。OpenAI 的 o1 模型表现非凡&#xff0c;它引入的创新性推理时缩放技术显著提升了推理能力…...

高阶C语言|深入理解字符串函数和内存函数

文章目录 前言1.求字符串长度1.1 字符串长度函数&#xff1a;strlen模拟实现 2.长度不受限制的字符串函数2.1 字符串拷贝函数&#xff1a;strcpy模拟实现 2.2 字符串连接函数&#xff1a;strcat模拟实现 2.3 字符串比较函数&#xff1a;strcmp模拟实现 3.长度受限制的字符串函数…...

UE学习日志#17 C++笔记#3 基础复习3

19.2 [[maybe_unused]] 禁止编译器在未使用某些内容时发出警告 19.3 [[noreturn]] 永远不会把控制权返回给调用点 19.4 [[deprecated]] 标记为已弃用&#xff0c;仍然可以使用但是不鼓励使用 可以加参数表示弃用的原因[[deprecated("")]] 19.5 [[likely]]和[[un…...

团体程序设计天梯赛-练习集——L1-028 判断素数

前言 一道10分的题目&#xff0c;相对来说比较简单&#xff0c;思考的时候要仔细且活跃&#xff0c;有时候在写代码的时候一些代码的出现很多余&#xff0c;并且会影响最后的结果 L1-028 判断素数 本题的目标很简单&#xff0c;就是判断一个给定的正整数是否素数。 输入格式…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(基础图形库实现)

目录 基础图形库的抽象 抽象图形 抽象点 设计我们的抽象 实现我们的抽象 测试 抽象线 设计我们的抽象 实现我们的抽象 绘制垂直的和水平的线 使用Bresenham算法完成任意斜率的绘制 绘制三角形和矩形 矩形 三角形 实现 绘制圆&#xff0c;圆弧和椭圆 继续我们的…...

创新创业计划书|建筑垃圾资源化回收

目录 第1部分 公司概况........................................................................ 1 第2部分 产品/服务...................................................................... 3 第3部分 研究与开发.................................................…...

反射、枚举以及lambda表达式

一.反射 1.概念&#xff1a;Java的反射&#xff08;reflection&#xff09;机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff0c;既然能拿到那么&am…...

ROS应用之IMU碰撞检测与接触事件识别

前言 碰撞检测与接触事件识别是机器人与环境交互中的重要任务&#xff0c;尤其是在复杂的动态环境中。IMU&#xff08;惯性测量单元&#xff09;作为一种高频率、低延迟的传感器&#xff0c;因其能够检测加速度、角速度等动态变化而成为实现碰撞检测的核心手段之一。结合先进的…...

docker安装MySQL8:docker离线安装MySQL、docker在线安装MySQL、MySQL镜像下载、MySQL配置、MySQL命令

一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令 docker pull mysql:8.0.41 2、离线包下载 两种方式&#xff1a; 方式一&#xff1a; -&#xff09;在一台能连外网的linux上安装docker执行第一步的命令下载镜像 -&#xff09;导出 # 导出镜…...

android安卓用Rime

之前 [1] 在 iOS 配置用上自改方案 [2]&#xff0c;现想在安卓也用上。Rime 主页推荐了两个安卓平台支持 rime 的输入法 [3]&#xff1a; 同文 Tongwen Rime Input Method Editor&#xff0c;但在我的 Realme X2 Pro 上似乎有 bug&#xff1a;弹出的虚拟键盘只有几个 switcher…...

每日一博 - 三高系统架构设计:高性能、高并发、高可用性解析

文章目录 引言一、高性能篇1.1 高性能的核心意义 1.2 影响系统性能的因素1.3 高性能优化方法论1.3.1 读优化&#xff1a;缓存与数据库的结合1.3.2 写优化&#xff1a;异步化处理 1.4 高性能优化实践1.4.1 本地缓存 vs 分布式缓存1.4.2 数据库优化 二、高并发篇2.1 高并发的核心…...

C++ 中的引用(Reference)

在 C 中&#xff0c;引用&#xff08;Reference&#xff09;是一种特殊的变量类型&#xff0c;它提供了一个已存在变量的别名。引用在很多场景下都非常有用&#xff0c;比如函数参数传递、返回值等。下面将详细介绍 C 引用的相关知识。 1. 引用的基本概念和语法 引用是已存在…...

负荷预测算法模型

1. 时间序列分析方法 时间序列分析方法是最早被用来进行电力负荷预测的方法之一&#xff0c;它基于历史数据来构建数学模型&#xff0c;以描述时间与负荷值之间的关系。这种方法通常只考虑时间变量&#xff0c;不需要大量的输入数据&#xff0c;因此计算速度快。然而&#xff…...

【C语言】内存管理

【C语言】内存管理 文章目录 【C语言】内存管理1.概念2.库函数3.动态分配内存malloccalloc 4.重新调整内存的大小和释放内存reallocfree 1.概念 C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。 在 C 语言中&#xff0c;内存是通过…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)

目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 ​编辑​编辑 UDP的特征 socke函数 bind函数 recvfrom函数&#xff08;接收函数&#xff09; sendto函数&#xff08;发送函数&#xff09; 五、网络编程之 UDP 用…...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法

使用 ROS1-Noetic 和 mavros v1.20.1&#xff0c; 携带经纬度海拔的话题主要有三个&#xff1a; /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码&#xff0c;来分析他们的发布过程。发现前两个话题都对应了同一…...