当前位置:   article > 正文

使用pytorch实现预训练模型迁移学习中的目标检测_模型迁移到目标检测

模型迁移到目标检测

目录

1.COCO数据集类别文件下载

2.fasterrcnn_resnet50_fpn预训练模型预测图片

导入相关的包

(1)读取类别文件

(2)数据变换

(3)加载预训练模型

(4)检测一张图片

(5)实时检测

3.对预训练目标检测模型的类别和backbone的修改

(1)fasterrcnn_resnet50_fpn

(2)ssd300_vgg16

(3)ssdlite320_mobilenet_v3_large

(4)怎么使用预训练模型进行自己的数据集的一个小实例


1.COCO数据集类别文件下载

链接:https://pan.baidu.com/s/17M-lhHh0t-rw2egWuaPWKg 
提取码:az39

2.fasterrcnn_resnet50_fpn预训练模型预测图片

提示:Faster R-CNN模型是以ResNet-50-FPN为骨干网络。

  • 第一:对于模型的输入图像,首先需要转换为tensor类型,并且图像的格式为[C,H,W],并且对于每一张图片,将其值转换为[0-1]之间,允许不同的尺寸的图片。
  • 第二:对于模型的训练:
    • 第一步:输入图像转换为tensor类型;
    • 第二步:对于target包含:
      • 图像中目标的坐标[x1,y1,x2,y2],其中0<=x1<x2=W和0<=y1<y2<=H;
      • 图像中每一个物体的标签(对应类别)。
    • 第三步:模型最后会返回一个字典的tensor,其中包含类别,坐标值回归的损失值。
  • 第三步:对于模型的前向推断(预测):
    • 第一步:只需要输入到模型中类型为tensor类型的图像;
    • 第二步:模型最后返回的值为一个列表字典的tensor,其中包含的内容;
      • 图像中目标的坐标[x1,y1,x2,y2],其中0<=x1<x2=W和0<=y1<y2<=H;
      • 图像中每一个物体的标签(对应类别);
      • 对应目标的预测概率。

https://pytorch.org/vision/stable/models/generated/torchvision.models.detection.fasterrcnn_resnet50_fpn.html?highlight=models#torchvision.models.detection.fasterrcnn_resnet50_fpn

导入相关的包

  1. """
  2. @Author : Keep_Trying_Go
  3. @Major : Computer Science and Technology
  4. @Hobby : Computer Vision
  5. @Time : 2023-01-08 21:09
  6. """
  7. import os
  8. import cv2
  9. import time
  10. import torch
  11. import cvzone
  12. import numpy as np
  13. from PIL import Image
  14. from torchvision import transforms
  15. from torch.utils.data import DataLoader,Dataset
  16. from torchvision.models.detection import fasterrcnn_resnet50_fpn

(1)读取类别文件

  1. with open('classes.txt','r') as fp:
  2. classes=fp.read().splitlines()
  3. print(len(classes))

(2)数据变换

  1. #数据变换
  2. transform=transforms.Compose([
  3. transforms.ToTensor()
  4. # transforms.Normalize(mean=[0.48235, 0.45882, 0.40784],std=[1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0])
  5. ])

(3)加载预训练模型

  1. #加载预训练模型
  2. # 预训练模型下载 https://download.pytorch.org/models/fasterrcnn_resnet50_fpn_coco-258fb6c6.pth
  3. modelFRCNNResNet50Fpn=fasterrcnn_resnet50_fpn(pretrained=True,progress=True)
  4. # print(modelSSD300VGG)

(4)检测一张图片

  1. #返回模型检测的结果
  2. def detectSignalImage(img_path):
  3. """
  4. :param img_path: 图像的路径
  5. :return:
  6. """
  7. img=Image.open(img_path)
  8. img_transfer=transform(img)
  9. #注意这个地方需要对图像进行升维
  10. imgReshape=torch.unsqueeze(input=img_transfer,dim=0)
  11. # print(img_transfer.shape)
  12. # print(type(img_transfer))
  13. #将模型设置为eval模式
  14. modelFRCNNResNet50Fpn.eval()
  15. detection=modelFRCNNResNet50Fpn(imgReshape)
  16. print('detection: {}'.format(detection))
  17. print('box: {}'.format(detection[0]['boxes']))
  18. print('label: {}'.format(detection[0]['labels']))
  19. print('scores: {}'.format(detection[0]['scores']))
  20. # pred_class = [classes[i] for i in list(detection[0]['labels'].numpy())]
  21. return detection[0]['boxes'],detection[0]['labels'],detection[0]['scores']
  1. #根据模型返回的结果,将其绘制到图像中
  2. def drawRectangle(boxes,labels,scores,img_path):
  3. """
  4. :param boxes: 对应目标的坐标
  5. :param labels: 对应目标的标签
  6. :param scores: 对应目标的类别分数
  7. :return:
  8. """
  9. imgRe=cv2.imread(img_path)
  10. for k in range(len(labels)):
  11. #左上角坐标(xleft,yleft)和右下角坐标(xright,yright)
  12. xleft=int(boxes[k][0])
  13. yleft=int(boxes[k][1])
  14. xright=int(boxes[k][2])
  15. yright=int(boxes[k][3])
  16. class_id=labels[k].item()
  17. print(class_id)
  18. confidence=scores[k].item()
  19. if confidence>0.7:
  20. text = classes[class_id] + ': ' + str('{:.4f}'.format(confidence))
  21. cv2.rectangle(imgRe, (xleft, yleft), (xright, yright), (255, 0, 255), 2)
  22. cvzone.putTextRect(img=imgRe, text=text, pos=(xleft + 9, yleft - 12),
  23. scale=1, thickness=1, colorR=(0, 255, 0))
  24. cv2.imshow('img', imgRe)
  25. cv2.waitKey(0)
  1. if __name__ == '__main__':
  2. boxes,labels,scores=detectSignalImage(img_path='images/fourDogs.png')
  3. drawRectangle(boxes=boxes,labels=labels,scores=scores,img_path='images/fourDogs.png')

(5)实时检测

  1. def timeDetect():
  2. # 计算开始时间
  3. start_time = time.time()
  4. # 计算帧率
  5. countFPS = 0
  6. # 开启摄像头
  7. cap = cv2.VideoCapture(0)
  8. while cap.isOpened():
  9. ret, frame = cap.read()
  10. frame = cv2.resize(src=frame, dsize=(520, 520))
  11. frame = cv2.flip(src=frame, flipCode=2)
  12. #将其opencv读取的图像格式转换为PIL读取的类型格式
  13. frame_PIL = Image.fromarray(frame)
  14. img_transform = transform(frame_PIL)
  15. # 对图像进行升维
  16. img_Transform = torch.unsqueeze(input=img_transform, dim=0)
  17. # 预测图片
  18. modelFRCNNResNet50Fpn.eval()
  19. detection = modelFRCNNResNet50Fpn(img_Transform)
  20. # 获取类别概率值
  21. end_time = time.time()
  22. countFPS += 1
  23. FPS = round(countFPS / (end_time - start_time), 0)
  24. cv2.putText(img=frame, text='FPS: ' + str(FPS), org=(10, 50),
  25. fontFace=cv2.FONT_HERSHEY_SIMPLEX,
  26. fontScale=1.0, color=(0, 255, 0), thickness=2)
  27. boxes=detection[0]['boxes']
  28. labels=detection[0]['labels']
  29. scores=detection[0]['scores']
  30. for k in range(len(labels)):
  31. xleft = int(boxes[k][0])
  32. yleft = int(boxes[k][1])
  33. xright = int(boxes[k][2])
  34. yright = int(boxes[k][3])
  35. class_id = labels[k].item()
  36. print(class_id)
  37. confidence = scores[k].item()
  38. if confidence>0.3:
  39. text = classes[class_id] + ': ' + str('{:.4f}'.format(confidence))
  40. cv2.rectangle(frame, (xleft, yleft), (xright, yright), (255, 0, 255), 2)
  41. cvzone.putTextRect(img=frame, text=text, pos=(xleft + 9, yleft - 12),
  42. scale=1, thickness=1, colorR=(0, 255, 0))
  43. cv2.imshow('img', frame)
  44. key = cv2.waitKey(1)
  45. if key == 27:
  46. break
  47. cap.release()
  48. cv2.destroyAllWindows()

3.对预训练目标检测模型的类别和backbone的修改

(1)fasterrcnn_resnet50_fpn

对其训练的类别进行修改:

  1. import torchvision
  2. from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
  3. # 在COCO上加载经过预训练的预训练模型
  4. model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
  5. # replace the classifier with a new one, that has
  6. # 将分类器替换为具有用户定义的 num_classes的新分类器
  7. num_classes = 2 # 1 class (person) + background
  8. # 获取分类器的输入参数的数量
  9. in_features = model.roi_heads.box_predictor.cls_score.in_features
  10. # 用新的头部替换预先训练好的头部
  11. model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)

对其backbone相关进行修改:

 

  1. import torchvision
  2. from torchvision.models.detection import FasterRCNN
  3. from torchvision.models.detection.rpn import AnchorGenerator
  4. # 加载预先训练的模型进行分类和返回
  5. # 只有功能
  6. backbone = torchvision.models.mobilenet_v2(pretrained=True).features
  7. # FasterRCNN需要知道骨干网中的输出通道数量。对于mobilenet_v2,它是1280,所以我们需要在这里添加它
  8. backbone.out_channels = 1280
  9. # 我们让RPN在每个空间位置生成5 x 3个锚点
  10. # 具有5种不同的大小和3种不同的宽高比。
  11. # 我们有一个元组[元组[int]]
  12. # 因为每个特征映射可能具有不同的大小和宽高比
  13. anchor_generator = AnchorGenerator(sizes=((32, 64, 128, 256, 512),),
  14. aspect_ratios=((0.5, 1.0, 2.0),))
  15. # 定义一下我们将用于执行感兴趣区域裁剪的特征映射,以及重新缩放后裁剪的大小。
  16. # 如果您的主干返回Tensor,则featmap_names应为[0]。
  17. # 更一般地,主干应该返回OrderedDict [Tensor]
  18. # 并且在featmap_names中,您可以选择要使用的功能映射。
  19. roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=['0', '1', '2', '3'],
  20. output_size=7,
  21. sampling_ratio=2)
  22. # 将这些pieces放在FasterRCNN模型中
  23. model = FasterRCNN(backbone,
  24. num_classes=2,
  25. rpn_anchor_generator=anchor_generator,
  26. box_roi_pool=roi_pooler)

(2)ssd300_vgg16

  1. #修改模型分类头的类别数
  2. def modelSSDVgg16(num_classes):
  3. #加载在COCO数据集上训练的预训练模型
  4. modelSSDLite=ssd300_vgg16(pretrained=True,progress=True)
  5. # replace the classifier with a new one, that has
  6. # 将分类器替换为具有用户定义的 num_classes的新分类器
  7. # 获取分类器的输入参数的数量
  8. c_in_features=[modelSSDLite.head.classification_head.module_list[i].in_channels for i in range(len(modelSSDLite.head.classification_head.module_list))]
  9. num_anchors=modelSSDLite.anchor_generator.num_anchors_per_location()
  10. # # 用新的头部替换预先训练好的头部
  11. modelSSDLite.head.classification_head=SSDClassificationHead(in_channels=c_in_features,num_anchors=num_anchors,num_classes=num_classes)
  12. return modelSSDLite

(3)ssdlite320_mobilenet_v3_large

  1. #修改模型分类头的类别数
  2. def modelSSD320(num_classes):
  3. #加载在COCO数据集上训练的预训练模型
  4. modelSSDLite=ssdlite320_mobilenet_v3_large(pretrained=True,progress=True)
  5. # replace the classifier with a new one, that has
  6. # 将分类器替换为具有用户定义的 num_classes的新分类器
  7. # 获取分类器的输入参数的数量
  8. c_in_features=[]
  9. norm_Layers=[]
  10. for i in range(len(modelSSDLite.head.classification_head.module_list)):
  11. in_channels_1=modelSSDLite.head.classification_head.module_list[i][0][0].in_channels
  12. normLayer=modelSSDLite.head.classification_head.module_list[i][0][1]
  13. c_in_features.append(in_channels_1)
  14. norm_Layers.append(normLayer)
  15. num_anchors=modelSSDLite.anchor_generator.num_anchors_per_location()
  16. # # 用新的头部替换预先训练好的头部
  17. modelSSDLite.head.classification_head=SSDLiteClassificationHead(in_channels=c_in_features,num_anchors=num_anchors,
  18. num_classes=num_classes,norm_layer=torch.nn.BatchNorm2d)
  19. return modelSSDLite

(4)怎么使用预训练模型进行自己的数据集的一个小实例

  1. #怎么使用预训练模型进行自己的数据集的一个小实例
  2. def example():
  3. model = fasterrcnn_resnet50_fpn(pretrained=True, progress=True)
  4. #images:四张图像,每一张图像的格式为[C,H,W]
  5. #boxes:对于每一张图像中包含11个目标,每一个目标包含四个坐标
  6. images, boxes = torch.rand(4, 3, 600, 1200), torch.rand(4, 11, 4)
  7. # print('images.shape: {}'.format(images.shape))
  8. # print('boxes.shape: {}'.format(boxes.shape))
  9. print('boxes: {}'.format(boxes))
  10. boxes[:, :, 2:4] = boxes[:, :, 0:2] + boxes[:, :, 2:4]
  11. print('boxes.shape: {}'.format(boxes.shape))
  12. # print('boxes: {}'.format(boxes))
  13. #这里的整数范围[1,91),其二维形状为[4,11]
  14. labels = torch.randint(1, 91, (4, 11))
  15. print('labels.shape: {}'.format(labels.shape))
  16. #将图像存放在一个列表中
  17. images = list(image for image in images)
  18. targets = []
  19. #将坐标和对应的标签存放在一个字典当中
  20. for i in range(len(images)):
  21. d = {}
  22. d['boxes'] = boxes[i]
  23. # print('boxes.shape: {}'.format(boxes[i].shape))
  24. d['labels'] = labels[i]
  25. # print('labels[i].shape: {}'.format(labels[i].shape))
  26. targets.append(d)
  27. # print('d: {}'.format(d))
  28. print('images.shape: {}'.format(len(images)))
  29. print('targets.shape: {}'.format(len(targets)))
  30. print('images: {}'.format(images))
  31. print('targets: {}'.format(targets))
  32. #注意模型默认的模式为训练模式
  33. # model.train()
  34. # output = model(images, targets)
  35. # print(output)
  36. # print(output['loss_classifier'].item())
  37. # For inference
  38. #设置为eval模式并进行检测
  39. model.eval()
  40. x = [torch.rand(3, 300, 400), torch.rand(3, 500, 400)]
  41. predictions = model(x)
  42. print('predictions: {}'.format(predictions))
  43. print('boxes.shape: {}')

提示:关于一个目标检测的完整实例,可能得后面给出。但是我相信给出了上面的三个目标检测模型类别的修改和backbone的修改之后以及一个模型训练的一个小实例之后,读者可以尝试写出一个完整的训练自己的目标检测的模型代码。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/840144
推荐阅读
相关标签
  

闽ICP备14008679号