OpenMMLab实战营第三课 图像分类代码实战与超算平台介绍

Pytorch简单代码结构展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

# Download training data from open datasets.
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)

# Download test data from open datasets.
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)
batch_size = 64

# Create data loaders.
train_dataloader = DataLoader(training_data, batch_size=batch_size)
test_dataloader = DataLoader(test_data, batch_size=batch_size)

for X, y in test_dataloader:
print(f"Shape of X [N, C, H, W]: {X.shape}")
print(f"Shape of y: {y.shape} {y.dtype}")
break

# Get cpu or gpu device for training.
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

# Define model
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10)
)

def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits

model = NeuralNetwork().to(device)
print(model)
## Define loss funtion and Optimizer
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)

def train(dataloader, model, loss_fn, optimizer):
size = len(dataloader.dataset)
model.train()
for batch, (X, y) in enumerate(dataloader):
X, y = X.to(device), y.to(device)

# Compute prediction error
pred = model(X)
loss = loss_fn(pred, y)

# Backpropagation
optimizer.zero_grad()
loss.backward()
optimizer.step()

if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")


def test(dataloader, model, loss_fn):
size = len(dataloader.dataset)
num_batches = len(dataloader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in dataloader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_fn(pred, y).item()
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")

# Saving Models
torch.save(model.state_dict(), "model.pth")
print("Saved PyTorch Model State to model.pth")
# Deployment
# loading Models
model = NeuralNetwork()
model.load_state_dict(torch.load("model.pth"))
#Predict new images
classes = [
"T-shirt/top",
"Trouser",
"Pullover",
"Dress",
"Coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
]
#没有归一化
model.eval()
x, y = test_data[0][0], test_data[0][1]
with torch.no_grad():
pred = model(x)
predicted, actual = classes[pred[0].argmax(0)], classes[y]
print(f'Predicted: "{predicted}", Actual: "{actual}"')

OpenMMLab里是怎么做的

OpenMMLab 项目中的重要概念--配置文件 比pytorch更简单的的方式 通过它OpenMMLab可以还原回pytorch代码

深度学习模型的训练涉及几个方面:

  • 模型结构模型 有几层、每层多少通道数等等
  • 数据集 用什么数据训练模型:数据集划分、数据文件路径、数据增强策略等等
  • 训练策略 梯度下降算法、学习率参数、batch size训练总轮次、学习率变化策略等等
  • 运行时 GPU、分布式环境配置等等
  • 一些辅助功能 如打印日志、定时保存checkpoint等等

一些问题和回答整理

只记录了一些我感兴趣的问题和回答(并不是原话经过整理)

问题: 输入图片的尺寸可以不固定吗?

回答: 对于早期的存在全链接层的卷积神经网络必须 输入图像是固定的,而后续一些下经网络(如ResNet)用了全局平均池化 ,代替了全连接层所以不限制图像尺寸。

问题: 神经网络也需要像人一样使用多种感官感知吗?

回答: 为了更好感知信息神经网络确实需要这样的策略 如多模态学习。

问题: 出现分类错误 如何修改错误?

回答: 可以通过可解释学习 来了解 程序哪里出了错。

超算平台应用(北京超级云计算中心)

登录官网下载客户端

利用云桌面平台

先用ssh 选择合适的分区(N30分区)

界面目录 cd run 分配了300G内存

查看模块

module avail

搭建环境

创建环境

module load anaconda/2021.05

conda create --name mmclassification python=3.8

激活环境

source activate mmclassification

加载cuda/11.1

module load cuda/11.1

安装pytorch 通过pip安装CUDA不能低于 11.1 不推荐用conda装

1
pip install torch==1.10.0+cu111 torchvision==0.11.0+cu111 torchaudio==0.10.0 -f https://download.pytorch.org/whl/torch_stable.html

安装 mmcv-full 模块,mmcv-full 模块安装时候需要注意 torch 和 cuda 版本。参考这里

1
2
pip install mmcv-full==1.7.0 -f
https://download.openmmlab.com/mmcv/dist/cu111/torch1.10/index.html

安装 openmmlab/mmclassification 模块,建议通过下载编译的方式进行安装;安装该模块需要 gcc ≥ 5,使用 module 加载一个 gcc ,例如 module load gcc/7.3

1
2
3
4
5
6
7
8
9
# 加载 gcc/7.3 模块
module load gcc/7.3

# git 下载 mmclassification 代码
git clone https://github.com/openmmlab/mmclassification.git

# 编译安装
cd mmclassification
pip install -e .

总结环境信息,可以使用 module list 查看当前环境中加载的依赖模块,如下:

module list

准备 shell 脚本,将环境信息预先保存在脚本中。

1
2
3
4
5
6
7
8
#!/bin/bash
# 加载模块
module load anaconda/2021.05
module load cuda/11.1
module load gcc/7.3

# 激活环境
source activate mmclassification

使用快传传输本地数据集到超算 创建data目录存放

划分数据集

自己写的脚本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import os
import random
import shutil

def mymkdir(file):
if not os.path.exists(file):
os.mkdir(file)


def getData(dirPath):
subDirs=os.listdir(dirPath)
mymkdir(os.path.join(dirPath,'data'))
destdir=os.path.join(dirPath,'data','val')
mymkdir(destdir)
destdir2=os.path.join(dirPath,'data','train')
mymkdir(destdir2)
for dir in subDirs:
tempDir=os.path.join(dirPath,dir)
destdirnow=os.path.join(destdir,dir)
destdirnow2=os.path.join(destdir2,dir)
mymkdir(destdirnow)
mymkdir(destdirnow2)
fs=os.listdir(tempDir)
random.shuffle(fs)
le=int(len(fs)*0.8) #这个可以修改划分比例
for f in fs[le:]:
shutil.move(os.path.join(tempDir,f), destdirnow)
for f in fs[:le]:
shutil.move(os.path.join(tempDir,f), destdirnow2)



#print(os.path.join(os.getcwd(),'flower_dataset'))
getData(os.path.join(os.getcwd(),'flower_dataset'))


MMCls 配置文件

mkdir configs/resnet18

cp ~/run/opnemmlab/resnet18_b32_flower.py ./configs/resnet18/

按要求修改配置文件

提交计算

准备作业脚本

取消计算

scancel 279704 # 279704 为作业ID

查看GPU利用率

在提交作业之后,使用 parajobs 或 squeue 查看作业的第八列 NODELIST(REASON)对于运行作业(R状态)显示作业使用的节点列表

squeue

查看到使用的节点列表之后,使用 ssh [节点] 进入GPU环境,执行 nvidia-smi 可查看 GPU 利用率。

ssh g0004 #g0004节点

nvidia-smi