深度学习之迁移学习resnet18模型及调用模型预测
- 互联网
- 2025-08-24 05:30:01

迁移学习resnet18模型及调用模型预测 目录 迁移学习resnet18模型及调用模型预测1 迁移学习1.1 概念1.2 主要思想1.3 优点1.4 迁移学习的步骤 2 模型迁移和调整2.1 ResNet18模型2.2 新数据2.3 冻结参数2.4 微调层2.5 新增层2.6 数据预处理 3 代码测试3.1 微调模型代码测试及保存模型3.2 新增层模型训练与测试3.3 调用模型预测新数据 1 迁移学习
1.1 概念
迁移学习是指利用已经训练好的模型,在新的任务上进行微调。迁移学习可以加快模型训练速度,提高模型性能,并且在数据稀缺的情况下也能很好地工作。
1.2 主要思想利用已有的知识来帮助解决新的问题。在深度学习中,这通常意味着使用在大型数据集上预训练的神经网络作为起点,然后针对特定任务进行微调(fine-tuning)。
1.3 优点 减少数据需求:对于新任务,不需要大量标注数据来从头开始训练模型。提高性能:预训练模型已经学习了通用的特征表示,这有助于新任务上的性能提升。节省计算资源:迁移学习可以减少训练时间和计算资源的需求。 1.4 迁移学习的步骤 1.选择预训练的模型和适当的层:通常,我们会选择在大规模图像数据集(如lmageNet)上预训练的模型,如VGG、ResNet等。然后,根据新数据集的特点,选择需要微调的模型层。对于低级特征的任务(如边缘检测),最好使用浅层模型的层,而对于高级特征的任务(如分类),则应选择更深层次的模型。2.冻结预训练模型的参数:保持预训练模型的权重不变,只训练新增加的层或者微调一些层,避免因为在数据集中过拟合导致预训练模型过度拟合。3.在新数据集上训练新增加的层:在冻结预训练模型的参数情况下,训练新增加的层。这样,可以使新模型适应新的任务,从而获得更高的性能。4.微调预训练模型的层:在新层上进行训练后,可以解冻一些已经训练过的层,并且将它们作为微调的目标。这样做可以提高模型在新数据集上的性能。5.评估和测试:在训练完成之后,使用测试集对模型进行评估。如果模型的性能仍然不够好,可以尝试调整超参数或者更改微调层。 2 模型迁移和调整2.1 ResNet18模型 2.2 新数据
新数据保存在train.txt和test.txt里,内容如下,是食物图片地址和食物图片的类别,一共有20种类别。
2.3 冻结参数保持预训练模型的权重不变,模型的参数中有requires_grad,为True时权重参数会变化,为False时不会,所以对预训练模型所有参数冻结可指定: model.parameters().requires_grad=False
for param in resnet_model.parameters(): print(param) param.requires_grad = False 2.4 微调层由于模型的输出为1000,而我们新数据的结果类别为20个,所以需要更改微调输出层。 更改输出层的输出,输入不变,需要先获取输入再重新定义输出层,如下,
## 获取输入 in_features = resnet_model.fc.in_features # 重构输出 resnet_model.fc = nn.Linear(in_features,20) 2.5 新增层需要保存原模型的权重参数不变,再新增一层输入输出分别为原模型的输出、新数据特征类别数。需要重新定义模型,可以先调用resnet18模型,再将其输出的1000,及新数据的20作为输入输出重新定义
class Resnet_add(nn.Module): def __init__(self): super().__init__() self.fc_add = torch.nn.Linear(1000, 20) def forward(self, x): x = resnet_model(x) out = self.fc_add(x) return out 2.6 数据预处理由于模型的输入图片是224*224,所以需要对我们的新数据进行处理,同时也进行了数据增强
data_transforms = { #字典 'train': transforms.Compose([ # 对图片做预处理的。组合, transforms.Resize([300,300]), #数据进行改变大小[256,256] transforms.RandomRotation(45), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(p=0.5), transforms.RandomVerticalFlip(0.5), transforms.RandomGrayscale(0.1), transforms.ToTensor(), #数据转换为tensor,默认把通道维度放在前面 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]), ]), } 3 代码测试3.1 微调模型代码测试及保存模型
模型保存:torch.save(model.state_dict(),‘best_rnt18.pth’)
代码展示:
import torch from torch.utils.data import Dataset,DataLoader #用于处理数据集的 import numpy as np from PIL import Image # from torchvision import transforms #对数据进行处理工具 转换 import torchvision.models as models from torch import nn resnet_model = models.resnet18(weights = models.ResNet18_Weights.DEFAULT) for param in resnet_model.parameters(): print(param) 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]), #数据进行改变大小[256,256] transforms.RandomRotation(45), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(p=0.5), transforms.RandomVerticalFlip(0.5), transforms.RandomGrayscale(0.1), transforms.ToTensor(), #数据转换为tensor,默认把通道维度放在前面 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]), ]), }#数组增强, #Dataset是用来处理数据的。 device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" model = resnet_model.to(device) class food_dataset(Dataset): # food_dataset是自己创建的类名称,可以改为你需要的名称 def __init__(self, file_path,transform=None): #类的初始化,解析数据文件txt self.file_path = file_path self.imgs = [] self.labels = [] self.transform = transform with open(self.file_path) as f:#是把train.txt文件中图片的路径保存在 self.imgs,train.txt文件中标签保存在 self.labels samples = [x.strip().split(' ') for x in f.readlines()] for img_path, label in samples: self.imgs.append(img_path) #图像的路径 self.labels.append(label) #标签,还不是tensor #初始化:把图片目录加载到self, def __len__(self): #类实例化对象后,可以使用len函数测量对象的个数 return len(self.imgs) #training_data[1] def __getitem__(self, idx): #关键,可通过索引的形式获取每一个图片数据及标签 image = Image.open(self.imgs[idx]) #读取到图片数据,还不是tensor,BGR if self.transform: #将pil图像数据转换为tensor image = self.transform(image) #图像处理为256*256,转换为tenor label = self.labels[idx] #label还不是tensor label = torch.from_numpy(np.array(label,dtype = np.int64)) #label也转换为tensor, return image, label training_data = food_dataset(file_path = './train_test/train.txt',transform = data_transforms['train']) # test_data = food_dataset(file_path = './train_test/test.txt',transform = data_transforms['valid']) # test_data = food_dataset(file_path = './test_true.txt',transform = data_transforms['valid']) #training_data需要具备索引的功能,还要确保数据是tensor train_dataloader = DataLoader(training_data, batch_size=64,shuffle=True)#64张图片为一个包, test_dataloader = DataLoader(test_data, batch_size=64,shuffle=True) loss_fn = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(params_to_update, lr=0.001) def train(dataloader, model, loss_fn, optimizer): model.train() #pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。 # 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。 batch_size_num = 1 for X, y in dataloader: #其中batch为每一个数据的编号 X, y = X.to(device), y.to(device) #把训练数据集和标签传入cpu或GPU pred = model.forward(X) #自动初始化 w权值 loss = loss_fn(pred, y) #通过交叉熵损失函数计算损失值loss # Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络 optimizer.zero_grad() #梯度值清零 loss.backward() #反向传播计算得到每个参数的梯度值 optimizer.step() #根据梯度更新网络参数 loss = loss.item() #获取损失值 if batch_size_num %1 == 0: print(f"loss: {loss:>7f} [number:{batch_size_num}]") batch_size_num += 1 best_acc = 0 def test(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) model.eval() #测试模式 test_loss, correct = 0, 0 global best_acc with torch.no_grad(): #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。 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() a = (pred.argmax(1) == y) #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号 b = (pred.argmax(1) == y).type(torch.float) test_loss /= num_batches correct /= size if correct > best_acc: best_acc = correct print(model.state_dict().keys()) torch.save(model.state_dict(),'best_rnt18.pth') print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}") scheduler = torch.optim.lr_scheduler.StepLR(optimizer,step_size=5,gamma=0.5) epochs = 20 for t in range(epochs): print(f"Epoch {t+1}\n-------------------------------") train(train_dataloader, model, loss_fn, optimizer) scheduler.step() test(test_dataloader, model, loss_fn) print(f"Done!,best: {best_acc}") model.load_state_dict(torch.load('best_rnt18.pth'))运行结果:
3.2 新增层模型训练与测试代码展示:
import torch from torch.utils.data import Dataset,DataLoader #用于处理数据集的 import numpy as np from PIL import Image # from torchvision import transforms #对数据进行处理工具 转换 import torchvision.models as models from torch import nn resnet_model = models.resnet18(weights = models.ResNet18_Weights.DEFAULT) for param in resnet_model.parameters(): print(param) param.requires_grad = False data_transforms = { #字典 'train': transforms.Compose([ # 对图片做预处理的。组合, transforms.Resize([300,300]), #数据进行改变大小[256,256] transforms.RandomRotation(45), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(p=0.5), transforms.RandomVerticalFlip(0.5), transforms.RandomGrayscale(0.1), transforms.ToTensor(), #数据转换为tensor,默认把通道维度放在前面 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]), ]), }#数组增强, #Dataset是用来处理数据的。 device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" class Resnet_add(nn.Module): def __init__(self): super().__init__() self.fc_add = torch.nn.Linear(1000, 20) def forward(self, x): x = resnet_model(x) out = self.fc_add(x) return out model = Resnet_add().to(device) params_to_update = [] for param in model.parameters(): if param.requires_grad == True: params_to_update.append(param) # model = models.resnet18(weights = models.ResNet18_Weights.DEFAULT) # model = resnet_model.to(device) class food_dataset(Dataset): # food_dataset是自己创建的类名称,可以改为你需要的名称 def __init__(self, file_path,transform=None): #类的初始化,解析数据文件txt self.file_path = file_path self.imgs = [] self.labels = [] self.transform = transform with open(self.file_path) as f:#是把train.txt文件中图片的路径保存在 self.imgs,train.txt文件中标签保存在 self.labels samples = [x.strip().split(' ') for x in f.readlines()] for img_path, label in samples: self.imgs.append(img_path) #图像的路径 self.labels.append(label) #标签,还不是tensor #初始化:把图片目录加载到self, def __len__(self): #类实例化对象后,可以使用len函数测量对象的个数 return len(self.imgs) #training_data[1] def __getitem__(self, idx): #关键,可通过索引的形式获取每一个图片数据及标签 image = Image.open(self.imgs[idx]) #读取到图片数据,还不是tensor,BGR if self.transform: #将pil图像数据转换为tensor image = self.transform(image) #图像处理为256*256,转换为tenor label = self.labels[idx] #label还不是tensor label = torch.from_numpy(np.array(label,dtype = np.int64)) #label也转换为tensor, return image, label training_data = food_dataset(file_path = './train_test/train.txt',transform = data_transforms['train']) # test_data = food_dataset(file_path = './train_test/test.txt',transform = data_transforms['valid']) # test_data = food_dataset(file_path = './test_true.txt',transform = data_transforms['valid']) #training_data需要具备索引的功能,还要确保数据是tensor train_dataloader = DataLoader(training_data, batch_size=64,shuffle=True)#64张图片为一个包, test_dataloader = DataLoader(test_data, batch_size=64,shuffle=True) loss_fn = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(params_to_update, lr=0.001) def train(dataloader, model, loss_fn, optimizer): model.train() #pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。 # 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。 batch_size_num = 1 for X, y in dataloader: #其中batch为每一个数据的编号 X, y = X.to(device), y.to(device) #把训练数据集和标签传入cpu或GPU pred = model.forward(X) #自动初始化 w权值 loss = loss_fn(pred, y) #通过交叉熵损失函数计算损失值loss # Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络 optimizer.zero_grad() #梯度值清零 loss.backward() #反向传播计算得到每个参数的梯度值 optimizer.step() #根据梯度更新网络参数 loss = loss.item() #获取损失值 if batch_size_num %1 == 0: print(f"loss: {loss:>7f} [number:{batch_size_num}]") batch_size_num += 1 best_acc = 0 def test(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) model.eval() #测试模式 test_loss, correct = 0, 0 global best_acc with torch.no_grad(): #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。 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() a = (pred.argmax(1) == y) #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号 b = (pred.argmax(1) == y).type(torch.float) test_loss /= num_batches correct /= size if correct > best_acc: best_acc = correct print(model.state_dict().keys()) torch.save(model.state_dict(),'best_rnt18_add.pth') print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}") scheduler = torch.optim.lr_scheduler.StepLR(optimizer,step_size=5,gamma=0.5) epochs = 20 for t in range(epochs): print(f"Epoch {t+1}\n-------------------------------") train(train_dataloader, model, loss_fn, optimizer) scheduler.step() test(test_dataloader, model, loss_fn) print(f"Done!,best: {best_acc}")运行结果:
3.3 调用模型预测新数据需要注意,调用保存的模型时,该模型的框架也需要先搭建好,才能加载训练好的模型参数,再预测
代码展示:
import torch from torch.utils.data import Dataset,DataLoader #用于处理数据集的 import numpy as np from PIL import Image # from torchvision import transforms #对数据进行处理工具 转换 import torchvision.models as models from torch import nn data_transforms = { #字典 'train': transforms.Compose([ # 对图片做预处理的。组合, transforms.Resize([300,300]), #数据进行改变大小[256,256] transforms.RandomRotation(45), transforms.CenterCrop(224), transforms.RandomHorizontalFlip(p=0.5), transforms.RandomVerticalFlip(0.5), transforms.RandomGrayscale(0.1), transforms.ToTensor(), #数据转换为tensor,默认把通道维度放在前面 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]), ]), }#数组增强, #Dataset是用来处理数据的。 device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" # model = resnet_model.to(device) class food_dataset(Dataset): # food_dataset是自己创建的类名称,可以改为你需要的名称 def __init__(self, file_path,transform=None): #类的初始化,解析数据文件txt self.file_path = file_path self.imgs = [] self.labels = [] self.transform = transform with open(self.file_path) as f:#是把train.txt文件中图片的路径保存在 self.imgs,train.txt文件中标签保存在 self.labels samples = [x.strip().split(' ') for x in f.readlines()] for img_path, label in samples: self.imgs.append(img_path) #图像的路径 self.labels.append(label) #标签,还不是tensor #初始化:把图片目录加载到self, def __len__(self): #类实例化对象后,可以使用len函数测量对象的个数 return len(self.imgs) #training_data[1] def __getitem__(self, idx): #关键,可通过索引的形式获取每一个图片数据及标签 image = Image.open(self.imgs[idx]) #读取到图片数据,还不是tensor,BGR if self.transform: #将pil图像数据转换为tensor image = self.transform(image) #图像处理为256*256,转换为tenor label = self.labels[idx] #label还不是tensor label = torch.from_numpy(np.array(label,dtype = np.int64)) #label也转换为tensor, return image, label test_data = food_dataset(file_path = './test_true.txt',transform = data_transforms['valid']) test_dataloader = DataLoader(test_data, batch_size=64,shuffle=True) resnet_model = models.resnet18() in_features = resnet_model.fc.in_features resnet_model.fc = nn.Linear(in_features,20) model = resnet_model model.load_state_dict(torch.load('best_rnt18.pth')) loss_fn = nn.CrossEntropyLoss() def test(dataloader, model, loss_fn): size = len(dataloader.dataset) num_batches = len(dataloader) model.eval() #测试模式 test_loss, correct = 0, 0 global best_acc with torch.no_grad(): #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。 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() a = (pred.argmax(1) == y) #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号 b = (pred.argmax(1) == y).type(torch.float) test_loss /= num_batches correct /= size print(f'true:{y}') print(f'pre:{pred.argmax(1)}') print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}") test(test_dataloader, model, loss_fn)运行结果:
深度学习之迁移学习resnet18模型及调用模型预测由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“深度学习之迁移学习resnet18模型及调用模型预测”
上一篇
云计算如何解决延迟问题?
下一篇
大数据治理之solr的体现