torch.optim是一个实现了各种优化算法的库。大部分常用的方法得到支持,并且接口具备足够的通用性,使得未来能够集成更加复杂的方法。
为了构建一个Optimizer,你需要给它一个包含了需要优化的参数(必须都是Variable对象)的iterable。然后,你可以设置optimizer的参 数选项,比如学习率,权重衰减,等等。
optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr = 0.0001)
#
optim.SGD([
{'params': model.base.parameters()},
{'params': model.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
#这意味着model.base的参数将会使用1e-2的学习率,model.classifier的参数将会使用1e-3的学习率,并且0.9的momentum将会被用于所 有的参数。
进行单次优化:所有的optimizer都实现了step()方法,这个方法会更新所有的参数。它能按两种方式来使用:
optimizer.step()
这是大多数optimizer所支持的简化版本。一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数。
load_state_dict(state_dict) [source]:加载optimizer状态,state_dict (dict) —— optimizer的状态。应当是一个调用state_dict()所返回的对象。
zero_grad() [source]:清空所有被优化过的Variable的梯度.
torch.utils.data:class torch.utils.data.Dataset
表示Dataset的抽象类。
class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
参数:
dataset (Dataset) – 加载数据的数据集。
batch_size (int, optional) – 每个batch加载多少个样本(默认: 1)。
shuffle (bool, optional) – 设置为True时会在每个epoch重新打乱数据(默认: False).
sampler (Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数。
num_workers (int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认: 0)
collate_fn (callable, optional) –
pin_memory (bool, optional) –
drop_last (bool, optional) – 如果数据集大小不能被batch size整除,则设置为True后可删除最后一个不完整的batch。如果设为False并且数据集的大小不能被batch size整除,则最后一个batch将更小。(默认: False
torchvision包
包含了目前流行的数据集,模型结构和常用的图片转换工具。
torchvision.datasets中包含了以下数据集
MNIST
COCO(用于图像标注和目标检测)(Captioning and Detection)
LSUN Classification
ImageFolder
Imagenet-12
CIFAR10 and CIFAR100
STL10
torchvision.models模块的 子模块中包含以下模型结构。
AlexNet
VGG
ResNet
SqueezeNet
DenseNet You can construct a model with random weights by calling its constructor:
pytorch torchvision transform:对PIL.Image进行变换
class torchvision.transforms.Compose(transforms)
多个transform组合起来使用。
class torchvision.transforms.CenterCrop(size)
将给定的PIL.Image进行中心切割,得到给定的size,size可以是tuple,(target_height, target_width)。size也可以是一个Integer,在这种情况下,切出来的图片的形状是正方形。
class torchvision.transforms.RandomCrop(size, padding=0)
切割中心点的位置随机选取。size可以是tuple也可以是Integer。
class torchvision.transforms.RandomHorizontalFlip
随机水平翻转给定的PIL.Image,概率为0.5。即:一半的概率翻转,一半的概率不翻转。
class torchvision.transforms.RandomSizedCrop(size, interpolation=2)
先将给定的PIL.Image随机切,然后再resize成给定的size大小。
class torchvision.transforms.Pad(padding, fill=0)
将给定的PIL.Image的所有边用给定的pad value填充。 padding:要填充多少像素 fill:用什么值填充 例子:
对Tensor进行变换
class torchvision.transforms.Normalize(mean, std)
给定均值:(R,G,B) 方差:(R,G,B),将会把Tensor正则化。即:Normalized_image=(image-mean)/std。
class torchvision.transforms.ToTensor
把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloadTensor
data = np.random.randint(0, 255, size=300)
img = data.reshape(10,10,3)
print(img.shape)
img_tensor = transforms.ToTensor()(img) # 转换成tensor
print(img_tensor)
class torchvision.transforms.ToPILImage
将shape为(C,H,W)的Tensor或shape为(H,W,C)的numpy.ndarray转换成PIL.Image,值不变。
argparse基本用法
argparse 是python自带的命令行参数解析包,可以用来方便地读取命令行参数。它的使用也比较简单。
import argparse
def main():
parser = argparse.ArgumentParser(description="Demo of argparse")
parser.add_argument('-n','--name', default=' Li ')
parser.add_argument('-y','--year', default='20')
args = parser.parse_args()
print(args)
name = args.name
year = args.year
print('Hello {} {}'.format(name,year))
if __name__ == '__main__':
main()
在上面的代码中,我们先导入了argparse这个包,然后包中的ArgumentParser类生成一个parser对象(好多博客中把这个叫做参数解析器),其中的description描述这个参数解析器是干什么的,当我们在命令行显示帮助信息的时候会看到description描述的信息。
接着我们通过对象的add_argument函数来增加参数。这里我们增加了两个参数name和year,其中’-n’,’–name’表示同一个参数,default参数表示我们在运行命令时若没有提供参数,程序会将此值当做参数值。执行结果如上图所示。
最后采用对象的parse_args获取解析的参数,由上图可以看到,Namespace中有两个属性(也叫成员)这里要注意个问题,当’-‘和’–'同时出现的时候,系统默认后者为参数名,前者不是,但是在命令行输入的时候没有这个区分接下来就是打印参数信息了。
当执行命令python fun_test.py -h可以查看帮助信息
load_state_dict的问题:
主要参考这篇佳作:
state_dict = torch.load('checkpoint.pt') # 模型可以保存为pth文件,也可以为pt文件。
from collections import OrderedDict
new_state_dict = OrderedDict()
for k, v in state_dict.items():
name = k[7:] # remove `module.`,表面从第7个key值字符取到最后一个字符,正好去掉了module.
new_state_dict[name] = v #新字典的key值对应的value为一一对应的值。
model.load_state_dict(new_state_dict) # 从新加载这个模型。
最简单的方法,加载模型之后,接着将模型DataParallel,此时就可以load_state_dict。
model = VGG()# 实例化自己的模型;
checkpoint = torch.load('checkpoint.pt', map_location='cpu') # 加载模型文件,pt, pth 文件都可以;
if torch.cuda.device_count() > 1:
# 如果有多个GPU,将模型并行化,用DataParallel来操作。这个过程会将key值加一个"module. ***"。
model = nn.DataParallel(model)
model.load_state_dict(checkpoint) # 接着就可以将模型参数load进模型。
map() 会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
def add20(number):
number = number+20
return number
list1 = [1,2,3]
newlist = map(add20,list1)
print(list(newlist))
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
ignored_params = list(map(id, vgg16.module.classifier.parameters())) #layer need to be trained
base_params = filter(lambda p: id(p) not in ignored_params, vgg16.module.parameters())
optimizer.step()这是大多数optimizer所支持的简化版本。一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数。
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
使用torch.optim.lr_scheduler()函数
def adjust_learning_rate(optimizer, epoch):
"""Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
lr = args.lr * (0.1 ** (epoch // 50))
param_groups = optimizer.state_dict()['param_groups']
param_groups[0]['lr']=lr
param_groups[1]['lr']=lr*10
# for param_group in param_groups:
# print param_group
# param_group['lr'] = lr
在train函数中采用自定义的AverageMeter类来管理一些变量的更新。在初始化的时候就调用的重置方法reset。当调用该类对象的update方法的时候就会进行变量更新,当要读取某个变量的时候,可以通过对象.属性的方式来读取
在训练开始之前写上model.trian(),在测试时写上model.eval()。然后自己写的时候也就保留了这个习惯,没有去想其中原因。如果模型中有BN层(Batch Normalization)和Dropout,需要在训练时添加model.train(),在测试时添加model.eval()。其中model.train()是保证BN层用每一批数据的均值和方差,而model.eval()是保证BN用全部训练数据的均值和方差;而对于Dropout,model.train()是随机取一部分网络连接来训练更新参数,而model.eval()是利用到了所有网络连接。
model.train() :
启用 BatchNormalization 和 Dropout
model.eval() :
不启用 BatchNormalization 和 Dropout
训练完训练(train)样本之后,使用训练好的模型验证测试(test)样本,需要在之前加上model.eval(),否则只要输入数据,即使不训练,模型也会改变权值。使用model.eval()时,框架会自动把BN(BatchNorm)和DropOut固定住,不会取平均,而是用训练好的值。
用time来计算一下程序执行的时间:
准确率计算:
def accuracy(output, target, topk=(1,)):
"""Computes the precision@k for the specified values of k"""
maxk = max(topk)
batch_size = target.size(0)
_, pred = output.topk(maxk, 1, True, True)
pred = pred.t()
correct = pred.eq(target.view(1, -1).expand_as(pred))
res = []
for k in topk:
correct_k = correct[:k].view(-1).float().sum(0)
res.append(correct_k.mul_(100.0 / batch_size))
return res
Variable的参数为“requires_grad”和“grad_fn”:
(1)requires_grad的值为:True和False,True代表tensor变量需要计算梯度,False代表不需要。默认值为False。
(2)grad_fn的值该变量是否是一个计算结果,即该变量是不是一个函数的输出值。若是,则grad_fn返回一个与该函数相关的对象,否则是None。
Autograd: 自动微分
autograd包是PyTorch中神经网络的核心, 它可以为基于tensor的的所有操作提供自动微分的功能, 这是一个逐个运行的框架, 意味着反向传播是根据你的代码来运行的, 并且每一次的迭代运行都可能不同.
optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0.