PyTorch核心机制与实战:动态图、自动微分、显存优化及多卡训练
1. 从一次模型训练卡死说起为什么值得重新认识PyTorch很多人第一次接触深度学习框架都是从一行import torch开始的。但真正让PyTorch在众多框架中站稳脚跟的不是它简洁的API而是它背后那套动态图自动微分的组合拳。我见过不少同行用PyTorch跑通了几个Demo之后就觉得不过如此结果一遇到自定义算子、多卡训练、显存爆炸、梯度异常这类问题就束手无策。问题不在于PyTorch难而在于大多数人只学了它的表面用法没有理解它为什么这样设计。这篇内容适合三类人第一类是有一定Python基础、想系统入门深度学习框架的开发者第二类是已经用过PyTorch但总觉得知其然不知其所以然的工程师第三类是需要把模型从实验阶段推向生产环境、被性能和部署问题折磨过的从业者。我会从PyTorch的核心机制讲起把动态计算图、自动微分、张量内存布局这些底层逻辑拆开揉碎再结合数据加载、模型定义、训练循环、显存优化、混合精度、模型导出等实际环节把每个关键选择背后的为什么讲清楚。需要说明的是PyTorch本身迭代很快不同版本之间API有差异。我下面提到的操作和参数主要基于近几个稳定版本的通用实践具体到你的环境时建议先确认版本号再对照官方文档。另外文中涉及的所有代码示例都是独立可运行的片段你可以直接复制到自己的脚本里做验证。2. 动态计算图到底动在哪里PyTorch的核心机制拆解2.1 从静态图到动态图一次前向传播里发生了什么要理解PyTorch先要理解计算图这个概念。计算图本质上是一种描述运算依赖关系的数据结构节点是张量或算子边是数据流向。早期很多框架采用先定义、后运行的静态图模式你需要先把整个网络结构声明好编译成图再喂数据。这种方式效率高但调试极其痛苦——你没法在中间插一句print看看某个张量长什么样。PyTorch走的是动态图路线。每次前向传播时框架会实时构建一张计算图运算执行完这张图就可以丢弃。这意味着你可以像写普通Python代码一样写模型if判断、for循环、递归调用都能自然融入。我举个最直观的例子import torch def forward(x, use_branch): if use_branch: return x * 2 1 else: return x * 3 - 1 x torch.tensor([1.0, 2.0, 3.0], requires_gradTrue) y forward(x, use_branchTrue) y.sum().backward() print(x.grad) # 输出 [2., 2., 2.]这段代码里if分支直接决定了计算图的走向。静态图框架要支持这种逻辑得引入复杂的控制流算子而PyTorch天然支持。这就是动态图最大的价值调试友好、逻辑表达自由。但动态图不是没有代价。每次迭代都要重新构建图会带来额外的Python解释器开销。所以PyTorch后来引入了torch.compile和TorchScript这类工具把动态图固化成静态图来加速。这里的关键认知是PyTorch不是纯粹的动态图框架而是动态图优先、可选择性静态化的框架。理解这一点你就能明白为什么有些场景下加一行torch.compile能让训练速度提升30%以上。2.2 自动微分不是魔法反向传播的链式法则实现自动微分是PyTorch的另一块基石。很多人知道调用.backward()就能算梯度但不知道梯度是怎么在计算图上流动的。简单说PyTorch为每个张量维护了一个grad_fn属性记录它是怎么被算出来的。当你调用backward()时框架从损失函数出发沿着grad_fn链反向遍历用链式法则逐层计算梯度。这里有个容易被忽略的细节只有requires_gradTrue的张量才会被纳入计算图。模型参数默认开启梯度追踪而输入数据通常不需要。如果你发现某个中间变量的梯度是None第一件事就是检查它的requires_grad状态。再深入一层PyTorch的自动微分支持梯度累加而不是梯度替换。也就是说每次调用backward()梯度会累加到.grad属性上而不是覆盖。这就是为什么训练循环里必须写optimizer.zero_grad()。我见过新手忘记清零梯度结果loss不降反升排查半天才发现是梯度累积导致的。# 正确的训练循环片段 for data, target in dataloader: optimizer.zero_grad() # 清零梯度必须放在前向之前 output model(data) loss criterion(output, target) loss.backward() # 反向传播梯度累加 optimizer.step() # 更新参数还有一个进阶技巧梯度裁剪。当网络较深或学习率较大时梯度可能爆炸导致参数更新幅度过大。用torch.nn.utils.clip_grad_norm_可以把梯度范数限制在阈值内这是训练RNN和Transformer时的常规操作。2.3 张量的内存布局为什么你的显存总是不够用张量是PyTorch的基本数据结构但很多人只把它当成多维数组忽略了它的内存布局。一个张量在内存中是连续存储的形状shape、步长stride、存储偏移storage_offset共同决定了如何索引数据。理解这一点对显存优化至关重要。举个例子view()和reshape()看起来功能相似但view()要求张量在内存中连续而reshape()会在必要时复制数据。如果你对一个转置后的张量调用view()会直接报错。这时候要么先调用.contiguous()要么改用reshape()。但.contiguous()会触发一次内存拷贝在显存紧张时可能成为压垮骆驼的最后一根稻草。另一个常见问题是原地操作。像x.add_()、x.relu_()这类带下划线的操作会直接修改原张量节省内存但可能破坏计算图的完整性。如果你在反向传播前对某个需要梯度的张量做了原地修改PyTorch会报a leaf Variable that requires grad is being used in an in-place operation的错误。我的经验是在模型定义中尽量避免原地操作除非你非常确定它不会影响梯度计算。显存优化的另一个关键是及时释放无用张量。Python的垃圾回收机制对GPU显存的管理并不及时尤其是在循环中创建的中间变量。你可以用del显式删除再配合torch.cuda.empty_cache()清理缓存。但要注意empty_cache()只是释放未被占用的缓存块不会释放正在使用的显存频繁调用反而会降低性能。3. 数据管道与模型定义那些文档里不会写的实操细节3.1 Dataset和DataLoader数据加载慢的根因在哪里数据加载是训练流程中最容易被低估的环节。很多人发现GPU利用率只有30%不到第一反应是模型太小其实更常见的原因是数据管道成了瓶颈。PyTorch提供了Dataset和DataLoader两个抽象前者负责定义怎么取一条数据后者负责怎么批量取、怎么并行取。DataLoader的num_workers参数决定了用几个子进程加载数据。设为0表示在主进程加载设为大于0的值会启动子进程。这里有个坑在Windows上num_workers大于0时需要把训练代码放在if __name__ __main__:保护块内否则会无限递归创建子进程。在Linux上则没有这个限制。另一个关键参数是pin_memory。当它为True时数据会被加载到锁页内存中从CPU传到GPU的速度会更快。但锁页内存是有限资源设得太多反而会导致系统变慢。我的经验是如果GPU训练是瓶颈开启pin_memory如果数据加载是瓶颈优先增加num_workers。还有一个容易被忽略的点是collate_fn。默认的批处理逻辑会把样本堆叠成张量但如果你的样本长度不一比如变长文本就需要自定义collate_fn来做填充。填充时要注意用padding_idx忽略填充位置的损失否则模型会学到一堆无意义的填充符。from torch.utils.data import Dataset, DataLoader class MyDataset(Dataset): def __init__(self, data, labels): self.data data self.labels labels def __len__(self): return len(self.data) def __getitem__(self, idx): return self.data[idx], self.labels[idx] def collate_fn(batch): # 自定义批处理逻辑比如变长序列填充 data, labels zip(*batch) max_len max(len(x) for x in data) padded torch.zeros(len(data), max_len) for i, x in enumerate(data): padded[i, :len(x)] x return padded, torch.tensor(labels) dataset MyDataset([torch.randn(10) for _ in range(100)], [i % 2 for i in range(100)]) loader DataLoader(dataset, batch_size8, shuffleTrue, num_workers4, pin_memoryTrue, collate_fncollate_fn)3.2 nn.Module的隐藏约定参数注册与设备迁移nn.Module是PyTorch定义模型的标准方式但它有一些隐藏约定不遵守就会踩坑。最重要的一条是只有通过self.xxx nn.Parameter(...)或self.xxx nn.Linear(...)这种方式赋值的子模块和参数才会被自动注册。如果你把参数放在一个普通Python列表里model.parameters()就找不到它们优化器也就无法更新。class BadModel(nn.Module): def __init__(self): super().__init__() self.weights [nn.Parameter(torch.randn(10, 10)) for _ in range(3)] # 不会被注册 class GoodModel(nn.Module): def __init__(self): super().__init__() self.weights nn.ParameterList([nn.Parameter(torch.randn(10, 10)) for _ in range(3)])另一个约定是train()和eval()模式。Dropout和BatchNorm在两种模式下的行为完全不同。训练时忘记调用model.train()或者推理时忘记model.eval()都会导致结果异常。更隐蔽的是eval()模式不会自动关闭梯度计算如果你在推理时不需要梯度应该配合torch.no_grad()使用否则会白白消耗显存。设备迁移也是新手常犯的错误。model.to(device)只会迁移模型参数不会迁移你手动创建的普通张量。如果输入数据没有移到GPU上就会报expected device cuda but got cpu的错误。我的习惯是在训练循环开始前把模型和数据都显式迁移到目标设备并在关键位置打印张量的device属性做确认。3.3 损失函数与优化器的搭配逻辑损失函数和优化器的选择不是随意的它们之间有内在的搭配逻辑。分类任务常用交叉熵损失回归任务常用均方误差这大家都知道。但很多人不知道的是PyTorch的CrossEntropyLoss内部已经包含了LogSoftmax和NLLLoss两步所以模型最后一层不要再加Softmax否则相当于做了两次归一化梯度会变得很小。优化器方面SGD适合需要精细调参的场景Adam适合快速收敛的实验。但Adam有个已知问题它的权重衰减实现和SGD不同早期版本中Adam的weight_decay等价于L2正则而不是真正的权重衰减。后来PyTorch引入了AdamW来修正这个问题。如果你在做Transformer类模型的训练优先用AdamW。学习率调度也是训练中的关键一环。StepLR、CosineAnnealingLR、OneCycleLR各有适用场景。我的经验是先用固定学习率跑通流程再根据loss曲线决定是否加调度器。如果loss在前期下降很快、后期震荡可以试试余弦退火如果loss一直不降先检查学习率是不是太大了。4. 训练循环之外显存、精度与多卡的实战取舍4.1 显存不够用时的排查顺序与优化手段显存不足是训练大模型时最常见的报错。遇到CUDA out of memory不要急着减小batch size先按下面的顺序排查第一确认是不是梯度累积导致的。如果你在循环里没有清零梯度显存会随着迭代次数线性增长。第二检查是不是中间变量没有释放。比如你在循环里把每个step的loss存进了一个列表这些loss张量会一直占用显存。第三看看是不是模型本身太大。用torch.cuda.memory_allocated()可以查看当前显存占用用torch.cuda.memory_summary()可以看到更详细的内存分布。如果确认是模型太大有几个优化手段。梯度检查点torch.utils.checkpoint可以用计算换显存在前向传播时不保存中间激活值反向传播时重新计算。混合精度训练torch.cuda.amp用FP16存储激活值和梯度显存占用可以减半。模型并行把不同层放到不同GPU上适合单卡放不下的大模型。from torch.cuda.amp import autocast, GradScaler scaler GradScaler() for data, target in dataloader: optimizer.zero_grad() with autocast(): output model(data) loss criterion(output, target) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()混合精度训练的关键是GradScaler。FP16的数值范围比FP32小梯度容易下溢成0。GradScaler会动态调整损失缩放因子把梯度放大到FP16能表示的范围内更新参数前再缩回去。注意scaler.step()替代了optimizer.step()scaler.update()用来调整缩放因子顺序不能错。4.2 多卡训练的两种模式DataParallel与DistributedDataParallelPyTorch支持两种多卡训练方式DataParallelDP和DistributedDataParallelDDP。DP实现简单一行代码就能用但效率低因为它是单进程多线程受Python GIL限制而且主卡要负责汇总梯度负载不均衡。DDP是多进程模式每个GPU一个进程梯度通过通信后端同步效率高得多。我的建议是只要卡数超过2张就用DDP。DDP的配置稍微复杂一点需要初始化进程组、设置local_rank、用DistributedSampler切分数据。但一旦跑通扩展性很好。import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP def setup(rank, world_size): dist.init_process_group(nccl, rankrank, world_sizeworld_size) def cleanup(): dist.destroy_process_group() # 在每个进程中 model model.to(rank) model DDP(model, device_ids[rank]) sampler DistributedSampler(dataset, num_replicasworld_size, rankrank) loader DataLoader(dataset, samplersampler, batch_sizebatch_size)DDP有一个容易踩的坑BatchNorm层在多卡训练时默认只统计当前卡上的均值和方差。如果每张卡的batch size很小统计量会不准确。解决办法是用SyncBatchNorm它会在所有卡之间同步统计量。转换方式很简单model nn.SyncBatchNorm.convert_sync_batchnorm(model)。4.3 从训练到推理模型导出与性能调优训练完模型只是第一步把它部署到生产环境还有一段路要走。PyTorch提供了多种导出方式torch.save保存整个模型或状态字典TorchScript把模型编译成可独立运行的格式ONNX导出成跨框架的中间表示。torch.save(model.state_dict(), path)是最推荐的方式因为它只保存参数不保存模型结构加载时需要先实例化模型再load_state_dict。这样代码和参数解耦模型结构改了也不影响参数加载。TorchScript适合需要脱离Python环境运行的场景。用torch.jit.trace或torch.jit.script把模型转成ScriptModule可以在C环境中加载。但trace只记录一次前向传播的路径如果模型有控制流必须用script。ONNX适合跨框架部署比如把PyTorch模型转到TensorRT或OpenVINO做推理加速。导出时要注意opset版本和动态轴设置否则可能遇到算子不支持的问题。推理阶段的性能调优核心是减少Python开销和充分利用硬件。torch.no_grad()关闭梯度计算model.eval()切换推理模式torch.inference_mode()比no_grad更激进会禁用更多内部状态跟踪。如果延迟要求极高可以考虑用torch.compile做图优化或者导出到专用推理引擎。5. 那些让我熬夜排查的坑版本兼容与常见报错5.1 CUDA版本、驱动版本与PyTorch版本的三角关系PyTorch的GPU版本依赖CUDACUDA又依赖显卡驱动。这三者版本不匹配就会报各种奇怪的错误。最常见的报错是CUDA driver version is insufficient for CUDA runtime version意思是驱动太旧不支持当前CUDA运行时。排查这个问题的顺序是先用nvidia-smi查看驱动支持的CUDA版本再用torch.version.cuda查看PyTorch编译时用的CUDA版本。如果前者小于后者要么升级驱动要么换一个用更低CUDA版本编译的PyTorch。另一个坑是conda安装和pip安装的PyTorch可能链接不同的CUDA库。如果你在conda环境里混用pip安装可能会出现undefined symbol之类的链接错误。我的建议是在一个环境里只用一种包管理工具要么全conda要么全pip。5.2 梯度为None或NaN的排查链路梯度为None通常有三个原因张量的requires_grad为False张量没有参与损失计算或者张量被原地操作破坏了计算图。排查时可以从损失函数出发用loss.grad_fn查看计算图的根节点然后逐层检查中间变量的grad_fn是否存在。梯度为NaN更麻烦通常是数值不稳定导致的。常见原因包括学习率太大、损失函数里有log(0)或sqrt(负数)、除零操作、FP16下溢。解决办法是降低学习率、给损失函数加epsilon、用torch.nan_to_num处理异常值、开启梯度裁剪。我遇到过一次梯度NaN排查了很久才发现是数据里有一个全零样本导致BatchNorm的方差为零除零后产生了NaN。数据清洗和异常值检查永远是训练前的必要步骤。5.3 模型保存与加载的版本陷阱用torch.save保存整个模型而不是state_dict时PyTorch会把模型类的路径也序列化进去。如果加载时模型类的定义变了或者模块路径变了就会报Cant get attribute的错误。这就是为什么官方推荐保存state_dict而不是整个模型。另一个陷阱是跨设备加载。在GPU上保存的模型加载到CPU上需要加map_locationcpu反过来在CPU上保存的模型加载到GPU上需要先加载再.to(device)。如果直接加载到不存在的设备上会报Attempting to deserialize object on a CUDA device but torch.cuda.is_available() is False。还有一个细节是PyTorch版本差异。高版本保存的模型低版本可能加载不了因为序列化格式有变化。如果必须在不同版本间迁移建议用ONNX做中转或者统一环境版本。6. 把PyTorch用顺手之后的一些个人体会PyTorch的上手曲线其实很平缓但精通曲线很陡。我自己的经验是前三个月基本都在调包真正开始理解它是从第一次自己写自定义autograd.Function、第一次用torch.profiler分析性能瓶颈、第一次用DDP跑通多机多卡开始的。如果你现在处于能跑通但不知道为什么的阶段我的建议是找一个小模型把它的前向传播、反向传播、参数更新过程用最原始的方式手写一遍不用nn.Module不用optimizer就用torch.tensor和backward()。写完之后你对PyTorch的理解会上一个台阶。另外不要害怕看源码。PyTorch的Python层源码可读性很好torch/nn/modules/linear.py、torch/optim/sgd.py这些文件都不长读一遍就能明白nn.Linear到底做了什么、SGD的动量是怎么实现的。这种向下挖一层的习惯比看十篇教程都有用。最后说一个实际工作中的小技巧养成记录环境配置的习惯。每次跑通一个实验把PyTorch版本、CUDA版本、显卡型号、关键依赖的版本都记下来。等到三个月后需要复现时你会感谢当时的自己。我见过太多因为环境不一致导致结果无法复现的案例这个坑踩一次就够了。

相关新闻

PyTorch深度学习实战:从张量到分布式训练与部署全链路指南

PyTorch深度学习实战:从张量到分布式训练与部署全链路指南

1. 从一张显卡到一套完整训练链路:我为什么把PyTorch当作深度学习的主力框架如果你刚接触深度学习,或者已经用过其他框架但总觉得“跑得起来却调不明白”,那PyTorch大概率是你绕不开的一站。它不是一个“点一下就能出结果”的黑盒工具&#x…

2026/10/15 5:37:22 阅读更多 →
兄弟钻攻中心C00系统PLC手册:地址、梯形图与维修实战

兄弟钻攻中心C00系统PLC手册:地址、梯形图与维修实战

简介:日本兄弟钻攻中心C00系统PLC系统手册是针对S500X1/S700X1机型的技术文档,专供经过认证或培训的操作与维护人员使用,用于掌握钻攻中心PLC程序编辑、调试与故障排查。内容从PLC基础概念、系统连接示意图讲起,再进入PLC功能操作…

2026/10/15 5:37:21 阅读更多 →
LLM request timed out排查指南:OpenClaw接入第三方API超时解决方案

LLM request timed out排查指南:OpenClaw接入第三方API超时解决方案

LLM request timed out 这个报错,接第三方 API 的朋友应该不陌生。OpenClaw 本身是个开源智能体框架,跑起来很轻,但一旦把模型源切到第三方兼容接口,超时就像定时炸弹一样时不时爆一下。这篇文章把我自己调通的全过程写出来&#…

2026/10/15 5:36:21 阅读更多 →

最新新闻

对抗样本攻击方法全解析:从FGSM到物理世界攻击

对抗样本攻击方法全解析:从FGSM到物理世界攻击

1. 对抗样本攻击的底层逻辑与整体分类框架搞机器学习安全这块的人,迟早会碰到对抗样本这个绕不开的坎。我第一次接触这个概念是在做一个图像分类的小项目时,模型在测试集上准确率跑到98%以上,结果把一张熊猫照片加上一层肉眼几乎看不出来的噪…

2026/10/15 6:13:42 阅读更多 →
屏幕蓝光与色温调节:Iris护眼软件配置指南

屏幕蓝光与色温调节:Iris护眼软件配置指南

长时间盯着屏幕,眼睛干涩、酸胀、晚上睡不着,这种状态持续了几年之后,我开始认真研究手里的显示设备到底哪里出了问题。折腾过显示器自带的护眼模式,试过系统里的夜间模式,也换过防蓝光眼镜——最后在日常主力设备上长…

2026/10/15 6:13:42 阅读更多 →
曲线轨道轮轨关系与钢轨磨耗养护全解析

曲线轨道轮轨关系与钢轨磨耗养护全解析

1. 曲线轨道:铁路线上最含蓄的“舞池”入行头几年,我一直觉得铁路最迷人的地方不是直线,而是曲线。直线太直白——两条钢轨平铺到底,列车轰隆而过,唯独曲线,列车在这里减速、倾斜、轮缘死死贴住轨侧&#x…

2026/10/15 6:13:42 阅读更多 →
YOLOv8移动端部署实战:NCNN、TNN、MNN三引擎横评与选型指南

YOLOv8移动端部署实战:NCNN、TNN、MNN三引擎横评与选型指南

忙了一下午,把训练好的YOLOv8s导出成ONNX,再转成三种不同的移动端格式,在真机上跑了三轮。反复替换、反复校准,最后得到的结论和很多人想的并不一样——跑分最高的引擎,不一定最少排坑;排坑最少的&#xff…

2026/10/15 6:13:42 阅读更多 →
对抗样本攻击方法全解析:从FGSM到PGD的实战指南

对抗样本攻击方法全解析:从FGSM到PGD的实战指南

1. 对抗样本攻击方法总结:从原理到实操的完整拆解搞对抗样本这几年,我最大的感受就是:攻击方法和防御方法就像在打一场永不停歇的军备竞赛。你今天找到一个能骗过模型的扰动,明天人家加个防御层就把你挡住了。但不管防御怎么进化&…

2026/10/15 6:13:42 阅读更多 →
桌面端AI工具实战:本地会话管理与API密钥安全存储指南

桌面端AI工具实战:本地会话管理与API密钥安全存储指南

1. 桌面端AI工具的核心价值与设计思路1.1 为什么桌面端是更务实的选择聊到AI工具的使用形态,很多人第一反应是打开浏览器、登录网页、输入问题、等待回答。这套流程在偶尔用用的时候没什么问题,但一旦你把它当成日常生产力工具,每天要调用几十…

2026/10/15 6:12:42 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →