尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
显存省了但GPU没吃饱?拆解LLM微调利用率低的真凶
显存从 48GB 一路压到 24GB 甚至 12GB模型终于塞进去了。nvidia-smi一看显存占用倒是挺健康可 GPU-Util 那个数字长期在 20%~30% 之间晃荡。很多人第一反应是“卡坏了”第二反应是“这模型是不是有 bug”。都不是。我最近在搭 LLM Training Lab 系列实验环境的时候遇到了一个特别典型的场景用 QLoRA 微调一个 7B 模型显存只用了 11GB / 24GB看着余量很大但 GPU 利用率死活上不去。跑一个 step 要 8 秒其中真正让 GPU 干活的不到 2 秒。这个 Lab 我标了一个感叹号就是因为它太有代表性了——显存省下来了不代表 GPU 被喂饱了。省显存的各种技巧往往只是把瓶颈从“放不下”换成了“跑不快”。这篇我就把“显存降了但 GPU 吃不满”这个现象彻底拆开从指标误读、真实原因、诊断工具到优化手段全部按我实操的路径过一遍。适合正在做 LLM 微调、LoRA/QLoRA 训练、低显存部署以及所有被“GPU 利用率低”折磨过的人。1. 显存省了GPU 利用率却低了先分清两个指标很多同学对“GPU 利用率”有一个默认的误解以为它代表 GPU 干活的百分比。这个错位是后面所有困惑的根源。1.1 显存占用率和 GPU 利用率根本不是一回事显存占用率看的是 HBM显存颗粒里已经放了多少钱。模型参数、优化器状态、激活值、CUDA context、通信缓冲区全都堆在这里。它反映的是“静态资源”的占用情况好比你家仓库里堆了多少货。GPU 利用率呢看的是流处理器SM在单位时间内有多少周期在跑实际的浮点运算。nvidia-smi里的GPU-Util其实是一个采样值NVIDIA 驱动在一段时间内统计 SM 上有 kernel 在跑的时间比例。它反映的是“动态执行”的繁忙程度好比仓库里的搬运工每小时真正搬货搬了多少分钟。两个指标没有必然联系模型占了 90% 显存但 SM 可能 90% 时间都在闲等模型只占 50% 显存SM 也可能跑得飞起。显存是“资格”利用率是“行为”中间隔着一整个流水线。1.2 从显存瓶颈切换到“别的瓶颈”系统瓶颈转移逻辑做 QLoRA、梯度检查点、混合精度之后你干的事情是把本来要更多显存才能完成的计算用“重复计算”或者“更低精度”的方式塞进更小的空间。但 GPU 本身没变数据还是那么多 token、那么多层要算。于是瓶颈出现了转移显存满了瓶颈可能在显存容量显存没满瓶颈就会暴露在别的地方——CPU 预处理、数据搬运、kernel 启动、图编译、通信等待。举一个生活化的例子把原本 200 人同时干的活压缩到 50 人场地里但你给每个人发的物料还是要从唯一的传送带上来。场地空了传送带就成了新的限速点。QLoRA 这类省显存方案的本质就是腾空场地但物流环节基本没动甚至因为需要额外反量化和计算物流更堵了。想明白这一点你就不会再用“加显存”来解决了。正确做法是诊断出当前真正的资源瓶颈在哪一层然后把那一层解开。2. 六个真实原因把“显存没满但 GPU 吃不满”拆开看这一节我按真实概率排序把我这两年在 LLM 训练场景里碰到的原因逐个讲透。每个都配一个最典型的迹象方便你对号入座。2.1 DataLoader 和预处理把流水线堵死了这是我见过最多的情况尤其是在自己写数据集、做对话模板、在线 tokenize 的时候。DataLoader里每个 worker 要读取原始文本做模板拼接、tokenizer 编码、padding/truncation、tensor 化这一串操作全在 CPU 上完成。如果每次取 batch 才临时处理GPU 会在每个 step 开始前白白等待几十甚至几百毫秒。我实测过一个项目一个 8 卡训练任务里每个 step 中 DataLoader 取数耗时占了总耗时的 58%。典型现象nvidia-smi的 GPU-Util 呈“锯齿状”——每步开始时突然跳高一下就跌回个位数然后等下一批数据。如果训练脚本里有num_workers0或者num_workers和 CPU 核数差太远几乎可以断定是这个原因。另外很多人在 tokenize 时用了tokenizer.encode而不是极简的tokenizer(text, return_tensorspt)再把 padding 放到 collate_fn 里做这种写法每一步都能吃掉 100ms 以上的 CPU 时间。2.2 CPU 与 GPU 之间的搬运偷偷吃掉一整段等待时间训练数据最终要送到 GPU 显存里这条路径是 PCIe 总线或者你服务器上的 NVLink-C2C。对常规训练来说训练数据量本身不大但问题是如果你没有用 pinned memory数据要从页锁内存拷贝到固定内存再传输这个“二传手”过程是同步的。同步的意思就是CPU 发起 H2D 拷贝CPU 必须等拷贝完成才能继续发下一个指令而 GPU 在这个 wait 期间无事可做。在 LoRA 训练这种单卡规模不大的场景里H2D 传输通常不是每秒几个 GB 的大流量问题而是“小批量、高频次、多次同步”的问题每次取 batch、每次把 labels 搬到 GPU、每次把 attention mask 搬上去、每次 gather 一下。每一处都触发一次隐式同步GPU 就被同步点切成了一段段碎片时间。典型现象GPU 利用率不高但 hostCPU侧的某个核占用率很高同时nvidia-smi里Volatile GPU-Util数值波动剧烈。2.3 Kernel 启动太密、算子太小GPU 只在“热身”这个原因在 LLM 里比想象中更隐蔽。LLM 的算力需求主要在 GEMM矩阵乘法上但注意力机制、LayerNorm、RMSNorm、残差连接、RoPE 位置编码、激活函数这些环节拆到 PyTorch 里是一大堆“小算子”。小算子的特点是每个算子本身运行时间可能只有几十微秒但 GPU 前期工作需要 launch 一次 kernel。一次 launch 从 CPU 发出指令到 GPU 收到并开始执行延迟通常在 5~20 微秒。如果一个小算子只跑 10 微秒那么 GPU 有 50% 以上的时间在“等待指令”SM 处于空闲转态。量化后的模型比如 int8 或 int4 权重尤其惨因为反量化经常引入逐元素操作算子更多、更碎。典型现象nvidia-smi显示的利用率不高但gpustat里看 power draw 已经很低GPU 温度也不高明显没有跑满算力。用 profiler 看 kernel 耗时分布会发现大量毫秒级以下的短 kernel。我曾经把一个 7B 模型在 4090 上做纯推理测试算下来理论算力至少能到每秒 30 个 token实际只有 12。一看 profiler 波形密密麻麻全是 20~50 微秒的小块中间还夹着等待间隔。这就是“显存够、但算力活活被调度拖死”的典型。2.4 优化器更新和梯度同步GPU 空转训练和推理不一样。推理只做 forward训练每个 step 还要 backward然后在 CPU 或 GPU 上更新优化器状态多卡还要通信同步梯度。在单卡微调场景optimizer step 一般不是瓶颈但梯度累积 多卡 DDP就不同了。DDP 在每个 step 结束时会有一次allreduce用来把各卡的梯度相加。这个通信本身很快但如果你的 batch 很小、梯度累积步数很多GPU 就会频繁进入“梯度同步等待”的空窗。另外极大模型的优化器更新比如 AdamW在 GPU 上执行时需要读取梯度和动量、更新参数这个操作涉及一大串内存带宽密集型算子。如果配置过小的 batch size优化器更新耗时在整个 step 里的占比会异常高。典型现象多卡时各卡显存占用基本一致但整体利用率只有 30%~50%单卡跑反而更高。Profiler 里能看到ncclKernelAllReduce或ncclAllReduce占了相当比例。2.5 Gradient Checkpointing 让计算翻倍利用率却不升反降省显存最狠的手段之一是 gradient checkpointing激活重计算。它会丢掉 forward 过程中的中间激活backward 时重新算一遍。这个设计的代价是backward 计算量显著上升。问题来了计算量上升 30%~50%GPU 利用率不一定上升——因为重计算是“碎”的。当激活值计算被拆成小块以后kernel 更碎、调度更频繁、总执行时间甚至比显存没优化时更慢。我发现很多人只看显存降了很开心完全没观察训练吞吐。我曾经在一次 IT 配置对比里做过测试同一批数据开与不开 checkpointing 的显存差了 6GB但 step 时间从 3.2 秒涨到 5.8 秒GPU 利用率不升反降。这个现象特别容易骗人你以为自己在省显存实际上是在用更多的墙钟时间换显存。在低显存卡上这可能是必要的权衡但你至少要知道自己付出了什么。2.6 torch.compile 和 CUDA Graphs 的“一次性成本”与动态 Shape最近很多代码模板开始默认加torch.compile。它确实能像魔法一样把上面的小算子融合掉但有三个“暗坑”第一首次编译要很久。对一个 7B 模型编译可能占用 5~15 分钟这个阶段 GPU 几乎是闲置的。如果你在跑短实验比如max_steps200的调优任务编译时间直接占了总训练时间的一半你看到的利用率就是“先 0% 很久后 100% 不久”。第二动态 shape 会触发反复重编译。LLM 训练如果存在不同长度的序列比如 padding 到最长但每次 tokenizer 输出长度不同torch.compile会把每个 shape 当成一个新编译对象。每来一个新 shapeGPU 就停下来等编译。第三CUDA Graphs 录制和重放。CUDA Graphs 可以把一串 kernel 捕获成一个图之后反复提交整个图减少 launch 开销。但捕获期间GPU 几乎不做事memory 还往往更高。如果一训练脚本循环里包含 Python 分支或动态判断捕获往往会失败然后悄悄退回普通模式你根本不知道。典型现象日志里看到torch.compile之后的warmup字样或者运行中 GPU 偶尔长暂停、后又恢复高占用。3. 诊断实操五分钟找到你的真实瓶颈不要瞎猜。我把诊断顺序固定住之后基本每次都能量到正确答案。3.1 先用 nvidia-smi 和 gpustat 看现象级别第一件事打开两个终端分别跑watch -n 0.5 nvidia-smi以及nvitopnvitop比nvidia-smi更好用能看到每个进程的 GPU 利用率、显存、SM 占用、内存带宽。观察 30~60 秒记录下列信息GPU-Util 是稳定高还是锯齿状还是长期个位数显存占用是否接近卡容量上限GPU 温度 / 功耗是否低温度低 功耗低 SM 没在工作是否有 CPU 进程持续占用大量核看top/htop如果显存没满但利用率个位数优先怀疑数据侧如果显存满了但利用率不高优先怀疑通信或算子碎如果功耗正常但利用率低多半是 kernel 太碎或者访问存储显存带宽已经到瓶颈。提示nvidia-smi的GPU-Util是采样值不是精确统计采样间隔通常 1 秒不能单看它要配合功耗和温度看。3.2 用 PyTorch Profiler 定位 CPU 侧耗时、H2D 耗时、kernel 耗时快速拿到准确的拆分用 PyTorch 自带的 profiler 就够了。我一般按下面这样包住一个 stepimport torch with torch.profiler.profile( activities[ torch.profiler.ProfilerActivity.CPU, torch.profiler.ProfilerActivity.CUDA, ], scheduletorch.profiler.schedule(wait1, warmup1, active5, repeat1), record_shapesTrue, profile_memoryTrue, ) as prof: for step_idx in range(8): train_one_step(step_idx) prof.step() print(prof.key_averages().table(sort_bycuda_time_total, row_limit20))关键看三行CPU 总耗时和Self CPU time如果 CPU 侧某个函数耗时很长而 CUDA 时间很短说明 CPU 是瓶颈。cudaMemcpyDtoH 或 HtoD排在前面的话传输是问题。kernel 数量和平均单 kernel 耗时单个 kernel 平均不到 20 微秒且 kernel 数量巨大算子碎片化问题严重。你还可以用prof.export_chrome_trace(trace.json)导出 trace然后在浏览器里打开 chrome://tracing 看时间线。图形比表格直观得多能看到 GPU 时间线上是不是布满空隙。3.3 一个更直观的方式Nsight Systems 看完整时间线如果 PyTorch Profiler 不够细我推荐再用 Nsight Systems 采一轮nsys profile --statstrue --tracecuda,nvtx,osrt -o train_profile -f true python train.py --max_steps 10它会给出 NCCL 通信、CUDA memory copy、kernel launch 等待、CPU 并发的完整分布。重点看CUDA Memory Copy和NCCL的时间占比以及在 GPU 时间轴上是否有大片空白没有任何 kernel 活动。Nsight 的报告对不太熟的人有点重但只要你经历过一次“一眼看出问题在哪”之后就离不开它了。3.4 我自己的一个完整分析案例我之前用 QLoRA 微调 7B 模型显存 11GB / 24GBGPU 利用率只有 31%。命令跑完我先看到nvidia-smi里 GPU-Util 锯齿状明显CPU 一个核占用 100%。随后 PyTorch Profiler 显示Name Self CPU % CUDA time % # of Calls DataLoader.collate 58.2% 0.1% 327 tokenizer encode 19.4% 0.0% 327 cudaMemcpy HtoD 6.8% 2.3% 654结论一下就出来了CPU 侧的处理才是绝对主导。优化方案是改用离线 pre-tokenize把 text 直接存成input_ids和attention_mask的 numpy 或 memmap 文件DataLoader 里只做torch.from_numpy和简单的 padding。改完之后step 时间直接少了 50%GPU 利用率拉到了 78%。4. 对症下药把 GPU 利用率顶上去的实战优化原因清楚之后优化就不是碰运气了。下面是我按优先级排序的实战手段。4.1 数据流水线先离线处理好再让 DataLoader 无脑取数最有效、最容易做错的优化其实是把数据处理从 DataLoader 里挪走。我建议的流程是提前把所有训练样本进行 tokenizer 编码存成.npy或.bin文件或者用 HuggingFacedatasets库的map方法离线处理并保存到箭筒格式Arrow。from datasets import load_dataset import os ds load_dataset(text, data_files{train: [train_0.txt]}) ds ds.map( lambda x: tokenizer(x[text], truncationTrue, max_length2048), batchedTrue, remove_columns[text], ) ds.save_to_disk(encoded_cache)训练时 DataLoader 只做torch.from_numpy()collate的轻量拷贝。打开persistent_workersTrue和prefetch_factor4让 worker 常驻提前预取。注意num_workers不是越大越好我见过有人为图快设到 32结果 CPU 上下文切换把 GPU 反而拖垮了。一般设成物理 CPU 核数的 1/2 到 1/4再配合 prefetch 看实证数据。每换一次 worker 数跑一个固定步数的实验比较 step time 即可。4.2 传输优化Pinned Memory 和单次拷大块做两件事。第一DataLoader里开pin_memoryTrue。它的作用是先把数据放到页锁定的内存中H2D 拷贝可以走更快的 DMA 路径不用先经过 pageable buffer。DataLoader(..., pin_memoryTrue, persistent_workersTrue)第二尽量减少传输次数。与其每个 batch 里把 input_ids、labels、attention_mask 分开 copy不如把它们拼成一个结构化的预处理 batch一次传输。很多 LLM trainer 喜欢各自封装 tensors但传输是“按次数收费启动开销”的一次拷 20MB 和 10 次拷 2MB后面代价远大于前者。如果数据量特别大也可以考虑把内存映射memmap文件的 offset 直接传给 GPU不行——GPU 不能直接访问 host 内存映射文件还是得先到 CPU 内存。所以 memmap 解决的是 CPU 侧磁盘读瓶颈不是传输瓶颈。4.3 计算图优化该融的融掉该录的录一遍面对“小算子碎片化”最佳解法是torch.compile或手写融合 kernel。如果能在不改变模型结构的前提下加下面两行试一下model torch.compile(model, modereduce-overhead)reduce-overhead模式特别适合 LLM 训练因为它会尽量把多个 kernel 融合成更少的 kernel并利用 CUDA Graphs 减少 launch。实测很多模型能提升 20%~40% 的有效吞吐。但要注意两个坑当你用的是 LoRA 时torch.compile可能对 adapters 和基座模型的融合遇到重编译问题。如果你动态替换 adapter 或改变训练序列长度确保所有输入长度一致pad 到固定长度避免反复重编译。首次编译会很长不要拿 50 步以内的短跑实验来评估。多跑几百步再判断。另一个手段是 CUDA Graphs如果torch.compile在某些自定义算子下走不通可以直接把训练步函数录制为 CUDA Graph之后重复 launch。其实torch.compile(modereduce-overhead)在 CUDA 后端已经做了这件事不用单独实现。4.4 并行与通信把同步节奏拉开如果确认是 DDP allreduce 导致的空窗有几个思路按实用度排序增大单卡 batch size减少 step 总数。通信次数变少通信开销占整体比例下降。梯度累积时先在本卡累积几个 micro-batch再一次 allreduce。PyTorch 的DDP默认每个 backward 都同步但配合torch.distributed的no_sync()可以延迟同步时机。使用GradScaler或 AMP 时注意梯度裁剪的同步点torch.nn.utils.clip_grad_norm_会在所有卡上做全局通信如果可避免就尽量减少调用频率。注意not allreduce 同步越多 GPU 利用率越高多卡训练的健康状态是“沟通少、干活密”。4.5 训练策略batch size、序列长度和梯度累积的节奏在低显存卡上做 LLM 训练还有一种“误解型”优化叫“为了省显存把 batch size 调到 1”。这样做显存确实省了但 batch size 1 意味着每步 GPU 执行的都是小 GEMM效率极差。显卡在 batch size 1 时可能只有满负载的 20%~30% 算术强度。正确做法是尽量把 micro-batch size 调到能吃掉当前显存余量的最大值。显存有富余就应该用去换吞吐。用梯度累积凑总的 effective batch size而不是把 micro-batch 无限调小。对变长序列固定 max_length避免动态 padding 导致的 shape 频繁变化或实现 bucketing把相近长度的样本分桶同时保持 batch 内长度相近减少 padding 浪费。这里面有一个“小花的钱不心疼”的心态误区显存没满就想让显存更空导致 batch size 畏手畏脚收益其实是负的。显存余量是用来做吞吐扩展的不是用来看着舒服的。5. 常见问题速查从现象直接对应排查方向我把这些年被问得最多的几类问题统一整理成一个表先看现象再看原因比自己瞎试快得多。现象可能原因验证手段修复方案GPU-Util 长期 0%~10%显存未满CPU 某个核几乎 100%DataLoader / 预处理瓶颈PyTorch Profiler 查看 Self CPU timehtop看 CPU 占用离线 pre-tokenizepin_memoryTruepersistent_workersTrueGPU-Util 呈锯齿状时高时低batch 取数慢或每步结束有评估/同步点watch nvidia-smi观察 30 秒加大 num_workers增大 prefetch减少 eval 频率GPU-Util 中等50%~60%显存已满功耗不高算子碎片化/小算子多看 profiler 中 kernel 平均耗时是否低于 20ustorch.compile(modereduce-overhead)或 CUDA GraphGPU-Util 不高NCCL通信时间占比超过 20%DDP 梯度同步频繁Nsight Systems 看 NCCL block增大单卡 batch延后 allreduce减少梯度累积步step 时间比未开 checkpointing 更慢gradient checkpointing 重计算开销过大对比开关前后 step time缩小 checkpointing 层数范围或用更细的 checkpoint 块前几分钟 GPU-Util 为 0之后突然跑满torch.compile 首次编译看日志中出现 Compiler / warmup 字样不要短跑评估用固定步数预热后再计时训练中途偶发 GPU-Util 清零然后又恢复动态 shape 触发重新编译 / 磁盘读取卡顿看 trace 中是否出现 compile / read 长段固定 max_lengthpad 到统一长度数据先拷到本地 SSD5.1 补充几条容易忽略的排查细节第一看util不如看 power。同一张卡功耗 30W 时利用率虚高也没用功耗到 250W 以上就算util只有 40%也说明 SM 在干重活只是采样周期错过了。nvidia-smi -q -d POWER可以看到完整功耗趋势。第二显卡有几个模式会锁功耗。笔记本卡的“性能模式”和“静音模式”差距巨大如果发现功耗永远上不去先检查驱动和电源管理设置别急着改代码。第三BF16 与 FP16 的算力差异。新卡对 BF16 的算力高于 FP16 或相同但如果你用 FP16 的autocast部分算子会走__half路径速度反而慢。简单做法是在支持 BF16 的卡上优先用torch.bfloat16。5.2 一个排查黑盒的通用套路如果你的项目太复杂不想每层都动手可以按这个“黑盒三步”快速缩小范围构造一个纯空转测试随机生成输入不做 DataLoader手动在 GPU 上构造 tensor跑同一个训练 step。如果 GPU 利用率接近 100%说明模型本身没问题瓶颈在数据和传输环境。加上 DataLoader但不做任何增强维持固定长度看 step time 是否显著变化。显著变化则瓶颈在数据管线。加上真实数据做完整训练对比 1 和 2 的结果。这样每次只加一个变量根因必现。我迭代了很多次实验最后发现最优组合往往不是某一项拉满而是离线 tokenize pin_memory persistent workers 固定长度 torch.compile 微调 batch size 到显存余量。这套组合在大多数 QLoRA / LoRA 微调任务上都能把 GPU 利用率从 20%~30% 抬到 70% 以上。对我个人来说最值钱的其实不是那几条优化代码而是想明白“显存降低”和“GPU 利用率”是两个维度的事。只要先分清指标再用 profiler 看一眼数据而不是对着nvidia-smi猜90% 的问题都能在半小时内定位。最后再提醒一句改完任何一项跑一个足够长的固定步数实验比如至少 200 步用 step time 而不是util数字做最终判断。因为 GPU 利用率的采样方式太容易骗人了。这个 Lab 系列的下一步我准备专门做一组torch.compile在不同 LLM 结构上的真实吞吐对比。如果你刚好卡在“显存有富余、GPU 不干活”的怪圈里按这套流程走一遍大概率能直接把训练速度翻上去。
RELATED

相关推荐

PE吹膜厚度波动问题分析与实时监控系统应用

PE吹膜厚度波动问题分析与实时监控系统应用

1. 项目背景与问题定位去年夏天我在一家软包装材料厂做技术咨询时,遇到个典型问题:他们的PE吹膜生产线频繁出现厚度波动超标,最严重时达到8μm,远超客户要求的5μm公差范围。产线主管老张挠着头说:"换了三批原料&…

📅 2026/11/2 16:42:12
解决Habitat仿真环境EGL与CUDA设备映射错误

解决Habitat仿真环境EGL与CUDA设备映射错误

1. 问题背景与现象解析 最近在部署Habitat仿真环境时遇到一个典型报错:"tryCreateContext(): unable to find CUDA device 0 among 2 EGL devices in total"。这个错误通常出现在使用Headless模式(无显示器环境)运行Habitat时&…

📅 2026/11/2 16:37:11
Milvus向量数据库存储链路全解析:从写入到查询的异步分层设计

Milvus向量数据库存储链路全解析:从写入到查询的异步分层设计

向量数据库这几年从“新鲜玩意”变成了很多系统的标配组件,Milvus 作为其中讨论度最高的一个,几乎成了面试里绕不开的话题。但大多数人聊到它,能说出来的无非是“存向量、建索引、做相似度检索”这几句,一旦被追问“一条数据从写入…

📅 2026/11/2 16:37:11
MORE NEWS

更多资讯

📰

Floorplan 在 Codex 中的完整实践:插件安装、$floorplan 绘图与只读 Ask 问答

【免费下载链接】floorplan See how your app actually fits together. An interactive, plain-English map of your codebase, drawn by Claude or Codex. 项目地址: https://gitcode.com/gh_mirrors/floorplan/floorplan 点击查看 免费下载 本文以 Floorplan 的 …

📰

Proton-GE 实战:非Steam游戏在Lutris上跑起来的3种接入方式

Proton-GE 实战:非Steam游戏在Lutris上跑起来的3种接入方式 【免费下载链接】proton-ge-custom Compatibility tool for Steam Play based on Wine and additional components 项目地址: https://gitcode.com/gh_mirrors/pr/proton-ge-custom Proton-GE 是在…

📰

USB2.0 电路设计核心关键点(源自 USB2.0 官方规范文档)

一、拓扑结构硬性约束层级限制:USB物理是分层星型拓扑,最大7层(Tier1~Tier7),主机为Tier1;一条通信路径中最多允许5个非根HUB;复合设备本身占用2层,不能放在第7层,第7层只…

📰

Scala Array操作:从定长数组到ArrayBuffer的完整指南

Scala的Array就是Java数组的封装,但Scala给它装上了集合操作的"超能力"。索引访问、map/filter、与List互转——让数组处理从Java的for循环中解放出来。 如果你从Java转到Scala,第一次用数组时可能会有疑问:Scala的Array和Java的数…

📰

MonoGame 跨平台游戏开发:30 分钟写出一个能动的方块

MonoGame 跨平台游戏开发:30 分钟写出一个能动的方块 【免费下载链接】MonoGame One framework for creating powerful cross-platform games. 项目地址: https://gitcode.com/gh_mirrors/mo/MonoGame 你手上有一个很小的创意:一个方块在窗口里移…

📰

从零开始学AI19——贝叶斯公式

贝叶斯主义超越数学公式,是一种认识世界的哲学:它认为概率是信念的度量,而非客观常数。与频率派“上帝视角”不同,贝叶斯强调人类在信息不全下通过先验、证据不断更新认知,这正是学习、决策与AI的核心逻辑。从医生诊断…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬