文章目录
一、迁移学习的简单介绍
二、数据集介绍 三、代码实现 1. 步骤 2.所用到方法介绍的文章链接 3. 完整代码
一、迁移学习的简单介绍
1.迁移学习是什么?
迁移学习是指利用已经训练好的模型,在新的任务上进行微调。 迁移学习可以加快模型训练速度,提高模型性能,并且在数据稀缺的情况下也能很好地工作。
2.迁移学习的步骤
(1) 选择预训练的模型和适当的层 :通常,我们会选择在大规模图像数据集(如ImageNet)上预训练的模型,如VGG、ResNet等。然后,根据新数据集的特点,选择需要微调的模型层。对于低级特征的任务(如边缘检测),最好使用浅层模型的层,而对于高级特征的任务(如分类),则应选择更深层次的模型。 (2) 冻结预训练模型的参数 :保持预训练模型的权重不变,只训练新增加的层或者微调一些层,避免因为在数据集中过拟合导致预训练模型过度拟合。 (3) 在新数据集上训练新增加的层 :在冻结预训练模型的参数情况下,训练新增加的层。这样,可以使新模型适应新的任务,从而获得更高的性能。 (4) 微调预训练模型的层 :在新层上进行训练后,可以解冻一些已经训练过的层,并且将它们作为微调的目标。这样做可以提高模型在新数据集上的性能。 (5) 评估和测试 :在训练完成之后,使用测试集对模型进行评估。如果模型的性能仍然不够好,可以尝试调整超参数或者更改微调层。
二、数据集介绍
下图是数据集的结构
在 food_dataset2 文件夹下含有训练数据和测试数据 训练集和测试集数据中都含有 20 种食物图片,数量在200~400不等 trainda.txt 和 testda.txt 文本中存放了每张图片的路径及标签,用 0~19 这20个数字分别对20种食物进行标签 在代码中通过trainda.txt 和 testda.txt 文本中的内容来获取每张图片及对应的标签 下面是trainda.txt文本中的部分内容(testda.txt 中的内容格式相同) 送福利!!! 私信送此数据集 !!!
三、代码实现
1. 步骤
1.调用resnet18模型,并保存需要训练的模型参数 2.定义一个图像预处理和数据增强字典 3.定义获取每张食物图片和标签的类方法 4.获取训练集和测试集数据 5.对数据集进行打包 6.调用交叉熵损失函数并创建优化器 7.定义训练模型的函数 8.定义测试模型的函数 9.训练模型,并每训练一轮测试一次
2.所用到方法介绍的文章链接
ResNet 残差网络神经网络
https://blog.csdn.net/weixin_73504499/article/details/142575775?spm=1001.2014.3001.5501 数据增强
https://blog.csdn.net/weixin_73504499/article/details/142499263?spm=1001.2014.3001.5501 调整学习率
https://blog.csdn.net/weixin_73504499/article/details/142526863?spm=1001.2014.3001.5501
3. 完整代码
import torch
import torchvision. models as models
from torch import nn
from torch. utils. data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
import numpy as np
""" 调用resnet18模型 """
resnet_model = models. resnet18( weights= models. ResNet18_Weights. DEFAULT)
for param in resnet_model. parameters( ) :
param. requires_grad = False
in_features = resnet_model. fc. in_features
resnet_model. fc = nn. Linear( in_features, 20 )
params_to_update = [ ]
for param in resnet_model. parameters( ) :
if param. requires_grad == True :
params_to_update. append( param)
""" 图像预处理和数据增强 """
data_transforms = {
'train' :
transforms. Compose( [
transforms. Resize( [ 300 , 300 ] ) ,
transforms. RandomRotation( 45 ) ,
transforms. CenterCrop( 224 ) ,
transforms. RandomHorizontalFlip( p= 0.5 ) ,
transforms. RandomVerticalFlip( p= 0.5 ) ,
transforms. RandomGrayscale( p= 0.1 ) ,
transforms. ToTensor( ) ,
transforms. Normalize( [ 0.485 , 0.456 , 0.406 ] , [ 0.229 , 0.224 , 0.225 ] )
] ) ,
'valid' :
transforms. Compose( [
transforms. Resize( [ 224 , 224 ] ) ,
transforms. ToTensor( ) ,
transforms. Normalize( [ 0.485 , 0.456 , 0.406 ] , [ 0.229 , 0.224 , 0.225 ] )
] )
}
""" 定义获取每张食物图片和标签的类方法 """
class food_dataset ( Dataset) :
def __init__ ( self, file_path, transform= None ) :
self. file_path = file_path
self. imgs = [ ]
self. labels = [ ]
self. transform = transform
with open ( self. file_path) as f:
samples = [ x. strip( ) . split( ' ' ) for x in f. readlines( ) ]
for img_path, label in samples:
self. imgs. append( img_path)
self. labels. append( label)
def __len__ ( self) :
return len ( self. imgs)
def __getitem__ ( self, idx) :
image = Image. open ( self. imgs[ idx] )
if self. transform:
image = self. transform( image)
label = self. labels[ idx]
label = torch. from_numpy( np. array( label, dtype= np. int64) )
return image, label
""" 获取训练集和测试集数据 """
training_data = food_dataset( file_path= 'trainda.txt' , transform= data_transforms[ 'train' ] )
test_data = food_dataset( file_path= 'testda.txt' , transform= data_transforms[ 'valid' ] )
""" 对数据集进行打包 """
train_dataloader = DataLoader( training_data, batch_size= 64 , shuffle= True )
test_dataloader = DataLoader( test_data, batch_size= 64 , shuffle= True )
""" 判断当前设备是否支持GPU,其中mps是苹果m系列芯片的GPU """
device = "cuda" if torch. cuda. is_available( ) else "mps" if torch. backends. mps. is_available( ) else "cpu"
print ( f"Using { device} device" )
model = resnet_model. to( device)
""" 调用交叉熵损失函数 """
loss_fn = nn. CrossEntropyLoss( )
"""" 创建优化器并调整优化器中的学习率--> lr """
optimizer = torch. optim. Adam( params_to_update, lr= 0.001 )
scheduler = torch. optim. lr_scheduler. StepLR( optimizer, step_size= 5 , gamma= 0.5 )
""" 定义训练模型的函数 """
def train ( dataloader, model, loss_fn, optimizer) :
model. train( )
for X, y in dataloader:
X, y = X. to( device) , y. to( device)
pred = model. forward( X)
loss = loss_fn( pred, y)
optimizer. zero_grad( )
loss. backward( )
optimizer. step( )
""" 定义测试模型的函数 """
best_acc = 0
def test ( dataloader, model, loss_fn) :
global best_acc
size = len ( dataloader. dataset)
num_batches = len ( dataloader)
model. eval ( )
test_loss, correct = 0 , 0
with torch. no_grad( ) :
for X, y in dataloader:
X, y = X. to( device) , y. to( device)
pred = model. forward( X)
test_loss += loss_fn( pred, y) . item( )
correct += ( pred. argmax( 1 ) == y) . type ( torch. float ) . sum ( ) . item( )
test_loss /= num_batches
correct /= size
print ( f"Test result: \n Accuracy: { ( 100 * correct) } %, Avg loss: { test_loss} " )
if correct > best_acc:
best_acc = correct
""" 定义模型训练的轮数,并每训练一轮测试一次 """
epochs = 30
for e in range ( epochs) :
print ( f"Epoch { e + 1 } \n---------------------------" )
train( train_dataloader, model, loss_fn, optimizer)
scheduler. step( )
test( test_dataloader, model, loss_fn)
print ( '最优的训练结果为:' , best_acc)
结果如下
此结果只是训练了30轮后的结果,可以训练更多轮,最后的准确率还会有所提高