变量
tensor变量:torch.tensor、torch.Tensor、Variable
1. torch.tensor(data) 是torch的一个函数,根据传入的data类型(比如是Long),生成对应的torch.LongTensor对象
2. torch.Tensor(data)是默认的Float对象,不管data是什么类型都会生成torch.FloatTensor
3. Variable是旧版本的torch.Tensor
tensor变量的声明与属性
1. 声明:
都用 torch.tensor(data, dtype=torch.float, device='cuda:0', requires_grad=False) 格式
2. 属性:
a.requires_grad 表示是否有跟踪梯度信息,自动求梯度
a.requires_grad_ 表示具体的梯度值
pipeline
- 基础模型,定义模型内部参数,定义模型前向传播方式: nn.Module, nn.Parameter(), forward()
- 定义损失函数和优化器
- loss是计算pred和true, criterion
- 优化器是定义梯度和参数如何更新,一般是 新参数=原参数-梯度x步长, optimizer
- 循环
- 前向传播 y' = model(x)
- 计算损失 loss = criterion(y', y)
- 梯度清零 optimizer.zero_grad() # 优化器里面的梯度清零,当前batch更新参数只用当前batch的梯度
- 反向传播 loss.backward() # 即根据计算图,计算每个参数的梯度,类似求导计算
- 梯度更新 optimizer.step() # 即根据优化器的类型,来更新参数
1. 训练的数据是不需要 requires_grad, 模型的参数是需要 requires_grad
train和eval和torch.no_grad()
- model.train()
- model.eval()
- with torch.no_grad()
在PyTorch中进行validation/test时,会使用model.eval()切换到测试模式,在该模式下:
1. 主要用于通知 dropout层 和 batchnorm层 在train和validation/test模式间切换
2. 在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p);
batchnorm层会继续计算数据的mean和var等参数并更新。
3. 在eval模式下,dropout层会让所有的激活单元都通过,而batchnorm层会停止计算和更新mean和var,
直接使用在训练阶段已经学出的mean和var值。该模式不会影响各层的gradient计算行为,
即gradient计算和存储与training模式一样,只是不进行反传(backprobagation)。
4. 而with torch.no_grad()则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用,具体行为就是停止gradient计算,
从而节省了GPU算力和显存,但是并不会影响dropout和batchnorm层的行为。
5. 如果不在意显存大小和计算时间的话,仅仅使用model.eval()已足够得到正确的validation/test的结果;
而with torch.no_grad()则是更进一步加速和节省gpu空间(因为不用计算和存储gradient),
从而可以更快计算,也可以跑更大的batch来测试。
item(), detach(), data(), cpu(), numpy()
- .item(), 只返回tensor变量中的值,且只返回一个值,不返回tensor,适用于计算loss后得到最终的loss具体数值
- .detach(), 返回值为tensor, 同时阻断反向传播, 即loss.backend()调用时,不计算使用了此函数的变量的梯度
- .data, 返回值为tensor, 不阻断反向传播,现在推荐使用 detach(), 更加安全,浅拷贝改变后反向会报错提醒
- .cpu(), 将数据从gpu转到cpu
- .numpy(), tensor转为numpy, 注意gpu上的变量只能是tensor
dataset和dataloader
- torch.utils.data.DataSet(), 需要定义好 `__getitem__`
- torch.utils.data.DataLoader(data, batch_size, shuffle, sampler, num_workers)
自定义数据集
1. 分别定义train和set的dataset和dataloader (已知trian和test分开情况下)
train_ds = dataset(train)
test_ds = dataset(test)
train_loader = dataloader(train_ds)
test_loader = dataloader(test_ds)
2. 利用sample进行划分,(随机划分), 用pytorch自带的sample, 如果用其他的,shuffle要设置为False
n_train = len(sentiment_train_set)
split = n_train // 3
indices = list(range(n_train))
train_sampler = torch.utils.data.sampler.SubsetRandomSampler(indices[split:])
valid_sampler = torch.utils.data.sampler.SubsetRandomSampler(indices[:split])
train_loader = DataLoader(sentiment_train_set, sampler=train_sampler, shuffle=False)
valid_loader = DataLoader(sentiment_train_set, sampler=valid_sampler, shuffle=False)
模型保存
1. 一般保存为 state_dict, 需要保存 net.state_dict() 和 optimizer.state_dict()
PATH = "state_dict_model.pt"
# save
torch.save(net.state_dict(), PATH)
# load
model = Net()
model.load_state_dict(torch.load(PATH))
model.eval()
2. checkpoint, 每个epoch都保存一次state_dict
3. different device model
- Save on GPU, Load on CPU
- Save on a GPU, load on a GPU
- Save on a CPU, load on a GPU
- Saving and loading DataParallel models
分布式训练
分为多卡多机分布式训练和多卡单机并行训练
- nn.DataParallel, 适用于多卡单机,即单机多GPU训练
基本流程:
1. replicate,复制module到多个device上
2. scatter,将input data按照first-dimension根据device数量进行划分
3. parallel_apply,将划分的data并行进行forward,
4. gather,按照first-dimension将各个device上的result进行汇总,然后计算整体loss
注意事项:
1. nn.DataParallel wrappe过的model,不能直接调用内部定义的函数,要用model.module.func来调用
2. 定义batch size时,注意和device数量结合,减少资源不协调
3. nn.DataParallel无法避免资源,因为是在master device进行分发,其他device仅并行计算,最后汇总和计算loss还是在master device
4. 使用nn.DataParallel后,记得调整batch size, 如果还是原来的batch size,比如100,只是把100分层几份来同时训练。时间反而会更久。如果是3个GPU,batch size应该改为300. 这样才利用上了nn.DataParallel。
5. nn.DataParallel速度可能还会变慢。。。。
- nn.distributed, 多卡多机和多卡单机都适用, 基本用这个
模型部署
- 基于flask接口:
1. 加载模型
2. 定义预处理函数
3. 定义 inference 函数
4. 定义接口整合上述函数