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.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 是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 resVariable的参数为“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.