数据增强,迁移学习,Resnet分类实战

目录

1. 数据增强(Data Augmentation)

2. 迁移学习

3. 模型保存    

4. 102种类花分类实战

1. 数据集

2.导入包

3. 数据读取与预处理操作 

4. Datasets制作输入数据

5.将标签的名字读出 

6.展示原始数据 

7.加载models中提供的模型 

8.初始化 

9.优化器设置 

10.训练模块


1. 数据增强(Data Augmentation)

        数据不够怎么办?采用翻转,镜像,增加数据

        如何更加高效利用数据?多利用几次

        在pytorch中有数据预处理部分:

            数据增强:torchvision中transforms模块自带功能,比较实用

            数据预处理:torchvision中transforms也帮我们实现好了,直接调用即可

            DataLoader模块直接读取batch数据

        pyorch官网:https://pytorch.org/vision/stable

2. 迁移学习

        在训练自己的模型时出现一些问题:

        1. 自己的数据不够好

        2. 训练参数花费时间多

        3. 训练模型太难

        解决方法:

        有前人已经训练好了模型,其实就是将训练的参数保留下来,而且目标都差不多。那么把别人的模型参数当成初始化参数,所有的结构和前人模型一样。

        网络模块设置:

    加载预训练模型,torchvision中有很多经典网络架构,调用起来十分方便,并且也可以用人家训练好的权重参数来继续训练,也就是所谓的迁移学习

    需要注意的是别人训练好的任务根咱们的可不是完全一样的,需要把最后的head层改一改,一般也就是最后的全连接层,改成咱们自己的任务

    训练时可以完全重头训练,也可以只训练最后咱们任务层,因为前几层都是做特征提取的,本质任务目标一致的。

        总结:迁移学习策略

                1. 将卷积层当成初始化权重参数

                2.将卷积层权重参数冻住不变,全连接层重新训练(一般是,数据量少,冻住的层数多)

3. 模型保存    

        网络模型保存与测试

            模型保存的时候可以带有选择性,例如在验证集中如果当前效果好则保存

            读取模型进行实际测试

4. 102种类花分类实战

      1. 数据集

        有训练集,测试集。一共102种花,每种花有25~100个图像

2.导入包

import os
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import torch
from torch import nn
import torch.optim as optim
import torchvision
from torchvision import transforms,models,datasets
import imageio
import time
import warnings
import random
import sys
import copy
import json
from PIL import Image

3. 数据读取与预处理操作 

data_dir = './flower_data'
train_dir = data_dir + '/train'
valid_dir = data_dir + '/valid'

制作好数据源:

    data_transforms中指定了所有图像预处理操作

    ImageFolder假设所有文件按文件夹保存好,每个文件夹下面存储同一类别的图片,文件夹的名字为分类的名字

data_transforms = {
    'train' : transforms.Compose([transforms.RandomRotation(45),#随即旋转,-45度到45度之间随机选
        transforms.CenterCrop(224), #从中心点开始裁剪
        transforms.RandomHorizontalFlip(p=0.5),#随即水平翻转,选择一个概率
        transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
        transforms.ColorJitter(brightness=0.2,contrast=0.1,saturation=0.1,hue=0.1), #参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
        transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
        transforms.ToTensor(),#转换成tensor格式
        transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])#均值,标准差
    ]), 
    'valid':transforms.Compose([transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])                   
    ])
}

 4. Datasets制作输入数据

        采用batch,将数据分组输入。

batch_size  = 8

image_datasets = {x : datasets.ImageFolder(os.path.join(data_dir,x),data_transforms[x]) for x in ['train','valid']}
dataloaders = {x : torch.utils.data.DataLoader(image_datasets[x],batch_size=batch_size,shuffle=True) for x in ['train','valid']}
dataset_szies = {x :len(image_datasets[x]) for x in ['train','valid']}
class_names = image_datasets['train'].classes
print(image_datasets)
print(dataloaders)

5.将标签的名字读出 

        用123....打标签好像不好,用花的名字作为标签

#读取标签对应的实际名字
with open('./flower_data/cat_to_name.json','r') as f:
    cat_to_name = json.load(f)
print(cat_to_name)

6.展示原始数据 

        展示下数据

            注意tensor的数据需要转换成numpy格式,而且还需要还原成标准化的结果

def im_convert(tensor):
    '''展示数据'''

    image = tensor.to('cpu').clone().detach()
    image = image.numpy().squeeze()
    image = image.transpose(1,2,0)
    image = image * np.array((0.229,0.224,0.225)) + np.array((0.485,0.456,0.406))
    image = image.clip(0,1)

    return image

fig = plt.figure(figsize=(20,12))
colunms = 4
rows = 2

dataiter = iter(dataloaders['valid'])
inputs,classes =next(dataiter)

for idx in range(colunms * rows):
    ax = fig.add_subplot(rows,colunms,idx+1,xticks = [],yticks = [])
    ax.set_title(cat_to_name[str(int(class_names[classes[idx]]))])
    plt.imshow(im_convert(inputs[idx]))
plt.show()

7.加载models中提供的模型 

        加载models中提供的模型,并且直接用训练好的权重当作初始化参数

            第一次执行需要下载,可能会比较慢

model_name = 'resnet' #可选的会比较多['resnet','alexnet','vgg','squeezenet','densenet','inception']
# 是否用人家训练好的特征来做
feature_extract = True

#是否用GPU训练
train_on_gpu = torch.cuda.is_available()

if not train_on_gpu:
    print('CUDA is not available .  Training on CPU...')
else:
    print('CUDA is  available .  Training on GPU...')

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

def set_parameter_requires_grad(model,feature_extracting):
    if feature_extract:
        for param in model.parameters():
            param.requires_grad = False #冻不冻住

model_ft = models.resnet152()
print(model_ft)

8.初始化 

        迁移学习,用前人的参数,改变全连接层。

def initalize_model(model_name,num_classes,feature_extract,use_pretrained=True):
    #选择合适的模型,不同模型的初始化方法稍微有点区别
    model_ft = None
    input_size = 0

    if model_name == 'resnet':
        model_ft = models.resnet152(pretrained=use_pretrained)
        set_parameter_requires_grad(model_ft,feature_extract)
        num_ftrs = model_ft.fc.in_features
        model_ft.fc = nn.Sequential(nn.Linear(num_ftrs,num_classes),
                                    nn.LogSoftmax(dim=1))
        input_size = 224

    return model_ft,input_size

feature_extract = True
model_ft,input_size = initalize_model(model_name,102,feature_extract,use_pretrained=True)

#GPU计算
model_ft = model_ft.to(device)

#模型保存
filename = 'checkpoint.pth'

#是否训练所有层

params_to_updata = model_ft.parameters()
print('Params to learn')
if feature_extract:
    params_to_updata = []
    for name,param in model_ft.named_parameters():
        if param.requires_grad == True:
            params_to_updata.append(param)
            print("\t",name)
else:
    for name,param in model_ft.named_parameters():
        if param.requires_grad == True:
            print("\t",name)

print(model_ft)

 

9.优化器设置 

#优化器设置
optimizer_ft = optim.Adam(params_to_updata,lr=1e-2)
scheduler = optim.lr_scheduler.StepLR(optimizer_ft,step_size=7,gamma=0.1) #学习率每7个epoch衰减成原来的1/10
#最后一层已经LogSoftmax()了,所以不能nn.CrossEntropyLoss()来计算了,nn.CrossEntropyLoss()相当于logSoftmax()和nn.NLLoss()整合
criterion = nn.NLLLoss()

10.训练模块

def train_model(model,dataloaders,criterion,optimizer,num_epochs=25,is_inception=False,filename=filename):
    since = time.time()
    best_acc = 0
    '''
    checkpoint = torch.laod(filename)
    best_acc = checkpoint['best_acc]
    model.load_state_dict(checkpoint['optimizer'])
    model.class_to_idx = checkpoint['mapping']
    '''
    model.to(device)

    val_acc_history = []
    train_acc_history = []
    train_losses = []
    vaild_losses = []
    LRs = [optimizer.param_groups[0]['lr']]

    best_model_wts = copy.deepcopy(model.state_dict())

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch,num_epochs-1))
        print('-'*10)

        #训练和验证
        for phase in ['train','valid']:
            if phase == 'train':
                model.train() #训练
            else:
                model.eval()  #验证
        
            running_loss = 0.0
            running_corrects = 0

            #把数据都取个遍
            for inputs,labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                #清零
                optimizer.zero_grad()
                #只有训练的时候计算和更新梯度
                with torch.set_grad_enabled(phase=='train'):
                    if is_inception and phase == 'train':
                        outputs,aux_outputs = model(inputs)
                        loss1 = criterion(outputs,labels)
                        loss2 = criterion(aux_outputs,labels)
                        loss = loss1 + loss2

                    else: #resnet执行的是这里
                        outputs= model(inputs)
                        loss = criterion(outputs,labels)
                
                    _,preds = torch.max(outputs,1)

                    #训练阶段更新权重
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                #计算损失
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / len(dataloaders[phase].dataset)
            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)

            time_elapsed = time.time() - since

            print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase,epoch_loss,epoch_acc))

            #得到最好的那次的模型
            if phase == 'valid' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
                state ={
                    'state_dict' : model.state_dict(),
                    'best_acc': best_acc,
                    'optimizer': optimizer.state_dict(),
                }
                torch.save(state,filename)
            if phase == 'valid':
                val_acc_history.append(epoch_acc)
                vaild_losses.append(epoch_loss)
                scheduler.step(epoch_loss)
            if phase=='train':
                train_acc_history.append(epoch_acc)
                train_losses.append(epoch_loss)
                
        print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
        LRs.append(optimizer.param_groups[0]['lr'])
        print()

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60,time_elapsed % 60))
    print('Best val Acc: {:.4f}'.format(best_acc))

    #训练完后用最好的一次当作模型的最终结果
    model.load_state_dict(best_model_wts)
    return model, val_acc_history,train_acc_history,vaild_losses,train_losses,LRs
#开始训练!!!
model_ft,val_acc_history,train_acc_history,vaild_losses,train_losses,LRs = train_model(model_ft,dataloaders,criterion,optimizer_ft,num_epochs=5)

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当使用TensorFlow进行迁移学习时,可以使用预训练的ResNet-50模型作为基础模型,并在其基础上进行微调。以下是一个基于TensorFlow的完整代码示例: ```python import tensorflow as tf from tensorflow import keras # 加载预训练模型 base_model = keras.applications.ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3)) # 冻结预训练模型的权重 for layer in base_model.layers: layer.trainable = False # 添加自定义的分类器层 x = base_model.output x = keras.layers.GlobalAveragePooling2D()(x) x = keras.layers.Dense(256, activation='relu')(x) predictions = keras.layers.Dense(num_classes, activation='softmax')(x) # 创建完整的模型 model = keras.models.Model(inputs=base_model.input, outputs=predictions) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 数据准备和增强 train_datagen = keras.preprocessing.image.ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True) test_datagen = keras.preprocessing.image.ImageDataGenerator(rescale=1./255) train_generator = train_datagen.flow_from_directory( train_data_dir, target_size=(224, 224), batch_size=batch_size, class_mode='categorical') validation_generator = test_datagen.flow_from_directory( validation_data_dir, target_size=(224, 224), batch_size=batch_size, class_mode='categorical') # 训练模型 model.fit( train_generator, steps_per_epoch=train_steps_per_epoch, epochs=num_epochs, validation_data=validation_generator, validation_steps=validation_steps_per_epoch) # 评估模型 test_generator = test_datagen.flow_from_directory( test_data_dir, target_size=(224, 224), batch_size=batch_size, class_mode='categorical', shuffle=False) scores = model.evaluate(test_generator) print(f'Test loss: {scores[0]}') print(f'Test accuracy: {scores[1]}') ``` 请注意,上述代码中的数据集路径、类别数量、训练轮数、批次大小等需要根据您的具体情况进行适当修改。此代码将在训练集上微调预训练的ResNet-50模型,并在验证集和测试集上评估性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值