实际上,很少有人从头开始训练整个卷积网络(使用随机初始化),因为拥有足够大小的数据集相对很少。 相反,通常在非常大的数据集上对 ConvNet 进行预训练(例如 ImageNet,其中包含 120 万个具有 1000 个类别的图像),然后将 ConvNet 用作初始化或固定特征提取器以完成感兴趣的任务。
https://cs231n.github.io/transfer-learning/

三种主要的转移学习方案:

  • 对卷积网络进行微调:代替随机初始化,我们使用经过预训练的网络初始化网络,例如在 imagenet 1000 数据集上进行训练的网络。 其余的训练照常进行。

ConvNet作为固定特征提取器

ConvNet作为固定特征提取器。采取在ImageNet上进行预训练的ConvNet,删除最后一个完全连接的层(该层的输出是针对像ImageNet这样的不同任务的1000类分数),然后将其余的ConvNet视为新数据集的固定特征提取器,冻结除所有网络的权重。最后一个完全连接的层将替换为具有随机权重的新层,并且仅训练该层。

在AlexNet中,会直接为隐藏层激活的图像计算4096-D向量,在分类器之前。我们称这些功能为CNN代码。

如果在ImageNet上的ConvNet训练期间也对CNN代码进行了阈值处理(通常是这样),则这些代码将被ReLUd(in other words 阈值设置为零),对于性能而言很重要。为所有图像提取4096-D向量后,为新数据集训练线性分类器(例如,线性SVM或Softmax分类器)。

微调ConvNet

第二种策略不仅是在新数据集的ConvNet上替换和重新训练分类器,而且还要通过继续进行反向传播来微调预训练网络的权重。可以对ConvNet的所有层进行微调,也可以使某些较早的层保持固定(由于过度拟合的考虑),而仅对网络的某些较高层进行微调。这是由于观察到的结果是,ConvNet的早期feature包含更多的通用feature(例如,边缘检测器或色斑检测器),这些feature应该对许多任务有用,但是后来,ConvNet的各层逐渐变得更具体地针对类别的细节

预训练模型

别人生成的最终的ConvNet checkpoints ,这可以使其他可以使用网络进行微调的人受益。例如,Caffe库有一个模型zoo,人们可以在其中共享网络权重。

迁移学习的选择思路四类:

  • 1、新数据集很小,与原始数据集相似。由于数据量很小,由于过度拟合的问题,微调ConvNet并不是一个好主意。由于数据与原始数据相似,因此我们希望ConvNet中的高级feature也与此数据集相关。因此,最好的想法可能是在CNN码上训练线性分类器。
    Hence, the best idea might be to train a linear classifier on the CNN codes.

  • 2、新数据集很大,并且与原始数据集相似。由于我们拥有更多的数据,因此,如果我们尝试通过整个网络进行微调,我们将更有信心不会过拟合。

  • 3、新数据集很小,但与原始数据集有很大不同。由于数据很小,因此最好只训练线性分类器。由于数据集非常不同,因此最好不要从网络顶部训练分类器,该网络包含更多特定于数据集的功能。取而代之的是,从网络中较早的某个位置进行激活来训练SVM分类器可能会更好。 Instead, it might work better to train the SVM classifier from activations somewhere earlier in the network.

  • 4、新数据集很大,并且与原始数据集有很大不同。由于数据集非常大,我们可以期望我们有能力从头开始训练ConvNet。但是,在实践中,使用预训练模型中的权重进行初始化通常仍然是有益的。在这种情况下,我们将有足够的数据和信心来调整整个网络。

迁移学习时,需要记住一些其他事项:

来自预训练模型的约束。
请注意,如果您希望使用预训练的网络,则在可用于新数据集的体系结构方面可能会受到一些限制。
例如,您不能从预先训练的网络中任意提取转化层。
但是,有些更改很简单:由于参数共享,您可以轻松地在不同空间大小的图像上运行经过预训练的网络。
这在Conv / Pool层的情况下很明显,因为它们的前向功能与输入体积的空间大小无关(只要跨度“合适”即可)。 对于FC层,这仍然成立,因为FC层可以转换为卷积层:例如,在AlexNet中,第一个FC层之前的最终合并卷的大小为[6x6x512]。 因此,看着该体积的FC层等效于具有一个卷积层,该卷积层的接收场大小为6x6,并且填充值为0。

学习率。
通常,对于经过微调的ConvNet权重使用较小的学习率,与新线性分类器(随机初始化)的权重相比(新线性分类器计算新数据集的类分数)。这是因为我们期望ConvNet权重相对较好,所以我们不希望它们过快或过分失真(尤其是在从随机初始化中训练新的线性分类器时)。

4. 很小的数据集的迁移学习实践——微调ConvNet/ConvNet 作为固定特征提取器

下载数据,并将其提取到当前目录

# Data augmentation and normalization for training
# Just normalization for validation
data_transforms = {'train': transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),'val': transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
}data_dir = 'data/hymenoptera_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x])for x in ['train', 'val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,shuffle=True, num_workers=4)for x in ['train', 'val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
class_names = image_datasets['train'].classesdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

可视化一些图像


def imshow(inp, title=None):"""Imshow for Tensor."""inp = inp.numpy().transpose((1, 2, 0))mean = np.array([0.485, 0.456, 0.406])std = np.array([0.229, 0.224, 0.225])inp = std * inp + meaninp = np.clip(inp, 0, 1)plt.imshow(inp)if title is not None:plt.title(title)plt.pause(0.001)  # pause a bit so that plots are updated# Get a batch of training data
inputs, classes = next(iter(dataloaders['train']))# Make a grid from batch
out = torchvision.utils.make_grid(inputs)imshow(out, title=[class_names[x] for x in classes])

编写一个通用函数来训练模型

现在,让我们编写一个通用函数来训练模型。 在这里,我们将说明:

  • 安排学习率
  • 保存最佳模型

以下,参数scheduler是来自torch.optim.lr_scheduler的 LR 调度程序对象。

def train_model(model, criterion, optimizer, scheduler, num_epochs=25):since = time.time()best_model_wts = copy.deepcopy(model.state_dict())best_acc = 0.0for epoch in range(num_epochs):print('Epoch {}/{}'.format(epoch, num_epochs - 1))print('-' * 10)# Each epoch has a training and validation phasefor phase in ['train', 'val']:if phase == 'train':model.train()  # Set model to training modeelse:model.eval()   # Set model to evaluate moderunning_loss = 0.0running_corrects = 0# Iterate over data.for inputs, labels in dataloaders[phase]:inputs = inputs.to(device)labels = labels.to(device)# zero the parameter gradientsoptimizer.zero_grad()# forward# track history if only in trainwith torch.set_grad_enabled(phase == 'train'):outputs = model(inputs)_, preds = torch.max(outputs, 1)loss = criterion(outputs, labels)# backward + optimize only if in training phaseif phase == 'train':loss.backward()optimizer.step()# statisticsrunning_loss += loss.item() * inputs.size(0)running_corrects += torch.sum(preds == labels.data)if phase == 'train':scheduler.step()epoch_loss = running_loss / dataset_sizes[phase]epoch_acc = running_corrects.double() / dataset_sizes[phase]print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))# deep copy the modelif phase == 'val' and epoch_acc > best_acc:best_acc = epoch_accbest_model_wts = copy.deepcopy(model.state_dict())print()time_elapsed = time.time() - sinceprint('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))print('Best val Acc: {:4f}'.format(best_acc))# load best model weightsmodel.load_state_dict(best_model_wts)return model

可视化模型预测

def visualize_model(model, num_images=6):was_training = model.trainingmodel.eval()images_so_far = 0fig = plt.figure()with torch.no_grad():for i, (inputs, labels) in enumerate(dataloaders['val']):inputs = inputs.to(device)labels = labels.to(device)outputs = model(inputs)_, preds = torch.max(outputs, 1)for j in range(inputs.size()[0]):images_so_far += 1ax = plt.subplot(num_images//2, 2, images_so_far)ax.axis('off')ax.set_title('predicted: {}'.format(class_names[preds[j]]))imshow(inputs.cpu().data[j])if images_so_far == num_images:model.train(mode=was_training)returnmodel.train(mode=was_training)

4. 微调 convnet

加载预训练的模型并重置最终的完全连接层。

model_ft = models.resnet18(pretrained=True)
num_ftrs = model_ft.fc.in_features
# Here the size of each output sample is set to 2.
# Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).
model_ft.fc = nn.Linear(num_ftrs, 2)model_ft = model_ft.to(device)criterion = nn.CrossEntropyLoss()# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

训练和评估

在 CPU 上大约需要 15-25 分钟。 但是在 GPU 上,此过程不到一分钟。

model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,num_epochs=25)

Training complete in 1m 7s
Best val Acc: 0.921569

visualize_model(model_ft)

5.ConvNet 作为固定特征提取器

在这里,我们需要冻结除最后一层之外的所有网络。 我们需要设置requires_grad == False冻结参数,以便不在backward()中计算梯度。

model_conv = torchvision.models.resnet18(pretrained=True)
for param in model_conv.parameters():param.requires_grad = False# Parameters of newly constructed modules have requires_grad=True by default
num_ftrs = model_conv.fc.in_features
model_conv.fc = nn.Linear(num_ftrs, 2)model_conv = model_conv.to(device)criterion = nn.CrossEntropyLoss()# Observe that only parameters of final layer are being optimized as
# opposed to before.
optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9)# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)

训练和评估

在 CPU 上大约需要 15-25 分钟。 但是在 GPU 上,此过程不到一分钟。

model_conv = train_model(model_conv, criterion, optimizer_conv,exp_lr_scheduler, num_epochs=25)

Training complete in 0m 34s
Best val Acc: 0.954248

visualize_model(model_ft)

09月28日 pytorch与resnet(四)三种主要的转移学习方案,微调ConvNet,ConvNet 作为固定特征提取器相关推荐

  1. 面试经历---阿里游戏(2020年09月28日晚上7点视频面试)

    9月28日晚上进行了一次视频面试,阿里广州游戏部门,下面说下这次面试的情况 1.自我介绍 介绍了做过的项目,面试官就围绕做过的项目进行深挖. 2.redis的集群方式 如果节点挂掉怎么办? 单个节点的 ...

  2. 2005年09月28日  日本,东京  晴朗

    又一次故地重游,来这里出差,前段日子公司限制上网,所以一直都没有机会来这里看望大家. 咳,在日本觉得没有国内那么随便,也没有朝鲜冷面可以吃. 这次来日本,也赶上了国内吃月饼的节日,而我去吃不到,公司发 ...

  3. 扒一扒HTTPS网站的内幕[2015年09月29日]

    扒一扒HTTPS网站的内幕 野狗 2015年09月28日发布 作者:王继波  野狗科技运维总监,曾在360.TP-Link从事网络运维相关工作,在网站性能优化.网络协议研究上经验丰富. 野狗官博:ht ...

  4. 今日早报 每日精选12条新闻简报 每天一分钟 知晓天下事10月28日

    365资讯简报,每天精选12条热点新闻简报1条微语,每天一分钟,知晓天下事! 2021年10月28日 星期四 农历九月廿三 1.工信部:电商平台双十一不得未经消费者同意或请求擅发营销短信. 2.军人家 ...

  5. 解密谷歌机器学习工程最佳实践——机器学习43条军规 翻译 2017年09月19日 10:54:58 98310 本文是对Rules of Machine Learning: Best Practice

    解密谷歌机器学习工程最佳实践--机器学习43条军规 翻译 2017年09月19日 10:54:58 983 1 0 本文是对Rules of Machine Learning: Best Practi ...

  6. 8月2日Pytorch笔记——梯度、全连接层、GPU加速、Visdom

    文章目录 前言 一.常见函数的梯度 二.激活函数及其梯度 1.Sigmoid 2.Tanh 3.ReLU 三.Loss 函数及其梯度 1.Mean Squared Error(MSE) 2.Softm ...

  7. 10月28日人工智能讲师叶梓为各工科院校老师进行了为期三天的人工智能培训

    10月28日人工智能讲师叶梓为各工科院校老师进行了为期三天的人工智能培训,培训过程中人工智能讲师叶梓与各高校老师就人工智能前沿热点进行热烈的讨论. 根据人力资源和社会保障部办公厅<关于印发专业技 ...

  8. 绝地求生服务器6月23日紧急维护,绝地求生6月28日更新维护时间介绍

    绝地求生6月28日更新维护时间介绍 2018-06-28 09:11:45来源:游戏下载编辑:苦力趴评论(0) <绝地求生>在今日上午10点钟左右将会进行游戏的例行服务器停机维护,下面就为 ...

  9. 日周月筛选器_天谕2.09月3日周版本更新维护内容预告

    亲爱的谕霸: 为了给谕霸们带来更好的游戏品质以及更极致的游戏体验,我们会不断对游戏进行调整和修复. <天谕2.0>9月3日周版本更新维护内容预告 特别提示本周维护时间为9月3日上午8:00 ...

  10. 6月28日 cf总结

    6月28日 cf总结 今天cf提前到10点了,还不如半夜..网速坑啊... A题:水题. 在一个01序列中每次删掉01和10,求最终剩下的序列的长度. 直接输出0的个数和1的个数的差即可,因为最终只要 ...

最新文章

  1. select sum也会返回null值
  2. mysql grant %_MySQL的Grant命令详解
  3. python3 设置默认编码_Python3的字符编码乱码问题解决思路
  4. Win 8 app 获取窗口的宽度和高度, 本地化, 及文本读取
  5. 通过系统调用open来查看flag
  6. python决策树生成规则_如何从scikit-learn决策树中提取决策规则?
  7. 全明星基金季卫东: 重仓新经济冠军,投资“幸福生活“
  8. ASP.Net MVC 在ajax接收controller返回值为Json数据
  9. 【数据结构与算法】之深入解析“二叉树的锯齿形层序遍历”的求解思路与算法示例
  10. Android App 瘦身总结 第一章 图片资源的优化处理
  11. spring-boot+spring-session集成
  12. 编程题:首尾相连的字符串
  13. 得物 × StarRocks:潮流网购社区的极速 OLAP 实践
  14. ARFoundation多图识别的一个脚本
  15. 如何获取qq邮箱的秘钥
  16. Python-random.seed()的作用
  17. QQ聊天对话框(Js实现,支持表情插入文本中间)
  18. 【Swing入门教程】一步一步做Netbeans(1):类Netbeans的主界面
  19. FPGA利用SCCB协议配置OV5640摄像头
  20. Python3使用pandas读取excel文件并用列表输出

热门文章

  1. 【ArcGIS|空间分析|网络分析】5 计算服务区和创建 OD 成本矩阵
  2. 杨辉三角程序(一步步优化)
  3. 源码解析 | 万字长文详解 Flink 中的 CopyOnWriteStateTable
  4. 微信小程序开发--【APP(Object)函数介绍】(三)
  5. linux网页视频黑边,ffmpeg去除视频黑边命令
  6. mysql根据视图update表数据_怎么更新Mysql数据表视图中数据
  7. python 安装了不能用_解决Python安装后pip不能用的问题
  8. python速学_【Python杂货铺】速学python基础
  9. unity 获取鼠标点击位置_Unity中实现瓶中液体晃动的效果(从建模开始)一
  10. neovim--ubuntu安装