记录一些课程实验中用到的功能,方便以后回顾
1. 数据准备部分
1.1 数据集划分
torch.utils.data.random_split(dataset, lengths)
eg:
train_dataset,test_dataset = random_split( dataset = dataset, lengths = [6,7])
其中dataset为Dataset类型的数据集,lengths为长度序列。如果希望每次得到相同的划分结果,则可以用torch.manual_seed()函数设置随机数种子。
如果自己新定义了数据集类,务必要重写__len__()方法,否则length会出错
参考自这篇博客
1.2 读取各个文件夹下的数据
os.listdir(path)
eg:
path = "../data/iris"
dirs = os.listdir( path )
有些数据集下载后的格式为多个以类别为名的文件夹,每个文件夹中是同一类的数据。但是在读取数据进行划分的时候,不得不将所有数据都放到一起划分训练集,这就需要用到os.listdir()方法。
listdir()的参数是目标文件夹,该方法会返回path文件夹中的文件或文件夹列表【注意不带前缀,如../data/iris/1文件夹在返回值中为1,因此往往需要结合os.join()方法】
# 应用举例
labels = []
dir_path = "../data/101_ObjectCategories/"
for path in os.listdir(dir_path):
path_name = os.path.join(dir_path, path)
for name in os.listdir(path_name):
file_name = os.path.join(path_name, name)
labels.append(label)
2. 模型部分
2.1 model.train()的作用
在进行模型训练时,有时会看到代码中出现model.train()。该方法的作用是启用 batch normalization 和 dropout ,如果在训练中用到这技巧,就要在训练之前来一行.train()。
相对的,如果要进行测试,需要关闭BN和Dropout,则需要在测试前调用model.eval()。
参考这篇博客
2.2 dropout()的用法
dropout让节点以概率p不激活【表现为对应值取0】,可以减少训练量,并降低过拟合的可能性。
通常dropout用在一层网络的定义之后,如下所示:
self.net = nn.Sequential(
nn.Linear(128 * 6 * 6, 512),
nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(512, 256),
nn.ReLU(),
nn.Linear(256, 101)
)
2.3 loss.item()
进行模型训练的时候通常还会计算训练的损失,此时就会用到.item()方法,其效果是将一个tensor类型的值转为python的基本数据类型,如果是多个值则需要用.tolist()方法。
此外,计算loss时已经自动对batch_size个数据求过平均了,因此如果是算训练误差还需要将batch_size【即代码中的img.size(0)】乘回来
loss = lossfunc(outputs, label)
# 反向传播求梯度
loss.backward()
# 更新所有参数
optimizer.step()
# item()将单个的tensor类型转为python基本数据类型,多个要用tolist()
# 为什么要乘img.size(0)——计算loss时自动求了平均,乘上batch_size即img.size(0)还原为总损失
train_loss += loss.item() * img.size(0)
train_count += img.size(0)
参考这篇博客
2.4 GPU运行时out of memory
在用cuda跑VGG11时,在train中的output = model(image) 处出现了报错,提示CUDA out of memory。
初步尝试:
首先尝试减小batch_size,可是从64减到16,还是提示报错。
第二次尝试:
然后参考这篇博客,在output = model(image)之前加入了一句,变成了如下的结果:
with torch.no_grad(): # 添加这行代码
output = model(images) # 再缩进这行
# output = model(images)
此时不再报out of memory的错误,但是出现了另外的错,RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
第三次尝试:
在查看这篇博客 时,发现了解决办法,在原先计算loss之后加入一句loss.require_grad_(True),这样就成功跑起来啦!
大概的原因是,原先这里需要求梯度,但是用了with torch.no_grad()后显示地关闭了梯度的求解。
with torch.no_grad(): # 添加这行代码
output = model(images) # 再缩进这行
loss = loss_func(output, labels).to(device)
loss.requires_grad_(True) # try
2.5 交叉熵损失函数
交叉熵损失函数nn.CrossEntropyLoss(pred, label)对pred和label有维度的要求,具体可参考这篇博客。