DC的开发日志

欢迎阅读我的开发日志!我会在这里记录与软件工作相关的内容

PyTorch DataLoader在原生Windows和WSL下的性能对比

Windows下的num_workers > 0报错 在Windows下新搭建的PyTorch环境中使用之前的某个课程项目进行测试时,发现设置DataLoader的num_workers大于0会导致模型训练卡死。由于GPU无占用,在JupyterLab日志中找到形如AttributeError: Can't get attribute xxx on <module '__main__' (built-in)>的报错,最后定位到DataLoader上。 注意到不少回答都认为Windows下应该将num_workers设为0,但并未解释原因,实际测试发现训练过程远比进行课程项目时慢,于是进一步搜索希望能够找到更好的解决方法。 根据这个帖子的讨论以及这篇博客介绍,由于Windows多进程机制与Linux存在区别,Windows下multiprocessing不支持使用fork创建进程,而是只能通过spawn创建新的进程;这一点差异就导致导入模块时会使用模块锁,避免多个进程导入同一模块时产生竞争。 解决方案也很简单,将原来项目的内部类(是一个数据集类)放到一个外部文件/模块中,并在原来的代码中导入它。此时multiprocessing便可以正确加载该模块,确保模块只被加载一次,然后在各个进程之间共享。 Windows下的DataLoader性能问题 通过上一节的改动,DataLoader已经可以多线程地加载数据集了。但留意到增加worker数量并不能提升训练速度,CUDA核心占用依然出现间断,且间断时CPU和磁盘使用增加。可以推测认为是DataLoader加载速度跟不上训练速度,GPU经常停下来等待数据加载。 不过这也好理解:Linux下通过fork创建进程的效率显著高于Windows,在这个issue下的讨论也普遍认为Windows的进程机制拖慢了PyTorch的效率。 “那么具体一点,能不能衡量一下Windows拖慢了多少训练速度呢?”由于之前干过一段时间性能测试,这个问题马上冒了出来。好消息是在上面提到的这篇博客中,作者给出了ta测试DataLoader的代码。而我对课程项目的代码做了简单修改,作为附加的测试项目,希望能测试真实训练场景下的性能。 Windows与(Subsystem) Linux下DataLoader性能对比 测试环境 CPU:6核心12线程 内存:32GB GPU:显存16GB 操作系统: Windows 10 Ubuntu 22.04(以WSL运行) 软件: Python 3.10 PyTorch 2.2 CUDA 11.8 测试项目 上述博客中的MNIST数据集仅加载测试 num_workers从0至12以2递增 仅测试加载数据集的用时 课程项目的AlexNet训练-验证5个epoch 涉及加载train、validation两个数据集 每个epoch在train集上训练,并在validation集上验证 (项目写的比较挫,其他hyperparameter就不写出来丢人了,主要只是测加载用时的影响) 测试记录 测试项目1 num_workers WSL用时(s) Windows用时(s) 0 16.22 16.68 2 8.38 14.49 4 4.67 10.71 6 4.00 10.56 8 3.67 11.36 10 3.47 12.22 12 4.06 14....

February 4, 2024

WSL安装配置JupyterLab与CUDA

由于一个下篇文章会提到的性能问题,需要在WSL重新部署一套CUDA和JupyterLab环境,简单记录一下。 WSL 安装WSL组件 较新的Windows 10/11已经预装有WSL,只需要预先在BIOS中开启VT并在Windows控制面板中启用“Windows虚拟机监控程序平台”。 可以查看支持安装的Linux发行版,不过我这里是炼丹用,还是选Ubuntu了。 wsl --list --online wsl --install -d Ubuntu-22.04 在WSL中使用代理 这里使用了ZingLix的解决方案,用ta写的脚本配置环境变量,使用宿主机的HTTP代理。以下脚本的作者是@ZingLix,我只是在此引用并使用,感谢ta分享的这个好用的脚本 2024-02-24编辑: **注意:**使用. proxy.sh set或source proxy.sh set设置代理;假如使用bash执行脚本的话,环境变量不会被应用 #!/bin/sh hostip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }') wslip=$(hostname -I | awk '{print $1}') port=<host_proxy_port> PROXY_HTTP="http://${hostip}:${port}" set_proxy(){ export http_proxy="${PROXY_HTTP}" export HTTP_PROXY="${PROXY_HTTP}" export https_proxy="${PROXY_HTTP}" export HTTPS_proxy="${PROXY_HTTP}" } unset_proxy(){ unset http_proxy unset HTTP_PROXY unset https_proxy unset HTTPS_PROXY } test_setting(){ echo "Host ip:" ${hostip} echo "WSL ip:" ${wslip} echo "Current proxy:" $https_proxy } if [ "$1" = "set" ] then set_proxy elif [ "$1" = "unset" ] then unset_proxy elif [ "$1" = "test" ] then test_setting else echo "Unsupported arguments....

February 4, 2024

Windows安装CUDA

前置工作 升级显卡驱动 安装Visual Studio的桌面应用开发套件(选做?似乎不影响PyTorch) 安装CUDA PyTorch可能需要某个指定版本的CUDA,从官网的归档里可以下载到特定版本的安装包 一路下一步直到选择组件的步骤 选择组件时留意一下CUDA以外的组件版本号,安装包附带的其他组件可能并不是最新的,此种情况下则不覆盖安装旧版本其他组件了 勾选上CUDA,下一步 现在的CUDA安装包会自动配置好PATH,等安装完成后就基本没有需要手动操作的地方了。 验证安装 命令行执行以下命令查看安装的CUDA版本: nvcc --version 然后前往C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\demo_suite\(默认安装路径),在命令行运行deviceQuery.exe和bandwidthTest.exe。若测试结果均为PASS,则CUDA环境已经成功安装。

January 30, 2024

在两台PVE主机间迁移VM

家里有一台PVE主机打算换下来休息了,但上面还跑着2台要用的VM。PVE 7.3引入了迁移虚拟机的命令行工具,于是尝试使用qm来更方便的迁移虚拟机。 注意!源主机PVE版本需要高于7.3,否则不具备该功能 在目标主机上创建API令牌 在文件夹视图下找到“数据中心>权限>API令牌”,然后创建一个token,记得复制保留secret;然后在“数据中心>权限”处为刚刚创建的API令牌授权,需要给/路径赋予Administrator权限才能成功完成迁移。 若不授权的话,则执行迁移命令时会首先报remote: storage '<storage_name>' does not exist!,如果出现该问题的话首先检查是否忘记授权。 查看目标主机fingerprint 执行pvenode cert info,查看pve-ssl.pem的fingerprint并复制保留。 在源主机上执行迁移命令 执行命令: qm remote-migrate <source_vm_id> <target_vm_id> apitoken='Authorization: PVEAPIToken=root@pam!<token_name>=<token_secret>,fingerprint=<target_host_fingerprint>',host=<target_host>,port=<target_host_port> --target-bridge <target_bridge> --target-storage <target_storage> 静候即可。完成迁移后若需要解锁源VM,则运行qm unlock <source_vm_id>。 参考 qm(1) Framework for remote migration to cluster-external Proxmox VE hosts | Proxmox Support Forum [Tip] Proxmox VE Cross-Cluster Live-Migration - debianforum.de

January 30, 2024

JupyterLab安装配置

家里打游戏用的电脑闲着也是闲着,决定装上JupyterLab当自己的“GPU云”来用,简单记录下首次安装配置的过程 JupyterLab 直接通过pip安装了 py -3 -m pip install jupyterlab 配置JupyterLab 首先生成JupyterLab的配置文件 py -3 -m jupyter lab --generate-config 在用户主目录下会生成JupyterLab的目录和配置文件,我主要改了这几项 c.ServerApp.root_dir = '<path to jupyter home>' #放在新装的一块SSD上了,专门炼丹用 c.ServerApp.port = <port number> 运行JupyterLab py -3 -m jupyter lab --no-browser 使用虚拟环境 首先得创建虚拟环境 py -3 -m venv <venv name> 2024-02-05编辑: 然后进入这个虚拟环境,并使用ipykernel注册这个环境(可能需要通过pip安装ipykernel,根据实际环境/提示信息灵活处理) py -3 -m ipykernel install --user --name=<venv name> --display-name=<display name in jupyter> 随后在JupyterLab中就可以使用这个虚拟环境kernel了 查看kernel:py -3 -m jupyter kernelspec list 删除kernel:py -3 -m jupyter kernelspec remove <venv name>

January 27, 2024

PowerShell执行策略与Python报错

在Windows下使用PyCharm及JupyterLab的终端时现在默认使用PowerShell了,但尝试进入虚拟环境时会出现错误提示“在此系统上禁止运行脚本”。通过如下方式解决 解决方法 使用管理员身份运行PowerShell,执行命令Set-ExecutionPolicy RemoteSigned,根据提示输入Y并回车。 PowerShell执行策略 为了防止恶意脚本执行,PowerShell默认设置脚本执行为Restricted,此时可执行单条命令,但不能执行脚本。如果执行脚本——比如激活虚拟环境时执行activate.ps1,则会出现报错。PowerShell有以下几种执行策略(摘录自微软知识库): AllSigned 脚本可以运行。 要求所有脚本和配置文件都由受信任的发布者签名,包括在本地计算机上编写的脚本。 在运行来自尚未分类为可信或不可信的发布者的脚本之前,会提示你。 存在运行已签名的恶意脚本的风险。 Bypass 不阻止任何操作,并且没有任何警告或提示。 此执行策略专为将 PowerShell 脚本内置到较大应用程序中的配置或以 PowerShell 为具有自己的安全模型的程序的基础的配置而设计。 Default 设置默认执行策略。 Restricted(对于 Windows 客户端)。 RemoteSigned(对于 Windows 服务器)。 RemoteSigned Windows 服务器计算机的默认执行策略。 脚本可以运行。 需要受信任的发布者对从 Internet 下载的脚本和配置文件(包括电子邮件和即时消息程序)的数字签名。 在本地计算机上编写且不是从 Internet 下载的脚本不需要数字签名。 如果脚本已解除阻止(例如通过使用 Unblock-File cmdlet),则运行从 Internet 下载且未签名的脚本。 存在运行来自 Internet 以外来源的未签名脚本以及可能存在恶意的签名脚本的风险。 Restricted Windows 客户端计算机的默认执行策略。 允许单个命令,但不允许脚本。 阻止运行所有脚本文件,包括格式和配置文件 (.ps1xml)、模块脚本文件 (.psm1) 和 PowerShell 配置文件 (.ps1)。 Undefined 当前范围内没有设置执行策略。 如果所有范围内的执行策略均为 Undefined,则对于 Windows 客户端,有效执行策略为 Restricted;对于 Windows Server,有效执行策略为 RemoteSigned。 Unrestricted 非 Windows 计算机的默认执行策略,无法更改。 未签名的脚本可以运行。 存在运行恶意脚本的风险。 在运行非来自本地 Intranet 区域的脚本和配置文件之前警告用户。 参考 关于执行策略 - PowerShell

January 27, 2024

使用WinSCP脚本同步网站文件

平时常用的是Windows的笔记本,想一键把写好的博客同步到服务器上,但又懒得折腾cygwin装rsync(两端都是Linux的话rsync当然就是首选了),最后还是用WinSCP的脚本来实现文件同步。 获取会话URL 首先使用WinSCP登入到服务器,然后在工具栏标签页->生成会话URL/代码生成会话URL。这里至少需要勾选用户名和SSH主机密钥,其他项目任意。建议不勾选密码,在执行脚本时会提示输入密码验证。URL形如以下格式: sftp://<username>;fingerprint=ssh-<fingerprint>@<hostname>:<port>/ 编写WinSCP脚本 我的目的只是同步本地的静态网站文件到远程目录,所以脚本内容也很简单。 open sftp://<username>;fingerprint=ssh-<fingerprint>@<hostname>:<port>/ synchronize remote <local_path> <remote_path> -delete -criteria=either -transfer=binary exit 执行脚本 执行脚本时需要用到WinSCP.com,我安装在默认路径,可能需要根据实际情况修改。写成批处理就很简单了,不赘述。 "C:\Program Files (x86)\WinSCP\WinSCP.com" /ini=nul /script="<path_to_script>\sync.txt" 参考 Generate Session URL/Code/Transfer Code Dialog :: WinSCP Scripting and Task Automation :: WinSCP synchronize command :: WinSCP

January 18, 2024

Rocky Linux 8上手及遇到的问题

由于我打算把开发和技术相关的碎碎念从我的博客剥离出来,所以在本地重新安装了一套使用Rocky Linux的网站服务器——至于为什么是Rocky Linux而非Ubuntu Server,那我只能说我相比Ubuntu现在更情愿去用原装的Debian。 虽然之前有过一点CentOS使用经历(主要是7,同部门的另一套产品用的8),但毕竟自用的服务器一直是Ubuntu Server,在使用和部署服务过程中遇到了一些问题,在这里简单记录下。 网络配置 这个主要怪我自己太久没用忘记干净了,可以在/etc/sysconfig/network-scripts改Network Manager配置,也可以用nmtui引导式的修改。 SELinux相关 首先遇到的问题是在其他目录编写好的service文件执行systemctl daemon-reload后未被识别。解决如这个回答所述,需要将service文件的SELinux file label修正。 查看SELinux file label的方式为: ls -lhZ <file_name> 修正方式为: restorecon <file_name> 之后遇到的服务启动问题也是类似原因:service使用的程序未放置在SELinux信任的路径下,且文件的label也不正确。知道原因后修正就简单了。通过journalctl -xe查看日志能够提供比systemctl报错更有价值的信息。 Nginx Rocky下通过yum/dnf安装的Nginx默认配置文件在/etc/nginx下,但并非如Ubuntu一样根据类型分为数个目录。按照最简单的方式配置的话,对Nginx本身的修改丢在/etc/nginx/nginx.conf里,网站等配置按照*.conf格式命名后放在/etc/nginx/conf.d里。 Nginx的systemd报错提示作用同样有限,查看jounralctl -u nginx获得的信息会更有用,比如我就因为写错SSL文件路径导致网站没起来,看systemd报错愣是啥也没看出来。 未解决的问题:SoftEther VPN 为了之后更新网站方便,本打算直接将服务器接入自用的VPN,但始终未成功,不知道是vpnclient创建的TUN设备不兼容还是我的配置有问题;最后还是在已接入VPN的Ubuntu服务器上设置转发实现的VPN接入。 不知为何Ubuntu上就能直接给虚拟适配器配置IP,而Rocky 8则一直报连接或设备不兼容,问题详情与这个帖子相同。下面只简单记录下我创建连接的命令。 sudo nmcli connection add con-name se_vpn type tun ifname vpn_vpn ipv4.addresses x.x.x.x/x ipv4.method manual connection.autoconnect yes

January 16, 2024