在深度学习任务中,我们经常会遇到这样的场景:训练一个模型需要几十个小时甚至更长时间。这时候如果一直开着终端连接服务器,不仅占用本地电脑资源,还随时面临网络波动导致连接中断的风险。更糟糕的是,一旦终端断开,正在运行的程序也会跟着终止,几个小时的训练成果可能就白费了。
我刚开始做深度学习时就踩过这个坑。有一次训练一个图像分类模型,跑了8个小时后,因为地铁里网络不稳定导致SSH连接断开,所有进度都丢失了。后来我发现,screen和nohup这两个工具简直就是救命神器,它们可以完美解决终端依赖问题。
screen就像一个虚拟终端,它能在服务器上创建一个持久化的会话环境。即使你断开连接,这个会话也会继续运行。而nohup则能确保程序在后台运行,并且把输出日志保存到文件中。两者结合使用,就能打造一个"永动机"式的深度学习任务执行环境。
使用screen的第一步是创建一个新会话。登录服务器后,在终端输入:
bash复制screen -S my_training_session
这个命令会创建一个名为"my_training_session"的新会话。我习惯用有意义的名称,比如"resnet50_training"或者"bert_finetune",这样后面恢复时更容易识别。
创建后,你就进入了一个全新的screen会话。这时候可以像平常一样启动你的训练脚本:
bash复制python train.py --model=resnet50 --epochs=100
当你需要暂时离开但又不想终止训练时,可以按下Ctrl+A然后按D来"分离"(detach)当前会话。你会看到类似这样的提示:
bash复制[detached from 12345.my_training_session]
这表示会话已经在后台继续运行了。你可以安全地断开SSH连接,或者继续在服务器上做其他事情。
当你重新连接服务器后,可以通过以下命令查看所有活跃的screen会话:
bash复制screen -ls
输出可能长这样:
bash复制There are screens on:
12345.my_training_session (Detached)
67890.another_session (Detached)
要恢复之前的会话,使用:
bash复制screen -r my_training_session
如果你只运行了一个screen会话,可以直接用screen -r恢复,不用指定名称。
screen还有很多实用功能可以提升效率:
分屏功能:在screen会话中,你可以使用Ctrl+A然后|(竖线)进行垂直分屏,或者Ctrl+A然后S进行水平分屏。这在需要同时监控训练进度和GPU使用情况时特别有用。
会话共享:如果你需要和同事协作调试,可以使用screen -x来共享同一个会话。两个人都能看到相同的界面并实时交互。
日志记录:在启动screen时加上-L参数,它会自动记录所有输出到screenlog.0文件中。这对于后期分析训练过程很有帮助。
bash复制screen -L -S logging_session
虽然screen很强大,但有时候我们还需要nohup来配合使用。nohup的主要作用是让命令忽略挂断信号,并且可以把输出重定向到文件。最基本的用法是:
bash复制nohup python train.py > training.log 2>&1 &
这个命令做了几件事:
nohup确保命令不会因为终端断开而终止>把标准输出重定向到training.log文件2>&1把标准错误也重定向到标准输出&让命令在后台运行我建议总是使用完整的重定向格式,这样可以确保所有输出都被记录下来,方便后续排查问题。
启动nohup任务后,你可以用ps命令查看运行状态:
bash复制ps aux | grep train.py
这会显示类似这样的输出:
bash复制user 12345 0.0 0.1 123456 7890 ? S 10:00 0:10 python train.py
其中第二列就是进程ID(PID)。如果需要终止任务,可以使用:
bash复制kill -9 12345
要实时查看日志输出,可以使用:
bash复制tail -f training.log
-f参数会让tail持续显示文件新增的内容,非常适合监控训练进度。
在使用nohup时,可能会遇到几个常见问题:
找不到命令:如果你直接nohup train.py可能会报错。应该使用完整的解释器命令,比如nohup python train.py或者nohup bash script.sh。
权限问题:确保你的脚本有执行权限。可以用chmod +x script.sh添加权限。
输出文件位置:nohup默认会把输出写到当前目录的nohup.out文件中。如果你指定了输出文件,要注意路径是否正确。我建议总是使用绝对路径来避免混淆。
单独使用screen或nohup都能解决终端依赖问题,但它们各有优缺点:
screen:可以随时恢复交互式会话,适合需要偶尔查看或干预的训练过程。但如果服务器重启,screen会话会丢失。
nohup:更加轻量级,输出直接记录到文件,适合完全无人值守的运行。但缺乏交互性,出现问题时不方便调试。
将两者结合,就能发挥各自优势。我的标准做法是:在screen会话中使用nohup启动训练任务。这样既保留了交互能力,又确保了输出被可靠记录。
bash复制screen -S training_session
bash复制nohup python train.py > training.log 2>&1 &
Ctrl+A然后D)现在,你的训练任务既可以在后台持续运行,输出也被记录到文件,而且你随时可以重新连接screen会话来查看或干预。
即使有了双重保护,有时还是会出现意外情况。这里分享几个恢复技巧:
screen会话意外终止:如果发现screen会话不见了,可以尝试screen -D -r session_name强制恢复。
nohup任务中断:在screen会话中,可以使用fg命令将后台任务调回前台查看错误信息。
日志轮转:对于长时间运行的任务,建议设置日志轮转,避免单个文件过大:
bash复制nohup python train.py >> training_$(date +%Y%m%d).log 2>&1 &
这个命令会按日期创建日志文件,方便管理。
在管理多GPU训练任务时,screen和nohup的组合尤其有用。比如我们要在4块GPU上启动分布式训练:
bash复制screen -S multi_gpu_training
nohup python -m torch.distributed.launch --nproc_per_node=4 train.py > dist.log 2>&1 &
这样启动后,可以随时detach screen会话,训练会继续在后台进行。需要检查进度时,重新连接即可。
进行超参数搜索时,通常需要同时运行多个实验。这时可以为每个实验创建单独的screen会话:
bash复制for lr in 0.1 0.01 0.001; do
screen -S "experiment_lr_${lr}" -dm bash -c "python train.py --lr=${lr} > lr_${lr}.log 2>&1"
done
这个命令会创建三个后台screen会话,分别运行不同学习率的实验。-dm参数表示以detached模式直接启动会话。
对于需要运行数周的大型实验,我建议设置定期检查点,并在screen会话中监控关键指标:
bash复制screen -S long_term_experiment
python train.py --checkpoint-interval=24h
Ctrl+A然后|),在右侧运行监控命令:bash复制watch -n 60 nvidia-smi
这样左侧是训练输出,右侧实时显示GPU使用情况。可以随时detach,需要时再恢复查看。