You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CS231n循环训练神经网络实例后续运行缓慢问题求助

问题分析与解决思路

你遇到的这个问题确实大概率是内存泄漏导致的——第一个模型训练时内存占用正常,但后续循环中,前一个模型/solver的内存没有被彻底释放,导致内存越用越多,系统开始频繁换页(swap),进而拖慢了代码执行速度。虽然你用了del语句,但Python的垃圾回收机制不会立刻回收内存,尤其是当对象之间存在引用循环(比如Solver持有Model的引用,Model又间接引用了Solver的某些配置)时,引用计数无法降到0,内存就会一直被占用。

下面是具体的验证方法和解决方案:


一、先验证是否真的是内存泄漏

可以通过监控内存使用情况来确认:

  1. 系统工具监控:

    • Linux/macOS:打开htop或top,观察Python进程的内存占用(RES列),如果每次循环后内存只升不降,就实锤内存泄漏。
    • Windows:打开任务管理器,查看Python进程的内存使用量变化。
  2. 代码中打印内存使用:
    用psutil库实时打印内存,先安装:pip install psutil,然后添加到你的循环中:

    import psutil
    import os
    
    def get_mem_usage_mb():
        proc = psutil.Process(os.getpid())
        return proc.memory_info().rss / (1024 ** 2)
    
    for lr in learning_rates:
        print(f"Before training lr={lr}: {get_mem_usage_mb():.2f} MB")
        # ... 你的模型训练代码 ...
        # del和gc代码
        print(f"After training lr={lr}: {get_mem_usage_mb():.2f} MB")
    

    如果每次循环后内存没有回落,就说明内存没被正确回收。


二、解决方案

针对CS231n的Solver和FullyConnectedNet实现,这里有几个有效的解决方法:

方法1:手动斩断引用并强制垃圾回收

Python的del只是删除变量名的引用,但如果其他对象还持有这个对象的引用(比如Solver里的self.model),内存还是不会被释放。我们可以先手动清除这些引用,再强制触发垃圾回收:

修改你的循环代码:

import gc

best_model = None
best_val_acc = -1
hidden_dims = [100, 100, 100, 100, 100]
reg= 0.0
std= 1e-2
learning_rates = [1e-4, 1e-5, 1e-6, 1e-7]

for lr in learning_rates:
    model = FullyConnectedNet(hidden_dims, reg= reg, weight_scale= std, normalization= None)
    solver = Solver(model, data, num_epochs = 10, batch_size = 200, update_rule= 'adam', lr_decay = 0.95,
                    optim_config= {'learning_rate': lr},
                    verbose = True, print_every= 1000)
    solver.train()
    val_acc = solver.check_accuracy(data['X_val'], data['y_val'])

    # 更新最佳模型
    if val_acc > best_val_acc:
        # 先删除之前的最佳模型,避免内存占用
        if best_model is not None:
            del best_model
        best_val_acc = val_acc
        best_model = model
        best_lr = lr
    else:
        # 不需要的模型直接删除
        del model

    # 斩断Solver对Model的引用,再删除Solver
    solver.model = None
    del solver

    # 强制触发垃圾回收
    gc.collect()

print("Best learning rate found to be: ", best_lr)

关键改动:

  • 先把solver.model设为None,切断Solver和Model之间的引用
  • 对不需要保留的Model直接del
  • 调用gc.collect()强制Python回收未使用的内存
方法2:用函数封装训练逻辑,利用作用域自动清理内存

Python的函数局部变量在函数执行结束后,引用计数会自动减少,垃圾回收更容易处理。把单个模型的训练逻辑封装到函数里:

import gc

def train_single_model(lr, hidden_dims, reg, std, data):
    model = FullyConnectedNet(hidden_dims, reg= reg, weight_scale= std, normalization= None)
    solver = Solver(model, data, num_epochs = 10, batch_size = 200, update_rule= 'adam', lr_decay = 0.95,
                    optim_config= {'learning_rate': lr},
                    verbose = True, print_every= 1000)
    solver.train()
    val_acc = solver.check_accuracy(data['X_val'], data['y_val'])
    return model, val_acc

best_model = None
best_val_acc = -1
hidden_dims = [100, 100, 100, 100, 100]
reg= 0.0
std= 1e-2
learning_rates = [1e-4, 1e-5, 1e-6, 1e-7]

for lr in learning_rates:
    model, val_acc = train_single_model(lr, hidden_dims, reg, std, data)
    if val_acc > best_val_acc:
        if best_model is not None:
            del best_model
        best_val_acc = val_acc
        best_model = model
        best_lr = lr
    else:
        del model
    gc.collect()

print("Best learning rate found to be: ", best_lr)

函数执行完后,里面的solver和临时变量会自动脱离作用域,引用计数归零,内存更容易被回收。

方法3:清理Solver内部的缓存数据

CS231n的Solver类会在训练过程中保存loss_history、train_acc_history等数组,如果这些数组很大,训练结束后没清理也会占用内存。可以给Solver加一个清理方法:

在cs231n/solver.py里的Solver类中添加:

def clear_cache(self):
    self.loss_history = []
    self.train_acc_history = []
    self.val_acc_history = []
    # 如果还有其他缓存的大数组,也在这里清空

然后在训练结束后调用:

solver.train()
val_acc = solver.check_accuracy(...)
solver.clear_cache()  # 清理缓存
solver.model = None
del solver

三、为什么第一个模型正常,后面变慢?

第一个模型训练时,系统内存充足,CPU/GPU可以高效执行;但后续模型训练时,内存被之前的模型数据占满,系统不得不使用磁盘swap空间(速度比内存慢几个数量级),导致代码执行速度骤降。这也是为什么不管换什么学习率,后续实例都会变慢——本质是内存不足导致的性能瓶颈,和学习率无关。

内容的提问来源于stack exchange,提问作者Ends of Invention

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:06:32