当前位置: 首页 > 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;内存是通过…...

deepseek大模型本机部署

2024年1月20日晚&#xff0c;中国DeepSeek发布了最新推理模型DeepSeek-R1&#xff0c;引发广泛关注。这款模型不仅在性能上与OpenAI的GPT-4相媲美&#xff0c;更以开源和创新训练方法&#xff0c;为AI发展带来了新的可能性。 本文讲解如何在本地部署deepseek r1模型。deepseek官…...

动态规划DP 最长上升子序列模型 拦截导弹(题目分析+C++完整代码)

概览检索 动态规划DP 最长上升子序列模型 拦截导弹 原题链接 AcWiing 1010. 拦截导弹 题目描述 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每…...

缩位求和——蓝桥杯

1.题目描述 在电子计算机普及以前&#xff0c;人们经常用一个粗略的方法来验算四则运算是否正确。 比如&#xff1a;248153720248153720 把乘数和被乘数分别逐位求和&#xff0c;如果是多位数再逐位求和&#xff0c;直到是 1 位数&#xff0c;得 24814>145 156 56 而…...

Baklib赋能企业实现高效数字化内容管理提升竞争力

内容概要 在数字经济的浪潮下&#xff0c;企业面临着前所未有的机遇与挑战。随着信息技术的迅猛发展&#xff0c;各行业都在加速推进数字化转型&#xff0c;以保持竞争力。在这个过程中&#xff0c;数字化内容管理成为不可或缺的一环。高效的内容管理不仅能够优化内部流程&…...

【视频+图文讲解】HTML基础2-html骨架与基本语法

图文教程 基本骨架 举个例子&#xff0c;下图所展示的为html的源代码 -!DOCTYPE&#xff1a;表示文档类型&#xff08;后边写的html表示文档类型是html&#xff09;&#xff1b;其中“&#xff01;”表示声明 只要是加这个声明标签的&#xff0c;浏览器就会把下边的源代码当…...

消息队列篇--原理篇--常见消息队列总结(RabbitMQ,Kafka,ActiveMQ,RocketMQ,Pulsar)

1、RabbitMQ 特点&#xff1a; AMQP协议&#xff1a;RabbitMQ是基于AMQP&#xff08;高级消息队列协议&#xff09;构建的&#xff0c;支持多种消息传递模式&#xff0c;如发布/订阅、路由、RPC等。多语言支持&#xff1a;支持多种编程语言的客户端库&#xff0c;包括Java、P…...

【力扣每日一题】存在重复元素 II 解题思路

219. 存在重复元素 II 解题思路 问题描述 给定一个整数数组 nums 和一个整数 k&#xff0c;要求判断数组中是否存在两个 不同的索引 i 和 j&#xff0c;使得&#xff1a; nums[i] nums[j]且满足 abs(i - j) < k 如果满足上述条件&#xff0c;返回 true&#xff0c;否则…...

React第二十八章(css modules)

css modules 什么是 css modules 因为 React 没有Vue的Scoped&#xff0c;但是React又是SPA(单页面应用)&#xff0c;所以需要一种方式来解决css的样式冲突问题&#xff0c;也就是把每个组件的样式做成单独的作用域&#xff0c;实现样式隔离&#xff0c;而css modules就是一种…...

本地运行大模型效果及配置展示

电脑上用ollama安装了qwen2.5:32b&#xff0c;deepseek-r1:32b&#xff0c;deepseek-r1:14b&#xff0c;llama3.1:8b四个模型&#xff0c;都是Q4_K_M量化版。 运行过程中主要是cpu和内存负载比较大&#xff0c;qwen2.5:32b大概需要22g&#xff0c;deepseek-r1&#xff1a;32b类…...

愿景:做机器视觉行业的颠覆者

一个愿景&#xff0c;两场战斗&#xff0c;专注制胜。 一个愿景&#xff1a;做机器视觉行业的颠覆者。 我给自己创业&#xff0c;立一个大的愿景&#xff1a;做机器视觉行业的颠覆者。 两场战斗&#xff1a;无监督-大模型 上半场&#xff0c;无监督。2025-2030&#xff0c;共五…...