# 当用cuda 生成feature时,又用dataloader 多线程加载数据集时,需要添加 下面函数。否则pytorch 会出错。
import multiprocessing as mp
mp.set_start_method('spawn')
如果数据集是 numpy 格式,可以通过 np.any(np.isnan(x)) 来判断是否有 nan,即:
assert not np.any(np.isnan(x)),'nan exists!'
如果是数据集是torch.tensor格式,可以通过torch.any(torch.isnan(x)) 来判断是否有nan
assert not torch.any(torch.isnan(x)),'nan exists!'
1) 学习率太高,
2) loss函数不合适,
3) 数据本身,是否存在Nan
4) target本身应该是能够被loss函数计算的
注意几点:
x = torch.clip(x, -1+1e-6, 1-1e-6)
y = torch.acos(x)
z = 1/(y+1e-6)
w = torch.inv(z)
"""
此处只限于pytorch 的使用
默认mask 里面 是 1:有效值得位置,0:无效值的地方
- check_mask_valid(mask): 检查mask里面是否全为0,如果全为0,则整个预测结果也无效,没必要计算loss
- maskNLLLoss(pred, target, mask): 带mask的交叉熵损失,如果mask 全为0,则返回带梯度的tensor(0., requres_grad=True)
- calAcc(pred, target, mask): 带mask的ACC,如果mask全为0, 则返回1。(这里不需要梯度)
"""
def check_mask_valid(mask):
# 检查 mask是否全为0, 如果全为0, 则说明整个target 都是无效的
if torch.sum(mask.float()).item() == 0:
return False
else:
return True
def maskNLLLoss(pred, target, mask):
# 返回的loss 必须是一个带梯度的tensor,因为train函数里面要做loss.backward()
if not check_mask_valid(mask):
return torch.tensor(0., requres_grad=True)# 如果mask全为0,则值无效,loss 返回为0,这里最好返回一个tensor并且带有grad,不然backward时 会出问题
target1hot = torch.nn.functional.one_hot(target.long(), pred.shape[1]).permuate(0,3,1,2).float()# B*C*H*W
crossEntropy = -torch.log((target1hot * pred).sum(dim=1) + 1e-6) * mask.float()# B*C*H*W
loss = crossEntropy.sum()/ mask.float().sum()
return loss
def calAcc(pred, target, mask):
# 返回的acc 可以是一个tensor 也可以是一个数值,因为acc不需要backward(),只是记录值
if not check_mask_valid(mask):
return 1
pred_ = torch.argmax(pred, dim=1)
equal = torch.eq(pred_.float(), target.float()).float()
masked_equal = equal * mask.float()
acc = torch.sum(masked_equal) / torch.sum(mask.float())
return acc.item()
Focal loss
"""
设置梯度累积参数acc_freq,在每次得到loss后,都要做一次 loss/acc_freq,不然一次性optimize.step()时会因为梯度太大而导致训练异常
if acc_freq > 0:# 梯度累积
loss = loss/acc_freq # 除以累积次数
"""
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, SubsetRandomSampler
import torch.optim as optim
val_split = 0.2
acc_freq = 4
# 数据集准备阶段
dataset = MyDataset()
dataset_size = len(dataset)
indices = list(range(dataset_size))
split = int(np.floor(val_split * dataset_size))
if shuffle_dataset:
np.random.seed(random_seed)
np.random.shuffle(indices)
train_indices, val_indices = indices[split:], indices[:split]
train_sampler = SubsetRandomSampler(train_indices)
valid_sampler = SubsetRandomSampler(val_indices)
train_loader = DataLoader(dataset, batch_size=4, sampler=train_sampler, num_workers=2)
# 模型准备阶段
lr = 1e-4
weight_decay = 0.2
Model = Model()
optimizer = torch.optim.Adam(model.parameters(), weight_decay=weight_decay, lr=lr)
# 训练阶段
def train():
for epoch in range(total_epoch):
for batch, (features, labels, mask) in enmuerate(train_loader):
pred = Model(features) # 预测
loss = loss_fn(pred, labels, mask) # 计算loss
acc = cal_acc(pred, labels, mask) # 计算acc
if acc_freq > 0:# 梯度累积
loss = loss/acc_freq # 除以累积次数
loss.backward()# 计算梯度
if (batch+1) % acc_freq == 0:
optimizer.step() # 反向传播
optimizer.zero_grad() # 清空梯度 非常重要(只要做optimizer.step(),就要接着zero_grad())
# update loss and acc
# save model
学习pytorch