DeepGEMM实践:为深度学习定制高性能矩阵乘法内核
1. 为什么我为一个“老掉牙”的矩阵乘法写了个专用库如果说有哪种计算十年前只待在HPC论文里今天却撑起了整个深度学习软件栈的底层那非矩阵乘莫属。线性层是矩阵乘注意力打分是矩阵乘卷积用im2col变换后还是矩阵乘。你训练一个Transformer、跑一次推理、做一次微调底层几千上万个算子同时在干的其实是同一件事算GEMM。DeepGEMM这个名字听着唬人拆开看就是Deep Learning GEMM。我最早做这个项目的动机特别朴素某次跑模型时发现GPU利用率忽高忽低profiler里大量时间被卡在矩阵乘法相关的kernel上。厂商自带的BLAS库已经很快了但针对特定形状、特定精度、特定硬件做定制化优化时通用库总有那么点“不够聪明”的别扭劲。于是我做了一个专门为深度学习场景优化的GEMM计算内核和配套调度方案顺便把整个调优思路完整踩了一遍。这篇文章就是这次实践的完整记录。如果你刚接触高性能计算这篇内容可以帮你理解GEMM为什么难、怎么优化、怎么排查如果你已经在写kernel这篇文章能提供一套可以直接拿去用的参考实现、参数范围和避坑清单。总之这不是一篇泛泛讲“矩阵乘法很重要”的科普而是一篇按真实项目流程走下来的实操笔记。1.1 模型训练变慢瓶颈往往在矩阵乘我们习惯把深度学习性能问题归咎于框架调度、Python开销或显存带宽但真实profiling样本里绝大多数训练step的时间消耗在少数几个GEMM kernel上。例如一个标准的Transformer层包含多个线性映射和注意力得分计算这些操作本质上都是对某个三维张量做批量矩阵乘。我之前在某个项目中遇到这样一个现象模型结构本身不大但每次step时间明显超过理论估算。一开始怀疑是数据加载慢查了半天发现数据管道很健康后来怀疑是算子融合不到位结果发现框架已经做了不少融合最后打开kernel级profiling才看到罪魁祸首是某个特定形状的矩阵乘kernel整体利用率不到30%。通用库的kernel是为“平均情况”设计的它会尽量覆盖各种形状、各种对齐、各种精度组合但针对具体场景它的分块尺寸、线程映射、流水线深度未必是最优的。DeepGEMM的思路就是在这种背景下确立的不做覆盖所有情况的万能库而是针对深度学习中最常见的那一类矩阵乘形状和精度把每一份算力都榨干。1.2 DeepGEMM 到底解决什么问题先明确应用场景。深度学习里的矩阵乘有三个显著特征一是M、N、K三个维度经常不是整齐的倍数带padding的、非对齐的形状特别多二是精度需求灵活训练常用BF16混合精度推理可能用FP16或INT8不同精度对硬件指令的利用方式完全不同三是调用频率极高一个batch训练可能包含几十上百次GEMM哪怕单次只提升5%累积收益也相当可观。DeepGEMM瞄准的目标非常具体在一块典型的现代GPU上针对FP16/BF16输入、FP32累加的混合精度矩阵乘在没有厂商闭源黑魔法的情况下通过合理分块和指令级优化把算力利用率推到80%以上。同时代码要足够清晰让人能看懂每个优化步骤的意图而不是一个神秘的黑盒。我见过太多性能优化项目最后陷入“为了优化而优化”的境地代码改得又臭又长性能却只涨了几个百分点。DeepGEMM的边界设定从一开始就很明确只做必要优化不追求极限玄学让每个改动背后都有数据支撑。2. 先算清楚GEMM 为什么慢瓶颈到底在哪很多人以为GEMM慢是因为计算量大这句话只对了一半。计算量大是事实但现代GPU的峰值算力非常恐怖真正让你跑不到峰值的原因往往是数据喂不饱计算单元。这个问题不先想清楚后续所有调优都是瞎忙。2.1 拆解一次矩阵乘算力与访存的赛跑矩阵乘CM×N的每个输出元素是A矩阵一行和B矩阵一列的点积。如果按照最朴素的方式把A中的每个元素读出来乘以B中对应元素再累加那么每个浮点运算几乎都伴随一次全局内存访问。全局内存带宽和计算单元的吞吐差距有多大呢以一张常见的加速卡为例峰值算力每秒可以完成数百万亿次浮点运算而显存带宽每秒只能搬运数TB数据。如果每次运算都依赖全局内存计算单元大部分时间都会空转等数据。这里有个关键指标叫“计算强度”即每字节数据搬运能支撑多少次浮点运算。只有当计算强度高于硬件本身的平衡点时计算单元才能跑满。GEMM的优化本质上就是不断提高这个强度让每个从显存搬进来的数据被反复使用更多次。我把这个过程类比成一个后厨场景厨师计算单元处理食材的速度极快但食材放在很远的大仓库全局内存每次取菜都要跑很远。如果每次炒菜需要什么就去仓库拿什么大部分时间都浪费在路上。聪明的做法是一次搬一筐菜放到灶台边的备菜台共享内存甚至直接在手里寄存器处理多个菜的工序。2.2 内存带宽与计算强度的关系GEMM的计算强度可以通过分块来量化。假设我们把A矩阵分成BM行、BK列的小块B矩阵分成BK行、BN列的小块那么这两个小块分别从全局内存加载一次就能计算出BM×BN个输出元素。此时总共搬入的数据量是BM×BK BK×BN个元素计算量是2×BM×BN×BK次浮点运算计算强度就是两者的比值。从公式可以看出BM和BN越大、BK越小计算强度越高。乍一看无限增大BM和BN就完事了可惜硬件不答应。共享内存容量有限寄存器数量有限线程块调度也有限制所以分块必须在硬件资源约束下寻找最优解。这也是GEMM优化的核心主线之一。2.3 精度选择FP16/BF16 和 Tensor Core 的机会深度学习常用的两种半精度格式让我在性能上有可观的增益FP16精度范围较小但数值密度高BF16的精度范围回到FP32水平但尾数位少。硬件设计上还有一个大杀器叫tensor core它在单个指令周期内能完成4×4甚至更大的矩阵乘累加操作吞吐量远超普通CUDA核心。但要触发这个能力数据格式、存储布局都有严格要求。DeepGEMM一开始就把精度路径定为FP16/BF16输入、FP32中间累加因为这个组合在深度学习训练中最常见。使用tensor core时数据通常需要满足特定对齐要求不够对齐的形状还得考虑padding策略。这些不是“锦上添花”的优化很多加速卡的混合精度算力上限就体现在这里不用tensor core的话这辈子都跑不满峰值。3. DeepGEMM 核心设计分块、流水、算力榨干理解了瓶颈之后DeepGEMM的架构设计就顺理成章了优先解决数据搬运问题再解决指令效率问题。整个内核设计的核心可以用三句话概括分块让数据局部化、流水线让搬运和计算重叠、tensor core让单次指令干更多活。3.1 分块策略让数据飞起来先说分块。我最终选择的主分块尺寸是128×128即每个线程块负责计算输出矩阵中128行、128列的一个区域。K维方向的子块尺寸设为16或32根据精度和硬件tensor core能力动态调整。为什么不是64×64或256×256太小的话计算强度不够数据搬运开销占比太高太大的话共享内存放不下那么多分块数据还会让一个线程块占用的资源过多降低并发度。这里有一个平衡点需要在实际设备上验证。我实测过在不同GPU上128×128配合K方向16或32的分块整体性能和资源占用最均衡。如果共享内存充裕且寄存器压力可控可以尝试更大的128×256但收益未必正比于体量增长因为更大的分块会导致线程块内同步次数增加和调度灵活性下降。分块确定后线程映射也顺理成章。我把线程块内部的128×128输出区域按8×8的微块划分每个线程负责8×864个输出元素这样4×4的tensor core指令正好完成一次微块的计算。线程数控制在256个既能保持足够的并行度又不会过多占用寄存器资源。3.2 共享内存与寄存器级的双重缓存数据从全局内存到计算单元中间要经过共享内存和寄存器两道“缓存”。朴素实现是从全局内存直接读数据慢改进版本先进共享内存快了一些终极版本是数据在共享内存和寄存器之间流水式流动让加载和计算同时进行。DeepGEMM在共享内存中为A和B各分配了两个缓冲区这就是经典的双缓冲模式。计算线程正在用缓冲区0的数据做矩阵乘时加载线程已经同步把下一批数据搬进缓冲区1。等这一轮计算结束互换角色缓冲区1的数据开始参与计算缓冲区0继续加载后续数据。这样做的好处是数据加载的延迟被计算过程完全遮盖内核的主循环变成了流水线式的“加载-计算-加载-计算”。寄存器级缓存同样重要。每个线程计算8×8的输出微块时需要把A的某个子向量和B的某个子向量留在寄存器里反复使用避免每次都去共享内存里取。寄存器访问速度虽然比共享内存快但毕竟是有限的资源分配不当就会出现寄存器溢出数据被挤到本地内存性能悬崖式下跌。3.3 Tensor Core 调用与布局转换要触发tensor core最关键的是数据布局。以常见的16×16×16矩阵乘指令为例A矩阵的一个16×16分块需要以特定ldmatrix模式加载到线程束寄存器中。如果原始数据的内存布局不符合要求要么做一次共享内存内的转置要么在全局内存加载时通过向量化读取配合共享内存swizzle操作完成布局重排。这里我踩过一个经典的坑直接把原始的row-major数据塞进tensor core结果指令根本没触发性能还不如普通CUDA核心算得快。原因是布局不满足硬件要求驱动会走fallback路径。正确做法是在共享内存中完成“读A转置、读B转置”的预处理写回时再用向量化stmatrix指令一次性写出一整块结果。布局转换听起来繁琐但它换来的是每次tensor core调用能完成远超普通的计算量。用生活类比解释的话普通CUDA核心相当于一个人一次拿一个箱子tensor core相当于开了一辆卡车一次拉一集装箱但前提是货物必须按特定方式码放整齐。布局转换就是码放货物的时间花得值。4. 实操从零实现一个高效的 GEMM Kernel这一节进入正题。我基于CUDA实现了一版可直接参考的GEMM内核骨架代码结构清晰注释对应上文的每一处设计决策。需要注意这里的代码以逻辑演示为主实际跑分还需要根据你的设备微调分块参数。4.1 Kernel 骨架与线程映射#define BM 128 #define BN 128 #define BK 32 #define TM 8 #define TN 8 #define THREADS 256 __global__ void deepgemm_kernel( const half* __restrict__ A, const half* __restrict__ B, float* __restrict__ C, int M, int N, int K) { // 当前线程块负责的输出宏块起始位置 int blockRow blockIdx.y * BM; int blockCol blockIdx.x * BN; // 共享内存缓冲区A分块和B分块各两个双缓冲 __shared__ half As[2][BM][BK]; __shared__ half Bs[2][BK][BN]; // 线程编号 int tid threadIdx.x; // 累加器每个线程负责 TM*TN 个输出元素 float acc[TM][TN] {0.f}; // 共享内存加载索引线程协作拷贝到共享内存 int loadRow tid / (BK / 2); int loadCol tid % (BK / 2) * 2; ... }注意上面这段代码省略了加载细节和主循环。线程映射的思路是256个线程协同把A的128×32分块和B的32×128分块搬进共享内存每个线程负责搬多个元素通过向量化读取提升带宽利用率。主循环的核心逻辑是从全局内存加载A和B的下一批数据到双缓冲区的下一侧在上一侧的数据上执行tensor core计算。这个“计算当前、加载后续”的重叠就是上一节说的流水线。4.2 双缓冲与异步 copyCUDA提供了异步拷贝指令可以在不经过寄存器的情况下把全局内存数据直接搬到共享内存。我在代码里用这个指令实现了真正的异步加载让数据搬运不再占据线程的计算时间。伪代码逻辑大致如下for (int k 0; k K; k BK) { // 异步加载下一块 A 和 B 到缓冲区 buffer_idx^1 cp_async(As[buffer_idx ^ 1], A global_offset_a); cp_async(Bs[buffer_idx ^ 1], B global_offset_b); cp_async_commit(); // 提交异步拷贝组 // 等待当前缓冲区数据就绪 cp_async_wait_group(1); // 使用缓冲区 buffer_idx 执行 tensor core 计算 compute_tile(As[buffer_idx], Bs[buffer_idx], acc); __syncthreads(); buffer_idx ^ 1; // 切换缓冲区角色 }这里有个细节cp_async_wait_group(1)表示等待还剩1组异步拷贝未完成时继续。因为这一轮计算用的是buffer_idx而下一轮数据正在加载到buffer_idx^1所以只需要确保提交的异步操作不超过1组未完成就能实现安全的重叠。4.3 调优参数速查不同硬件的tensor core规格、共享内存大小、寄存器数量都有差异参数不能照抄。我整理了一份速查表给出了常见情况的参数范围和使用建议参数常见范围说明BM × BN128×128、128×256输出宏块越大计算强度越高但占用共享内存和寄存器越多BK16、32、64太小导致计算强度不足太大导致共享内存K方向占用过高TM × TN8×8、4×8、8×4每线程输出元素数与tensor core指令对齐有关线程数128、256、512平衡并行度和资源占用一般256比较均衡双缓冲1、22是标配追求极限可以上多级buffer选择参数时不要一次性全改一次只调一个变量观察性能曲线的变化方向。我试过同时调BM和BK结果性能诡异下跌后来拆开分析才发现是共享内存溢出触发了局部内存回退单个参数怎么看都有问题。5. 实测效果从 profiling 到提速理论设计再漂亮最后还是得用数据说话。这一节记录DeepGEMM的实测结果和评估方法方便你复现时对照。5.1 测试环境与方法测试环境为某型号数据中心级GPU搭配CUDA工具链输入尺寸覆盖了三种典型场景小矩阵128×128、中等矩阵512×512、大矩阵2048×2048K维度固定为1024。精度配置为FP16输入、FP32累加。测试方法上我特别注意两点一是多次运行取中位数而不是平均值避免偶发频率波动和调度噪声干扰二是每次测量前做预热确保GPU进入稳定工作状态。数据全程使用同一批随机输入保证可比性。5.2 数据比对直接看结果。以2048×2048×2048的大矩阵为例基线版本朴素实现每个线程直接读写全局内存测得的算力利用率只有约12%。加入共享内存分块后提升到35%左右。加入双缓冲流水线后进一步提升到55%。最后启用tensor core并完成布局转换利用率跳到了80%以上。从12%到80%七倍左右的差距靠的不是某一项黑魔法而是四层优化逐级叠加的结果。每一层优化的收益都不一样分块带来的收益最大流水线和tensor core各贡献了可观的增量。小矩阵场景的情况更有意思。128×128的矩阵规模较小固定开销比如kernel启动、线程初始化、同步操作占总时间的比例更高。朴素实现和优化实现之间的差距反而缩小了因为硬件本身就能在这么小的规模上快速完成计算。这提醒我一个重要结论优化不是无脑套模板要先看规模再定策略。6. 踩坑与排查共享内存不够、数值漂移、性能上不去写kernel的过程中我几乎把常见性能陷阱踩了个遍。每次踩坑后都花了不少时间排查回头整理出来至少能帮你省下几周弯路。6.1 共享内存与寄存器超限问题共享内存超限是最容易遇到的问题。BM、BN、BK越大分块数据占用的共享内存越多。某次我把BK从32改成64直接导致编译失败或运行时出现隐式回退。关键是理解共享内存有两层限制线程块内声明数组不能超过单块共享内存上限同时要留出足够的空间给tensor core操作数重排。寄存器超限的表现稍有不同。寄存器分配过多时编译器会把多余变量排挤到本地内存kernel日志那叫一个难看带宽占用直接飙升到好几倍性能却掉到脚踝。我在调TM×TN时遇到过这个坑改成小尺寸后性能不降反升就是因为寄存器压力降下来了。6.2 数值稳定性问题用了FP16之后某些形状的矩阵乘结果会出现肉眼可见的精度下降尤其是K维度特别大的时候。FP16的尾数位数只有11位中间累加结果如果直接用FP16存误差会快速累积。我的解决方案是强制FP32累加即tensor core输入用FP16但累加器全程保持FP32只在最后写回输出时转成需要的格式。还有一个细节容易被忽略当K维度很大时,中间累加值可能远大于单个乘法的结果这时即使累加器是FP32逐项加法的浮点误差仍然存在。更激进的做法是用分裂累加把累加结果拆成高位和低位两个FP32变量或者使用Kahan补偿算法。不过对于绝大多数深度学习场景FP32累加已经够了分裂累加属于锦上添花。6.3 性能瓶颈难定位时的排查思路如果性能低于预期我的建议是按照固定顺序排查首先看kernel是否实际启用了tensor core指令方法是在编译选项中打开ptx/dump输出检查指令序列其次看共享内存和寄存器占用是否正常再次是分析数据加载阶段是否存在bank conflict。bank conflict是共享内存里的隐形杀手。当多个线程同时访问同一bank的地址时硬件会把访问串行化导致共享内存带宽骤降。在加载A和B分块时我调整了线程索引和内存地址的映射关系。用一个简单的swizzle操作把需要同时访问的地址散布到不同bank。这个改动带来的性能提升比预期大得多尤其在BM和BN比较大的配置下。还有一个常见的诊断技巧单独注释掉tensor core计算只保留数据加载逻辑。如果加载阶段本身的耗时已经占比很高说明问题出在访存路径如果加载很快但整体很慢则问题多半在计算指令或同步开销上。7. 一些收尾经验整个DeepGEMM做下来我最大的体会是高性能计算优化与其说是炫技不如说是一遍遍和硬件对话。每次性能卡住都是因为我某个假设没考虑硬件的真实行为。比如以为共享内存越大越好结果忽略了bank conflict以为tensor core必定加速结果忽略了数据布局要求。最后再分享一个小技巧调参时不要只看最终的GFLOPS数要同时记录共享内存占用、寄存器数、kernel耗时三个指标。三者之间的关系往往比单一指标更能说明问题。我手上常备一张纸每调一次参数就更新一列数据哪个参数改变引起哪些连锁反应一眼就能看出规律。如果你也想自己写一个GEMM内核建议从最简单的版本开始把基线跑通再一层层叠加优化。每加一层优化都对比一次基线确认收益真实存在再继续。不要一口气把所有技巧全塞进去否则出了问题根本分不清是哪个改动导致的。DeepGEMM这个项目虽然规模不大但从原理分析到落地调优的完整链路比单纯调用厂商库获得的那点性能提升更有价值。

相关新闻

红外图像非均匀性校正:神经网络场景自适应方法解析

红外图像非均匀性校正:神经网络场景自适应方法解析

简介:这份PDF是一篇基于神经网络的红外图像非均匀性校正学术论文,面向红外探测、图像处理与机器学习领域的工程技术人员和研究者。论文针对红外焦平面材料、制造工艺及多路模拟信号输出导致的像元响应不一致问题,详细介绍了盲元检测与补偿、双…

2026/10/13 11:41:14 阅读更多 →
从全连接到卷积:PyTorch卷积神经网络参数解析与实战

从全连接到卷积:PyTorch卷积神经网络参数解析与实战

1. 从全连接层到卷积层:为什么我们需要换一种思维方式如果你跟着 PyTorch 的学习路径一路走到 task05,大概率前面已经折腾过线性回归、softmax 分类、多层感知机这些内容了。到了卷积神经网络这一关,很多人第一反应是“不就是换个网络结构吗”…

2026/10/13 11:40:10 阅读更多 →
Claude记忆增强实践:上下文压缩与向量索引协同方案

Claude记忆增强实践:上下文压缩与向量索引协同方案

1. “claude-mem”不是官方产品,而是开发者社区自发构建的记忆增强实践体系“claude-mem”这个词最近在技术社区、AI工具讨论组和开发者笔记中高频出现,但它从未出现在Anthropic的任何官方文档、API说明或产品路线图中。它不是一款独立软件,也…

2026/10/13 11:40:14 阅读更多 →

最新新闻

Flink Scala API生产实践:时间语义、状态管理与反压调优

Flink Scala API生产实践:时间语义、状态管理与反压调优

1. 项目概述:这不是“学Flink”,而是用Scala API把实时数据流真正跑起来“Flink-ScalaApi常规”——看到这个标题,别急着点开文档或翻API手册。它不是一句空泛的技术标签,而是一套在真实生产环境中被反复验证、打磨、踩坑后沉淀下…

2026/10/13 12:05:53 阅读更多 →
网格交易如何用ATR动态调整网格大小?Python实现与实战避坑

网格交易如何用ATR动态调整网格大小?Python实现与实战避坑

简介:这是一份讲解自动调整网格交易策略中网格大小方法的原创文档,面向希望改进传统网格策略的量化投资者,以及使用Python进行股票分析的开发学习者。文档针对固定网格导致过早满仓或空仓的痛点,给出魔灯的两类自适应方案&#xf…

2026/10/13 12:05:53 阅读更多 →
多波束水深测量数据处理:从原始数据到合格成果的关键步骤

多波束水深测量数据处理:从原始数据到合格成果的关键步骤

简介:这是一份面向海洋测绘、航道测量等领域的专业文献,系统论述多波束水深测量数据处理方法。内容从多波束测深系统组成切入,详细定义测量船坐标系、多波束探头坐标系、姿态传感器坐标系、电罗经坐标系、水平坐标系及测量坐标系,…

2026/10/13 12:05:53 阅读更多 →
artcraft:基于Canvas的参数驱动视觉创作工具集

artcraft:基于Canvas的参数驱动视觉创作工具集

1. 从“artcraft”这个名字说起:它到底想解决什么问题 第一次看到“artcraft”这个项目标题,我的直觉是:这大概率是一个把“艺术创作”和“工程实现”缝合在一起的东西。art 是艺术,craft 是手艺、工艺,合在一起就是“…

2026/10/13 12:05:53 阅读更多 →
k邻近算法实战指南:从数据清洗到在线更新的七道关卡

k邻近算法实战指南:从数据清洗到在线更新的七道关卡

1. 这不是“调个包”那么简单:k邻近算法在真实项目里到底怎么用你打开sklearn文档,看到from sklearn.neighbors import KNeighborsClassifier,敲下几行代码跑通了鸢尾花数据集——恭喜,你完成了k邻近算法的“Hello World”。但如果…

2026/10/13 12:05:53 阅读更多 →
环形链表 II:快慢指针找入环点的数学推导与代码实现

环形链表 II:快慢指针找入环点的数学推导与代码实现

要搞懂这道“环形链表Ⅱ”,光会判断有没有环远远不够。很多人在 LeetCode-141 里用快慢指针跑得飞起,一遇到 142 要找入环点就直接懵住。LeetCode-142 真正考的不是“会不会用双指针”,而是“能不能讲清楚快指针和慢指针相遇之后,…

2026/10/13 12:04:52 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →