训练神经网络时train loss或是validation loss出现nan

在使用带有SE block的神经网络进行训练时,博主遇到了训练loss变为nan的情况。经过排查,发现是nn.AdaptiveAvgPool3d(1)层输出存在inf。更换为nn.AvgPool3d后问题解决。文章提供了检查和解决loss nan的步骤,包括数据检查、归一化、loss计算以及forward路径的逐层检查。
部署运行你感兴趣的模型镜像

最近使用带有SE block的网络在pytorch框架下做训练。training loss 随着epoch增多不断下降,但是突然到某一个epoch出现loss为nan的情况,但是两三个epoch之后,loss竟然又恢复正常,而且下降了。
这几篇博客是我debug的借鉴,真的非常有用。
这篇介绍了出现nan的基本解决思路。
https://blog.youkuaiyun.com/qq_32799915/article/details/80612342
这篇介绍了为什么在多层dense layer之后某一层dense layer输出可能会出现nan,以及weight初始化的重要性及初始化方法。
https://yey.world/2020/12/17/Pytorch-14/
我自己的基本排查思路是:

  1. 首先检查数据中是否有inf 或者nan的情况。

普通numpy数组可用

np.all(np.isfinite(data))

我自己用的是医疗图像nifiti格式的压缩图像,所以使用代码如下:

def check_image(img_fname: str):
	#检查图像/numpy数组中是否有nan存在
    npy = sitk.GetArrayFromImage(sitk.ReadImage(img_fname))
    return np.any(np.isnan(npy))

def check_image_inf(img_fname: str):
	#检查图像/numpy数组中数据是否都是finit的(提示:若使用此函数,单独检查nan的函数可不用)
    npy = sitk.GetArrayFromImage(sitk.ReadImage(img_fname))
    return np.all(np.isfinite(npy))

def check_for_nan(input_folder: str):
    nii_files = subfiles(input_folder, suffix='.nii.gz')
    for n in nii_files:
        if check_image(n):
            print("nans found in ", n)
        elif not check_image_inf(n):
            print("infs found in ", n)
            
img_fold = '' #保存数据的文件夹
check_for_nan(img_fold)

如果数据没有问题,检查数据是否有normalization,如果没有归一化也可能出现nan或者网络层计算中出现infinit。

  1. 检查使用loss是否带有除法,算log的时候有负数或者很小的数。
    我所用的检查loss是否为nan的方法:
assert torch.isnan(loss).sum() == 0 and torch.isinf(loss).sum() == 0, ('loss is nan or ifinit', loss)

如果loss中有infit或者nan,则会输出

'loss is nan or ifinit', loss(这里会输出loss的值)

如果确认loss也并没有问题,那么问题可能出现在forward path中。

  1. 检查forward path每一层的输出结果,进行问题定位。在每一层后加入:
assert torch.isnan(out).sum() == 0 and torch.isinf(out).sum() == 0, ('output of XX layer is nan or infinit', out.std()) #out 是你本层的输出 out.std()输出标准差

如果是某一层计算出问题,考虑是不是初始化函数没有使用或者用得不对。
接下来,就到我的检查血泪史了。我发现我SE block的nn.AdaptiveAvgPool3d(1)输出中有inf!!!奇怪的是,这一次层的输入却没这个问题。后来我直接用了torch.nn.AvgPool3d代替前面的函数,它终于正常跑起来了。

b, c, D, H, W = x.size()  #b: batch size, c: channels, (D, H, W) data shape
y = torch.nn.AvgPool3d((D,H,W), padding=0)(x)
y = y.view(b, c) # 将y变成shape为(b,c)的tensor, 后面接全连接层

一周的辛酸血泪,终于好了。
具体nn.AdaptiveAvgPool3d()函数的内部实现我还没来得及研究,之后搞明白了再来分享到底为啥出问题。

您可能感兴趣的与本文相关的镜像

GPT-oss:20b

GPT-oss:20b

图文对话
Gpt-oss

GPT OSS 是OpenAI 推出的重量级开放模型,面向强推理、智能体任务以及多样化开发场景

<think>除了权重数量不足(`MaxNWts`设置过低)之外,神经网络训练失败可能由多种因素引起。以下将详细探讨这些因素,并提供相应的解决方案代码和解释。 ###1. **数值不稳定(梯度消失/爆炸)****原因**:当网络层数较深或权重初始化不当,梯度可能在反向传播过程中变得极小(消失)或极大(爆炸)。**表现**:损失函数出现`NaN`,或权重变为`Inf`。**解决方案代码**:```r#在nnet训练中增加梯度裁剪和权重初始化控制model_ann <-train(D~ t,data =data,method= "nnet",trControl= ctrl_unified,tuneGrid =tuneGrid_ann,linout= TRUE,trace =TRUE,metric= "RMSE",MaxNWts =100000,maxit =100000,#新增稳定性控制参数abstol=1e-8,#绝对损失容忍度reltol =1e-8,#相对损失容忍度#权重初始化范围(根据输入范围动态计算)rang=0.7,#或使用 rang= if(max(data$t) >min(data$t))0.7/diff(range(data$t))else0.1#梯度裁剪(通过自定义函数实现)preProcess =c("center","scale")#数据标准化)``` ###2. **数据问题****原因**:-输入数据包含`NA`或`Inf`值-特征量纲差异过大-类别不平衡(分类问题)**解决方案代码**:```r#数据清洗和预处理library(tidyr)library(dplyr)#移除缺失值data_clean<- data%>%drop_na()%>%#过滤无穷值filter_all(all_vars(!is.infinite(.)))#标准化处理preProc<-preProcess(data_clean,method =c("center","scale"))data_processed <-predict(preProc,data_clean)#使用处理后的数据训练model_ann<- train(D~ t,data =data_processed,...)```###3.**收敛问题****原因**:-学习率过高/过低-迭代次数不足(`maxit`设置过小)-局部最小值**解决方案代码**:```r#增加迭代次数并添加早停机制model_ann <-train(...,maxit=100000,#收敛控制abstol =1e-10,reltol =1e-10,#学习率调整(通过decay参数间接控制)tuneGrid= expand.grid(size= seq(2,11, by=1),decay= c(0.0001,0.001,0.01,0.1,1)#增加更大的decay值))``` ###4. **模型复杂度过高导致过拟合****原因**:隐藏层节点过多或权重衰减不足,导致训练集完美拟合但泛化性能差。**表现**:训练误差极低但验证误差很高。**解决方案代码**:```r#使用更强的正则化(权重衰减)和早停ctrl_early <-trainControl(method ="cv",number =10,savePredictions ="final",classProbs =FALSE,summaryFunction =defaultSummary,#早停设置returnResamp ="all",verboseIter= TRUE,stopOnNaN= TRUE)model_ann <-train(...,trControl= ctrl_early,tuneGrid =expand.grid(size =c(2,4,6,8),#减少最大节点数decay =c(0.1,1,10)#增加衰减强度))``` ###5. **软件/硬件限制****原因**:-内存不足(特别是大型网络)-数值计算库错误**解决方案代码**:```r#减少批量大小或使用增量训练#切换到更高效的神经网络包(如RcppML::nn)#增加虚拟内存(操作系统级别)#示例:使用 mini-batch训练(需自定义模型)library(keras)model_keras<- keras_model_sequential()%>%layer_dense(units =8, activation= 'relu', input_shape =c(1))%>%layer_dense(units =1)model_keras%>% compile(loss= 'mse',optimizer =optimizer_rmsprop(learning_rate =0.01))history<- model_keras%>% fit(x =data$t,y =data$D,epochs=100,batch_size =32,#控制内存使用validation_split =0.2)```###6.**激活函数选择不当****原因**:例如在回归任务中使用 ReLU可能导致输出无界。**解决方案**:根据任务类型选择激活函数:-回归任务:输出层使用线性激活(`linout=TRUE`)-二分类:输出层使用 sigmoid-多分类:输出层使用 softmax**代码调整**:```r#在nnet中,通过linout控制输出层激活函数#linout=TRUE表示线性输出(回归),FALSE表示逻辑输出(分类)```###7.**随机种子影响****原因**:权重初始化随机性导致结果不可复现。**解决方案**:```r#设置全局随机种子set.seed(123)model_ann<- train(...)```###综合诊断函数```r#神经网络训练诊断函数diagnose_nnet_failure <-function(model) {if(model$results$RMSE==0){return("Overfitting detected: Zerotraining error")}if (any(is.na(model$results$RMSE))){failed_params<- which(is.na(model$results$RMSE))return(paste("Trainingfailedforparameters:",paste(failed_params, collapse= ",")))}if(max(model$results$RMSE) >1e5) {return("Numerical instability: Exploding gradients")}return("Noobvious failuredetected")}``` ###总结导致神经网络训练失败的常见因素包括: 1.数值不稳定性(梯度消失/爆炸) 2.数据质量问题(缺失值、量纲) 3.收敛问题(迭代不足、学习率不当)4.模型过拟合5.硬件/软件限制6.激活函数选择错误7.随机初始化影响通过系统性的数据预处理、参数调整和稳定性控制,可有效避免大部分失败情况。 §§相关问题§§: 1.如何检测神经网络训练中的梯度消失问题?2.在R中如何实现自定义的早停机制(earlystopping)? 3.针对类别不平衡数据,神经网络应如何调整?4.如何解释权重衰减(decay)与学习率(learning rate)的关系?</think>### 除了权重数量,还有哪些因素会导致神经网络训练失败? 神经网络训练失败可能由多种因素引起,以下是最常见的7类问题及其解决方案: --- #### 1. **梯度消失/爆炸问题** **原因**:深层网络中梯度在反向传播过程中指数级减小或增大 **表现**:损失函数值变为 `NaN` 或无限大 **解决方案**: ```r # 添加梯度裁剪和权重初始化控制 model_ann <- train( ..., # 梯度裁剪 clip = 1.0, # 限制梯度范围在[-1.0, 1.0] # 改进的权重初始化 initFunc = "Xavier", # Xavier/Glorot初始化 initFuncParams = c(0, 1), # 初始化范围 # 使用ReLU激活函数避免梯度消失 act.fct = "relu" ) ``` --- #### 2. **数据质量问题** **原因**:缺失值、异常值、数据尺度差异 **解决方案**: ```r # 数据预处理管道 library(recipes) recipe_spec <- recipe(D ~ t, data = data) %>% step_impute_knn(all_predictors()) %>% # KNN填充缺失值 step_center(all_numeric()) %>% # 中心化 step_scale(all_numeric()) %>% # 标准化 step_outliers_maha(all_numeric()) %>% # 处理异常值 step_corr(all_numeric(), threshold = 0.9) # 移除高相关特征 prepped_data <- prep(recipe_spec, training = data) data_processed <- bake(prepped_data, new_data = data) ``` --- #### 3. **学习率问题** **原因**:学习率过大导致震荡,过小导致收敛缓慢 **解决方案**: ```r # 自适应学习率策略 model_ann <- train( ..., # 学习率调度 learningrate = 0.01, learningrate_decay = 0.95, # 每epoch衰减5% learningrate_min = 1e-6, # 最小学习率 # 或使用优化器内置调度 optimizer = "rmsprop" # 替代默认的sgd ) ``` --- #### 4. **过拟合问题** **原因**:模型过于复杂,训练数据不足 **解决方案**: ```r # 正则化技术组合 model_ann <- train( ..., # 正则化增强 decay = 0.1, # L2正则化强度 dropout = 0.3, # 随机丢弃30%神经元 # 早停机制 early_stopping = TRUE, patience = 10, # 10轮无改善则停止 validation_split = 0.2 # 验证集比例 ) ``` --- #### 5. **激活函数选择不当** **原因**:不匹配任务类型的激活函数 **解决方案**: ```r # 根据任务类型选择激活函数 if(regression_task) { output_activation <- "linear" hidden_activation <- "relu" } else if(binary_classification) { output_activation <- "sigmoid" hidden_activation <- "tanh" } else { output_activation <- "softmax" hidden_activation <- "leaky_relu" } model_ann <- nnet( ..., act.fct = hidden_activation, output.fct = output_activation ) ``` --- #### 6. **硬件/内存限制** **原因**:显存不足,计算资源不够 **解决方案**: ```r # 内存优化策略 library(keras) # 使用更高效的框架 model <- keras_model_sequential() %>% layer_dense(units = 64, activation = 'relu', input_shape = c(1)) %>% layer_dense(units = 1) %>% compile( loss = 'mse', optimizer = optimizer_adam(), metrics = c('mae') ) %>% fit( x = data$t, y = data$D, batch_size = 32, # 减小批次大小 epochs = 100, callbacks = list( callback_reduce_lr_on_plateau(monitor = "val_loss", factor = 0.5) ) ) ``` --- #### 7. **收敛问题** **原因**:局部最小值、鞍点、病态条件 **解决方案**: ```r # 高级优化技术 model_ann <- train( ..., # 改进的优化器 optimizer = "adam", # 动量加速 momentum = 0.9, # 二阶优化方法 hessian = TRUE, # 多起点初始化 num_init = 5, # 5次不同初始化尝试 # 学习率预热 warmup_epochs = 10 ) ``` --- ### 训练失败诊断工具 ```r # 神经网络诊断函数 diagnose_nnet <- function(model) { if(any(is.na(model$weights))) { cat("❗ 权重包含NA值:检查梯度爆炸或数据问题\n") } if(max(model$fitted.values) > 1e10) { cat("⚠️ 输出值过大:检查输入缩放和激活函数\n") } if(model$convergence == 0) { cat("✅ 模型成功收敛\n") } else { cat(paste("❌ 收敛失败 - 代码:", model$convergence, "\n1 = 达到最大迭代\n4 = 数值错误\n")) } # 梯度检查 if(!is.null(model$gradient)) { grad_norm <- norm(model$gradient, "2") cat(sprintf("梯度范数: %.4e\n", grad_norm)) if(grad_norm < 1e-8) cat("⚠️ 梯度消失可能\n") if(grad_norm > 1e4) cat("⚠️ 梯度爆炸可能\n") } } # 使用示例 diagnose_nnet(model_ann) ``` ### 关键预防措施 1. **数据预处理**:始终标准化/归一化输入数据 2. **梯度监控**:在训练过程中跟踪梯度范数 3. **损失曲线**:可视化训练/验证损失曲线 4. **敏感性分析**:测试不同超参数组合 5. **数值稳定性**:使用双精度浮点计算
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值