Dell G15 5520 RTX 3050 Laptop 显卡问题导致游戏/模型训练崩溃蓝屏重启的一次排查记录
结论
显卡的显存在较高频率下不稳定,需要手动降频。最终我在核心:405-2100 MHz 显存:405-5501 MHz下可以保持较高的稳定性,不会出现初始参数下的蓝屏重启的问题。
硬件环境
电脑:Dell G15 5520
CPU:Intel Core i5-12500H
核显:Intel Iris Xe
独显:NVIDIA GeForce RTX 3050 Laptop GPU,4GB VRAM
背景
从我拿到这个电脑的第一天起,只要我一玩游戏,电脑就蓝屏,或者游戏出现卡死的状况,比如原神,赛博朋克,逃离鸭科夫,米塔,地平线4,等等,3A大作,独立游戏全都一视同仁,没有一个能正常游玩半个小时以上。但是,其中有两个游戏非常特殊,空洞骑士和奥日,这两个游戏没有崩溃过,这也导致我当时认为不是电脑的问题,可能是显卡太差了,性能不够带不起来游戏的3D渲染,虽然逃离鸭科夫和米塔也带不起来有点扯淡,但我当时就这样说服了自己。
平时打游戏比较少,加上一开始的时候我拿它训练模型什么的也没事,就没有管他。直到前几天,我在训练一个小模型的时候,发生了和游戏崩溃一样的事,电脑崩溃重启了,这直接撞到我的熟练区了,一个几十MB的小模型你个3050训练不了这不胡诌吗,这显卡绝对有问题啊。然后我又去找了一下游戏的一些性能需求,打算新仇旧帐一块算,结果一看地平线4都18年的游戏了,他的推荐显卡的性能还没我这个3050强呢。其实当时找到这这个问题之后我也没想修他,想着这个电脑都用了4年了,直接618换个新的得了。嘿,一看今年的笔记本,我去年买一台今年买二手都能赚一点。得了吧,修修补补又三年,先修吧,也就有了这个排查记录。
问题复现
地平线 4
地平线 4运行大概20分钟后画面卡死,声音仍然继续播放,但窗口无法正常操作,显卡负载归零,弹窗强制关闭。在同一时间,Windows 事件查看器里出现了 NVIDIA 驱动相关的记录。


GWN 模型训练
GWN模型训练,环境为PyTorch 2.5.1+cu121,CUDA 12.1,batch=16,epochs=20,偶尔会出现电脑黑屏后重启,大多数情况下训练过程报错终止。训练日志记录如下。
正常训练
遇到非法内存访问
[case] device cuda epochs 20 batch 16
[train] device = cuda
[epoch 1] loss=2.5040 val_rmse=7.0906 lr=6.0e-05 steps=120/120
[epoch 2] loss=1.7521 val_rmse=4.5731 lr=1.2e-04 steps=120/120
[epoch 3] loss=1.0894 val_rmse=3.2107 lr=1.8e-04 steps=120/120
[train] WARN training crashed:
CUDA error: an illegal memory access was encountered
CUDA kernel errors might be asynchronously reported at some other API call,
so the stacktrace below might be incorrect.
CUDA 同步定位
CUDA 同步定位,同样出现出现任务执行失败。
[case] device cuda epochs 20 batch 16
[train] device = cuda
[epoch 1] loss=2.5048 val_rmse=7.1013 lr=6.0e-05 steps=120/120
[epoch 2] loss=1.7579 val_rmse=4.6111 lr=1.2e-04 steps=120/120
[train] WARN training crashed:
cuDNN error: CUDNN_STATUS_EXECUTION_FAILED
关闭 cuDNN
验证指标变成了 nan,出现了数值异常,但是此处在我降频之后就被修好了。emmm,但是我印象里这个错误还有其他的触发方式,比如我之前自己搓了一个模型训练的时候也有这个nan的问题,我那时是在模型里加了一个norm层解决的,不理解。
[case] device cuda epochs 20 batch 16
[train] device = cuda
[epoch 1] loss=2.5040 val_rmse=7.0905 lr=6.0e-05 steps=120/120
[epoch 2] loss=1.7642 val_rmse=nan lr=1.2e-04 steps=119/120
[epoch 3] loss=1.0848 val_rmse=nan lr=1.8e-04 steps=120/120
[epoch 4] loss=0.9376 val_rmse=nan lr=2.4e-04 steps=119/120
...
[epoch 16] loss=0.8188 val_rmse=nan lr=5.2e-05 steps=117/120
[train] early stop @ epoch 16
小 batch 训练
小 batch 训练,显存占用仅556 MiB,温度约 70°C,仍然触发 CUDA 错误,不是显存爆了。
[case] device cuda epochs 8 batch 4
[train] device = cuda
[epoch 1] loss=2.1730 val_rmse=4.9791 lr=6.0e-05 steps=477/477
[epoch 2] loss=1.1130 val_rmse=3.0742 lr=1.2e-04 steps=477/477
[epoch 3] loss=0.9278 val_rmse=2.7030 lr=1.8e-04 steps=477/477
[epoch 4] loss=0.8829 val_rmse=2.5214 lr=2.4e-04 steps=477/477
[train] WARN training crashed:
CUDA error: an illegal memory access was encountered
排查
先排查驱动的问题,将驱动更新为官方推荐版本。直接下载dell官方推荐的驱动Dell Drivers & Downloads,然后为了彻底卸载之前的驱动我又下载了Wagnardsoft / Display Driver Uninstaller 官方下载,之后按照下图的执行顺序清除现有驱动并进行重装。

再跑训练,还是不行。那没办法了,去查一下硬件吧。我用Dell自己的SupportAssist跑了一遍官方硬件扫描。大概流程是打开 SupportAssist,进支持 / Support,选 I want to check a specific piece of hardware,找 Video Card / 显卡,选 Stress Test / 压力测试。但是,我跑完这一遍检测没有任何问题。


于是我换了一个更专业的工具OCCT 官方下载,跑了一遍30分钟高负载的3D Adaptive和VRAM 检测,还是没有任何问题。

这就很神奇了,再跑模型训练还是出现问题,明明测试的负载要高于训练,但是什么问题也检测不出来,系统也没有报错,但是一跑游戏马上就卡了。
驱动没有问题,使用的是dell官网上推荐的版本,并且已经使用DDU完全清除了之前的驱动。OCCT的测试没有问题,说明整体上看这块显卡硬件上没什么大问题,核心和显存都没有那种直接的坏。那么问题应该是显卡中的一些组件在某些情况下不稳定。显卡不稳定,但是什么会导致不稳定呢,我想到了内存,对内存进行超频的话,内存出错的概率会增加,那么显卡是不是也是这个问题呢,要不降频试试。于是我直接将核心和显存的最大频率砍到1200MHz和5501MHz。哎,好了,模型训练也正常了,游戏也能跑了。但是这样功率限制太多了,我就让gpt去跑脚本调参,看看哪个配比没有阉割太多,又能保证稳定。
| 参数 | 结果 | 最高功耗 |
|---|---|---|
1200 / 6001 |
12 epoch 通过 | 27.62W |
1500 / 5501 |
12 epoch 通过 | 35.35W |
1650 / 5501 |
12 epoch 通过 | 42.56W |
1800 / 5501 |
12 epoch 通过 | 51.83W |
2100 / 5501 |
12 epoch 通过 | 70.56W |
2100 / 5501 |
30 epoch 确认通过 | 70.31W |
这个显卡的初始频率是2100 / 6001,也就是说我将显存或者核心的频率降低一点,问题就解决了。
脚本
直接命令
nvidia-smi -lgc 405,2100
nvidia-smi -lmc 405,5501
nvidia-smi --query-gpu=name,pstate,temperature.gpu,power.draw,clocks.gr,clocks.mem --format=csv,noheader,nounits
最终调频脚本:set-nvidia-tuned-clocks.ps1
param(
[int]$MaxGraphicsMHz = 2100,
[int]$MaxMemoryMHz = 5501
)
$ErrorActionPreference = "Continue"
Write-Host "Setting NVIDIA tuned clocks: graphics 405-$MaxGraphicsMHz MHz, memory 405-$MaxMemoryMHz MHz"
nvidia-smi -lgc 405,$MaxGraphicsMHz
nvidia-smi -lmc 405,$MaxMemoryMHz
Write-Host ""
Write-Host "Current status:"
nvidia-smi --query-gpu=name,pstate,temperature.gpu,power.draw,clocks.gr,clocks.mem --format=csv,noheader,nounits
运行方式:
powershell -ExecutionPolicy Bypass -File "C:\job\Vue\personalized-navigation-system\tools\gpu-repro\set-nvidia-tuned-clocks.ps1"
恢复默认频率脚本:reset-nvidia-clocks.ps1
$ErrorActionPreference = "Continue"
Write-Host "Resetting NVIDIA locked graphics and memory clocks."
nvidia-smi -rgc
nvidia-smi -rmc
Write-Host ""
Write-Host "Current status:"
nvidia-smi --query-gpu=name,pstate,temperature.gpu,power.draw,clocks.gr,clocks.mem --format=csv,noheader,nounits
开机自动应用脚本:startup-apply-nvidia-tuned-clocks.ps1
$ErrorActionPreference = "Continue"
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$logDir = Join-Path $scriptRoot "startup-logs"
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
$logPath = Join-Path $logDir ("startup-apply-" + (Get-Date -Format "yyyyMMdd-HHmmss") + ".log")
function Write-Log([string]$message) {
$line = "$(Get-Date -Format o) $message"
$line | Tee-Object -FilePath $logPath -Append
}
Write-Log "Startup NVIDIA tuned clock apply started."
Write-Log "ScriptRoot=$scriptRoot"
Start-Sleep -Seconds 25
$target = Join-Path $scriptRoot "set-nvidia-tuned-clocks.ps1"
if (-not (Test-Path -LiteralPath $target)) {
Write-Log "ERROR: target script missing: $target"
exit 1
}
$success = $false
for ($i = 1; $i -le 8; $i++) {
Write-Log "Attempt ${i}: applying tuned clocks."
$output = & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $target 2>&1
foreach ($line in $output) {
Write-Log ([string]$line)
}
$check = & nvidia-smi --query-gpu=clocks.gr,clocks.mem --format=csv,noheader,nounits 2>&1
Write-Log "Clock check: $check"
if (($output -join "`n") -match "GPU clocks set" -and ($output -join "`n") -match "Memory clocks set") {
$success = $true
break
}
Start-Sleep -Seconds 10
}
if ($success) {
Write-Log "Startup NVIDIA tuned clock apply finished successfully."
exit 0
}
Write-Log "ERROR: Startup NVIDIA tuned clock apply did not confirm success."
exit 2
使用教程
1. 放置脚本
先新建一个文件夹,用来专门存放调频脚本,放哪都行,没关系,例如:
C:\gpu-clock\
然后把下面两个脚本放到同一个文件夹里:
C:\gpu-clock\set-nvidia-tuned-clocks.ps1
C:\gpu-clock\startup-apply-nvidia-tuned-clocks.ps1
如果还需要恢复默认频率,也可以把恢复脚本一起放进去:
C:\gpu-clock\reset-nvidia-clocks.ps1
一定要注意:
set-nvidia-tuned-clocks.ps1 和 startup-apply-nvidia-tuned-clocks.ps1 必须放在同一个文件夹里。
原因是开机自动应用脚本里有这两行:
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$target = Join-Path $scriptRoot "set-nvidia-tuned-clocks.ps1"
它会先找到 startup-apply-nvidia-tuned-clocks.ps1 自己所在的目录,然后在同一个目录里寻找:
set-nvidia-tuned-clocks.ps1
如果两个脚本不在同一个文件夹里,开机自动脚本会找不到真正的调频脚本,日志里会出现:
ERROR: target script missing
2. 确认 nvidia-smi 可以使用
打开 PowerShell,执行:
nvidia-smi
如果能看到显卡信息,说明 nvidia-smi 可以正常使用。
如果提示找不到命令,可以改用完整路径:
"C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe"
如果你的电脑必须使用完整路径,那么脚本里的 nvidia-smi 也需要改成完整路径,例如:
& "C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe" -lgc 405,2100
& "C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe" -lmc 405,5501
3. 手动测试调频是否生效
先用管理员权限打开 PowerShell,然后执行:
powershell -ExecutionPolicy Bypass -File "C:\gpu-clock\set-nvidia-tuned-clocks.ps1"
成功后一般会看到类似输出:
GPU clocks set
Memory clocks set
然后查看当前频率:
nvidia-smi --query-gpu=name,pstate,temperature.gpu,power.draw,clocks.gr,clocks.mem --format=csv,noheader,nounits
注意:空闲状态下显卡频率可能会降到很低,这是正常的。锁定的是允许的频率范围,不代表显卡空闲时一定固定在 2100 / 5501 MHz。
4. 设置开机自动应用
因为锁频命令通常需要管理员权限,所以我使用 Windows 任务计划程序来实现登录后自动运行。
管理员权限打开 PowerShell,执行:
$taskName = "NVIDIA Tuned Clocks 2100-5501"
$scriptPath = "C:\gpu-clock\startup-apply-nvidia-tuned-clocks.ps1"
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal `
-UserId $env:USERNAME `
-LogonType Interactive `
-RunLevel Highest
Register-ScheduledTask `
-TaskName $taskName `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Description "Apply NVIDIA tuned graphics/memory clocks at user logon."
这里的关键点是:
-AtLogOn:用户登录时运行
-RunLevel Highest:使用最高权限运行
-WindowStyle Hidden:后台静默执行,不弹 PowerShell 窗口
5. 手动运行一次计划任务
创建完成后,可以不用重启,直接手动触发一次:
Start-ScheduledTask -TaskName "NVIDIA Tuned Clocks 2100-5501"
等待半分钟左右,然后查看日志:
C:\gpu-clock\startup-logs\
如果日志里出现:
GPU clocks set
Memory clocks set
Startup NVIDIA tuned clock apply finished successfully.
说明开机自动调频脚本可以正常工作。
6. 检查计划任务是否存在
Get-ScheduledTask -TaskName "NVIDIA Tuned Clocks 2100-5501"
也可以打开:
任务计划程序 -> 任务计划程序库
找到:
NVIDIA Tuned Clocks 2100-5501
7. 删除开机自动应用
如果以后不想登录后自动锁频,可以删除这个计划任务:
Unregister-ScheduledTask -TaskName "NVIDIA Tuned Clocks 2100-5501" -Confirm:$false
8. 恢复默认频率
删除计划任务只是不再开机自动设置,不会立刻恢复当前频率。
如果要立刻恢复 NVIDIA 默认频率,执行:
nvidia-smi -rgc
nvidia-smi -rmc
或者运行恢复脚本:
powershell -ExecutionPolicy Bypass -File "C:\gpu-clock\reset-nvidia-clocks.ps1"
恢复后可以再查一次:
nvidia-smi --query-gpu=name,pstate,temperature.gpu,power.draw,clocks.gr,clocks.mem --format=csv,noheader,nounits