1 概述
1.1 写在前面
上一篇文章搞了一下WSL,但是只是用Ubuntu给texlive套了个壳,虽然texlive安装好就占了8.5个G(苦笑),还是感觉有点浪费这个系统。因为本人主要搞机器学习,所以又去研究了一下WSL能不能提升网络训练的速度,结果还真有up做过测试,可以看这个视频。训练mnist大概能节省一半的时间,这个提升还是挺有诱惑力的,于是花时间折腾了一下。
1.2 前置工作
- 安装WSL 2
- 安装Ubuntu 22.04
- 安装Windows Terminal(可选)
上述软件/工具的安装教程在我上一篇博客中已给出,地址是这里。
2 环境配置
系统版本:Windows 10 专业版 22H2 内部版本19045.4651
WSL:第2版
Linux子系统:Ubuntu 22.04.3 LTS
cuda驱动版本:12.2.138
cuda toolkit:12.1 for Linux WSL-Ubuntu 2.0 x86_64
cudnn:8.9.0 for cuda 12.x
python:3.10
pytorch:2.3.0+cu121
VSCode:1.91.0
尤其要注意cuda、toolkit、cudnn以及pytorch之间的版本对应关系,这个自己查吧,其实挺简单的。
3 安装流程
3.1 anaconda安装
3.1.1 anaconda下载
进入官网,选择最新版本anaconda下载
下载完成是一个后缀为.sh
的文件,我们将它移动到ubuntu的/home/username
文件夹下
打开文件资源管理器
,左侧侧栏最下方有个Linux
选项,这就是ubuntu系统的内部目录(十分的方便啊),找到对应路径,复制进去
3.1.2 安装anaconda
输入以下命令安装anaconda,注意版本是否一致
bash Anaconda3-2024.06-1-Linux-x86_64.sh
然后一直按着Enter
,过一下用户协议,输入yes
,接受协议,然后安装位置默认即可
是否初始化,输入yes
然后把当前shell关闭,重新启动一下,输入conda -V
测试是否正常输出版本号
3.1.3 创建虚拟环境
输入以下命令创建虚拟环境,用于安装pytorch
conda create -n torch230 python=3.10
激活环境,测试是否安装成功
3.2 cuda toolkit 安装与配置
3.2.1 cuda toolkit 安装
进入NVIDIA官网cuda toolkit对应版本的下载界面,选择Linux/X86_64/WSL-Ubuntu/2.0/deb[local]
依次复制以下命令进行安装
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/12.1.0/local_installers/cuda-repo-wsl-ubuntu-12-1-local_12.1.0-1_amd64.deb
sudo dpkg -i cuda-repo-wsl-ubuntu-12-1-local_12.1.0-1_amd64.deb
sudo cp /var/cuda-repo-wsl-ubuntu-12-1-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda
3.2.2 环境变量配置
输入sudo vim ~/.bashrc
,打开环境变量配置文件,将光标调到最后,添加以下两条环境变量
export PATH=/usr/local/cuda-12.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
输入source ~/.bashrc
命令,使环境变量立即生效。
配置完成之后,重新启动shell,执行nvcc -V
指令,检查是否安装成功
3.3 cudnn安装
3.3.1 下载对应版本的cudnn
进入NVIDIA官网cuda toolkit对应版本的下载界面,选择第二个下载
3.3.2 cudnn安装
cudnn没有严格意义上的安装过程,只需要将lib和include两个文件夹里的文件移动到对应路径即可
首先,将下载的cudnn压缩包移动到/home/username/
路径下,运行以下命令解压
sudo tar -xvf cudnn-linux-x86_64-8.9.0.131_cuda12-archive.tar.xz
进入解压后的目录,依次输入以下命令进行拷贝
cd cudnn-linux-x86_64-8.9.0.131_cuda12-archive/lib
sudo cp -r * /usr/local/cuda-12.1/lib64
cd ..
cd include
sudo cp -r * /usr/local/cuda-12.1/include
然后更改一下目录权限
sudo chmod a+r /usr/local/cuda-12.1/include/cudnn*
sudo chmod a+r /usr/local/cuda-12.1/lib64/libcudnn*
检查是否安装成功
cat /usr/local/cuda-12.1/include/cudnn_version.h | grep CUDNN_MAJOR -A 2
3.4 pytorch安装
进入pytorch官网,选择对应版本的安装命令
# 激活环境
conda activate torch230
# 安装pytorch
pip install torch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0 --index-url https://download.pytorch.org/whl/cu121
安装完成!
测试一下
import torch
print(torch.__version__)
print(torch.cuda.is_available())
完成!
3.5 vscode连接该环境
3.5.1 连接过程
打开vscode,按Ctrl+Shift+P
,打开命令输入框,输入wsl
,选择WSL: 在新窗口中连接到WSL
,vscode会自动连接完成配置
另外,为了在vscode中运行python代码,需要在扩展商店下载相关插件,包括isort、Python、Pylance、Python Debugger
,该过程耗时较长,需要多次重新加载窗口
。
3.5.2 mnist数据集测试
点击图中所示位置进行环境选择,选择torch230
环境
以下是pytorch官方的示例代码,仅修改了数据读取的工作线程数以及添加了时间统计。在ubuntu中新建mnist.py
文件,并复制粘贴该代码,使用命令python mnist.py
运行
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.optim.lr_scheduler import StepLR
import time
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout(0.25)
self.dropout2 = nn.Dropout(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2)
x = self.dropout1(x)
x = torch.flatten(x, 1)
x = self.fc1(x)
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1)
return output
def train(args, model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % args.log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
if args.dry_run:
break
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
def main():
# Training settings
parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
parser.add_argument('--batch-size', type=int, default=64, metavar='N',
help='input batch size for training (default: 64)')
parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
help='input batch size for testing (default: 1000)')
parser.add_argument('--epochs', type=int, default=14, metavar='N',
help='number of epochs to train (default: 14)')
parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
help='learning rate (default: 1.0)')
parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
help='Learning rate step gamma (default: 0.7)')
parser.add_argument('--no-cuda', action='store_true', default=False,
help='disables CUDA training')
parser.add_argument('--no-mps', action='store_true', default=False,
help='disables macOS GPU training')
parser.add_argument('--dry-run', action='store_true', default=False,
help='quickly check a single pass')
parser.add_argument('--seed', type=int, default=1, metavar='S',
help='random seed (default: 1)')
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
help='how many batches to wait before logging training status')
parser.add_argument('--save-model', action='store_true', default=False,
help='For Saving the current Model')
args = parser.parse_args()
use_cuda = not args.no_cuda and torch.cuda.is_available()
use_mps = not args.no_mps and torch.backends.mps.is_available()
torch.manual_seed(args.seed)
if use_cuda:
device = torch.device("cuda")
elif use_mps:
device = torch.device("mps")
else:
device = torch.device("cpu")
train_kwargs = {'batch_size': args.batch_size}
test_kwargs = {'batch_size': args.test_batch_size}
if use_cuda:
cuda_kwargs = {'num_workers': 5,
'pin_memory': True,
'shuffle': True}
train_kwargs.update(cuda_kwargs)
test_kwargs.update(cuda_kwargs)
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
dataset1 = datasets.MNIST('../data', train=True, download=True,
transform=transform)
dataset2 = datasets.MNIST('../data', train=False,
transform=transform)
train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)
model = Net().to(device)
optimizer = optim.Adadelta(model.parameters(), lr=args.lr)
scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma)
start_time = time.time()
for epoch in range(1, args.epochs + 1):
train(args, model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
scheduler.step()
end_time = time.time()
print(f"Total time taken: {end_time - start_time} seconds")
if args.save_model:
torch.save(model.state_dict(), "mnist_cnn.pt")
if __name__ == '__main__':
main()
3.5.3 踩坑及处理
运行mnist.py
报错Could not load library libcudnn_cnn_train.so.8. Error: /usr/local/cuda-12.1/lib64/libcudnn_cnn_train.so.8: undefined symbol: _ZN5cudnn3cnn5infer22queryClusterPropertiesERPhS3_, version libcudnn_cnn_infer.so.8
,这是由于使用pip命令安装pytorch2.3+cu121
时,默认会一起安装pytorch提供的cudnn,从而与我们前面安装的cudnn产生了冲突,解决方案有两个:
- 把我们自己安装的cudnn删掉,并注释掉环境变量(那我前面不是白干了,我可不受这委屈!)
- 把pytorch提供的cudnn卸载
这里介绍第二种,首先,输入命令pip list
可以看到,pytorch提供的cudnn是8.9.2.26
,与我们安装的8.9.0
是冲突的,我们可以使用命令pip uninstall nvidia-cudnn-cu12
卸载
随后再次进行测试
运行成功!
可以看到,运行时间为64秒,笔者自己测试在Windows上运行需要170秒,快了大约三倍,还是不错的。