当前位置:   article > 正文

【PyTorch】单目标检测项目部署

【PyTorch】单目标检测项目部署

 【PyTorch】单目标检测项目

两种部署情况:部署在 PyTorch 数据集上,以及部署在本地存储的单个映像上。

目录

定义数据集

搭建模型

部署模型


定义数据集

详细参照前文【PyTorch】单目标检测项目

  1. import torchvision
  2. import os
  3. import pandas as pd
  4. import matplotlib.pylab as plt
  5. import torch
  6. %matplotlib inline
  7. # 定义一个函数,用于将a列表中的元素除以b列表中的对应元素,返回一个新的列表
  8. def scale_label(a,b):
  9. # 使用zip函数将a和b列表中的元素一一对应
  10. div = [ai/bi for ai,bi in zip(a,b)]
  11. # 返回新的列表
  12. return div
  13. # 定义一个函数,用于将a列表中的元素乘以b列表中的对应元素,返回一个新的列表
  14. def rescale_label(a,b):
  15. # 使用zip函数将a和b列表中的元素一一对应
  16. div = [ai*bi for ai,bi in zip(a,b)]
  17. # 返回新的列表
  18. return div
  19. import torchvision.transforms.functional as TF
  20. # 定义一个函数,用于调整图像和标签的大小
  21. def resize_img_label(image,label=(0.,0.),target_size=(256,256)):
  22. # 获取原始图像的宽度和高度
  23. w_orig,h_orig = image.size
  24. # 获取目标图像的宽度和高度
  25. w_target,h_target = target_size
  26. # 获取标签的坐标
  27. cx, cy= label
  28. # 调整图像大小
  29. image_new = TF.resize(image,target_size)
  30. # 调整标签大小
  31. label_new= cx/w_orig*w_target, cy/h_orig*h_target
  32. # 定义一个transformer函数,用于对图像和标签进行变换
  33. def transformer(image, label, params):
  34. # 调用resize_img_label函数,对图像和标签进行尺寸调整
  35. image,label=resize_img_label(image,label,params["target_size"])
  36. # 如果params中scale_label参数为True,则调用scale_label函数,对标签进行缩放
  37. if params["scale_label"]:
  38. label=scale_label(label,params["target_size"])
  39. # 将图像转换为张量
  40. image=TF.to_tensor(image)
  41. # 返回变换后的图像和标签
  42. return image, label
  43. from torch.utils.data import Dataset
  44. from PIL import Image
  45. class AMD_dataset(Dataset):
  46. def __init__(self, path2data, transform, trans_params):
  47. # 初始化函数,传入数据路径、转换函数和转换参数
  48. pass
  49. def __len__(self):
  50. # 返回数据集的大小
  51. return len(self.labels)
  52. def __getitem__(self, idx):
  53. # 根据索引获取数据集中的一个样本
  54. pass
  55. # 返回调整后的图像和标签
  56. return image_new,label_new
  57. def __init__(self, path2data, transform, trans_params):
  58. # 获取标签文件路径
  59. path2labels=os.path.join(path2data,"Training400","Fovea_location.xlsx")
  60. # 读取标签文件
  61. labels_df=pd.read_excel(path2labels,engine='openpyxl',index_col="ID")
  62. # 获取标签数据
  63. self.labels = labels_df[["Fovea_X","Fovea_Y"]].values
  64. # 获取图片名称
  65. self.imgName=labels_df["imgName"]
  66. # 获取图片ID
  67. self.ids=labels_df.index
  68. # 获取图片全路径
  69. self.fullPath2img=[0]*len(self.ids)
  70. for id_ in self.ids:
  71. # 根据图片名称判断图片类型
  72. if self.imgName[id_][0]=="A":
  73. prefix="AMD"
  74. else:
  75. prefix="Non-AMD"
  76. # 获取图片全路径
  77. self.fullPath2img[id_-1]=os.path.join(path2data,"Training400",prefix,self.imgName[id_])
  78. # 获取数据转换函数
  79. self.transform = transform
  80. # 获取数据转换参数
  81. self.trans_params=trans_params
  82. def __getitem__(self, idx):
  83. # 打开指定索引的图像
  84. image = Image.open(self.fullPath2img[idx])
  85. # 获取指定索引的标签
  86. label= self.labels[idx]
  87. # 对图像和标签进行变换
  88. image,label = self.transform(image,label,self.trans_params)
  89. # 返回变换后的图像和标签
  90. return image, label
  91. #重写
  92. AMD_dataset.__init__=__init__
  93. AMD_dataset.__getitem__=__getitem__
  94. path2data="./data/"
  95. #验证参数
  96. trans_params_val={
  97. "target_size" : (256, 256),
  98. "p_hflip" : 0.0,
  99. "p_vflip" : 0.0,
  100. "p_shift" : 0.0,
  101. "p_brightness": 0.0,
  102. "p_contrast": 0.0,
  103. "p_gamma": 0.0,
  104. "gamma": 0.0,
  105. "scale_label": True,
  106. }
  107. amd_ds2=AMD_dataset(path2data,transformer,trans_params_val)
  108. from sklearn.model_selection import ShuffleSplit
  109. sss = ShuffleSplit(n_splits=1, test_size=0.2, random_state=0)
  110. indices=range(len(amd_ds2))
  111. for train_index, val_index in sss.split(indices):
  112. print(len(train_index))
  113. print("-"*10)
  114. print(len(val_index))
  115. from torch.utils.data import Subset
  116. # 创建一个Subset对象,将amd_ds2数据集按照val_index索引进行划分,得到验证集val_ds
  117. val_ds=Subset(amd_ds2,val_index)
  118. from torch.utils.data import DataLoader
  119. # 创建一个DataLoader对象,用于加载验证集数据
  120. val_dl = DataLoader(val_ds, batch_size=16, shuffle=False)

 

搭建模型

 详细参照前文【PyTorch】单目标检测项目

  1. import torch.nn as nn
  2. import torch.nn.functional as F
  3. class Net(nn.Module):
  4. def __init__(self, params):
  5. super(Net, self).__init__()
  6. def forward(self, x):
  7. return x
  8. def __init__(self, params):
  9. super(Net, self).__init__()
  10. C_in,H_in,W_in=params["input_shape"]
  11. init_f=params["initial_filters"]
  12. num_outputs=params["num_outputs"]
  13. self.conv1 = nn.Conv2d(C_in, init_f, kernel_size=3,stride=2,padding=1)
  14. self.conv2 = nn.Conv2d(init_f+C_in, 2*init_f, kernel_size=3,stride=1,padding=1)
  15. self.conv3 = nn.Conv2d(3*init_f+C_in, 4*init_f, kernel_size=3,padding=1)
  16. self.conv4 = nn.Conv2d(7*init_f+C_in, 8*init_f, kernel_size=3,padding=1)
  17. self.conv5 = nn.Conv2d(15*init_f+C_in, 16*init_f, kernel_size=3,padding=1)
  18. self.fc1 = nn.Linear(16*init_f, num_outputs)
  19. def forward(self, x):
  20. identity=F.avg_pool2d(x,4,4)
  21. x = F.relu(self.conv1(x))
  22. x = F.max_pool2d(x, 2, 2)
  23. x = torch.cat((x, identity), dim=1)
  24. identity=F.avg_pool2d(x,2,2)
  25. x = F.relu(self.conv2(x))
  26. x = F.max_pool2d(x, 2, 2)
  27. x = torch.cat((x, identity), dim=1)
  28. identity=F.avg_pool2d(x,2,2)
  29. x = F.relu(self.conv3(x))
  30. x = F.max_pool2d(x, 2, 2)
  31. x = torch.cat((x, identity), dim=1)
  32. identity=F.avg_pool2d(x,2,2)
  33. x = F.relu(self.conv4(x))
  34. x = F.max_pool2d(x, 2, 2)
  35. x = torch.cat((x, identity), dim=1)
  36. x = F.relu(self.conv5(x))
  37. x=F.adaptive_avg_pool2d(x,1)
  38. x = x.reshape(x.size(0), -1)
  39. x = self.fc1(x)
  40. return x
  41. Net.__init__=__init__
  42. Net.forward=forward
  43. params_model={
  44. "input_shape": (3,256,256),
  45. "initial_filters": 16,
  46. "num_outputs": 2,
  47. }
  48. model = Net(params_model)
  49. model.eval()
  50. if torch.cuda.is_available():
  51. device = torch.device("cuda")
  52. model=model.to(device)

部署模型

  1. path2weights="./models/weights.pt"
  2. # 加载模型权重
  3. model.load_state_dict(torch.load(path2weights))
  4. # 定义设备为GPU
  5. device = torch.device("cuda")
  6. # 定义一个函数,用于计算模型在数据集上的损失和指标
  7. def loss_epoch(model,loss_func,dataset_dl,sanity_check=False,opt=None):
  8. # 初始化运行损失和运行指标
  9. running_loss=0.0
  10. running_metric=0.0
  11. # 获取数据集的长度
  12. len_data=len(dataset_dl.dataset)
  13. # 遍历数据集
  14. for xb, yb in dataset_dl:
  15. # 将标签堆叠成一维张量
  16. yb=torch.stack(yb,1)
  17. # 将标签转换为浮点型,并移动到GPU上
  18. yb=yb.type(torch.float32).to(device)
  19. # 将输入数据移动到GPU上,并获取模型输出
  20. output=model(xb.to(device))
  21. # 计算当前批次的损失和指标
  22. loss_b,metric_b=loss_batch(loss_func, output, yb, opt)
  23. # 累加损失
  24. running_loss+=loss_b
  25. # 如果指标不为空,则累加指标
  26. if metric_b is not None:
  27. running_metric+=metric_b
  28. # 如果是进行sanity check,则只计算一个批次
  29. if sanity_check is True:
  30. break
  31. # 计算平均损失
  32. loss=running_loss/float(len_data)
  33. # 计算平均指标
  34. metric=running_metric/float(len_data)
  35. # 返回平均损失和平均指标
  36. return loss, metric
  37. # 将中心点坐标和宽高转换为边界框坐标
  38. def cxcy2bbox(cxcy,w=50./256,h=50./256):
  39. # 创建一个与cxcy形状相同的张量,每个元素都为w
  40. w_tensor=torch.ones(cxcy.shape[0],1,device=cxcy.device)*w
  41. # 创建一个与cxcy形状相同的张量,每个元素都为h
  42. h_tensor=torch.ones(cxcy.shape[0],1,device=cxcy.device)*h
  43. # 将cxcy的第一列提取出来,并增加一个维度
  44. cx=cxcy[:,0].unsqueeze(1)
  45. # 将cxcy的第二列提取出来,并增加一个维度
  46. cy=cxcy[:,1].unsqueeze(1)
  47. # 将cx、cy、w_tensor、h_tensor按列拼接起来
  48. boxes=torch.cat((cx,cy, w_tensor, h_tensor), -1)
  49. # 将boxes的第一列和第二列分别减去w_tensor和h_tensor的一半,然后将结果按行拼接起来
  50. return torch.cat((boxes[:, :2] - boxes[:, 2:]/2,boxes[:, :2] + boxes[:, 2:]/2), 1)
  51. # 定义一个函数metrics_batch,用于计算输出和目标之间的交并比
  52. def metrics_batch(output, target):
  53. # 将输出和目标转换为边界框格式
  54. output=cxcy2bbox(output)
  55. target=cxcy2bbox(target)
  56. # 计算输出和目标之间的交并比
  57. iou=torchvision.ops.box_iou(output, target)
  58. # 返回交并比的和
  59. return torch.diagonal(iou, 0).sum().item()
  60. # 定义一个函数,用于计算损失函数、输出和目标之间的损失值
  61. def loss_batch(loss_func, output, target, opt=None):
  62. # 计算输出和目标之间的损失值
  63. loss = loss_func(output, target)
  64. # 计算输出和目标之间的度量值
  65. metric_b = metrics_batch(output,target)
  66. # 如果opt不为空,则执行反向传播和优化
  67. if opt is not None:
  68. opt.zero_grad()
  69. loss.backward()
  70. opt.step()
  71. # 返回损失值和度量值
  72. return loss.item(), metric_b
  73. # 定义损失函数,使用SmoothL1Loss,reduction参数设置为sum
  74. loss_func=nn.SmoothL1Loss(reduction="sum")
  75. # 在不计算梯度的情况下,计算模型在验证集上的损失和指标
  76. with torch.no_grad():
  77. loss,metric=loss_epoch(model,loss_func,val_dl)
  78. # 打印损失和指标
  79. print(loss,metric)

 

  1. from PIL import ImageDraw
  2. import numpy as np
  3. import torchvision.transforms.functional as tv_F
  4. np.random.seed(0)
  5. import matplotlib.pylab as plt
  6. %matplotlib inline
  7. def show_tensor_2labels(img,label1,label2,w_h=(50,50)):
  8. # 将label1和label2按照img的shape进行缩放
  9. label1=rescale_label(label1,img.shape[1:])
  10. label2=rescale_label(label2,img.shape[1:])
  11. # 将img转换为PIL图像
  12. img=tv_F.to_pil_image(img)
  13. # 获取w_h的宽度和高度
  14. w,h=w_h
  15. # 获取label1的坐标
  16. cx,cy=label1
  17. # 在img上绘制一个绿色的矩形
  18. draw = ImageDraw.Draw(img)
  19. draw.rectangle(((cx-w/2, cy-h/2), (cx+w/2, cy+h/2)),outline="green",width=2)
  20. # 获取label2的坐标
  21. cx,cy=label2
  22. # 在img上绘制一个红色的矩形
  23. draw.rectangle(((cx-w/2, cy-h/2), (cx+w/2, cy+h/2)),outline="red",width=2)
  24. # 显示img
  25. plt.imshow(np.asarray(img))
  26. # 生成一个长度为10的随机整数数组,数组中的元素为0到len(val_ds)之间的随机整数
  27. rndInds=np.random.randint(len(val_ds),size=10)
  28. # 打印生成的随机整数数组
  29. print(rndInds)

  1. # 设置图像大小
  2. plt.rcParams['figure.figsize'] = (15, 10)
  3. # 调整子图之间的间距
  4. plt.subplots_adjust(wspace=0.0, hspace=0.15)
  5. # 遍历随机索引
  6. for i,rndi in enumerate(rndInds):
  7. # 获取图像和标签
  8. img,label=val_ds[rndi]
  9. # 获取图像的宽度和高度
  10. h,w=img.shape[1:]
  11. # 不计算梯度
  12. with torch.no_grad():
  13. # 获取模型预测的标签
  14. label_pred=model(img.unsqueeze(0).to(device))[0].cpu()
  15. # 绘制子图
  16. plt.subplot(2,3,i+1)
  17. # 显示图像和标签
  18. show_tensor_2labels(img,label,label_pred)
  19. # 将标签转换为边界框
  20. label_bb=cxcy2bbox(torch.tensor(label).unsqueeze(0))
  21. # 将模型预测的标签转换为边界框
  22. label_pred_bb=cxcy2bbox(label_pred.unsqueeze(0))
  23. # 计算IOU
  24. iou=torchvision.ops.box_iou(label_bb, label_pred_bb)
  25. # 设置标题
  26. plt.title("%.2f" %iou.item())
  27. # 如果索引大于4,则跳出循环
  28. if i>4:
  29. break

  1. # 定义一个函数,用于加载图片和标签
  2. def load_img_label(labels_df,id_):
  3. # 获取图片名称
  4. imgName=labels_df["imgName"]
  5. # 判断图片名称是否以"A"开头
  6. if imgName[id_][0]=="A":
  7. # 如果是,则前缀为"AMD"
  8. prefix="AMD"
  9. else:
  10. # 否则,前缀为"Non-AMD"
  11. prefix="Non-AMD"
  12. # 拼接图片路径
  13. fullPath2img=os.path.join(path2data,"Training400",prefix,imgName[id_])
  14. # 打开图片
  15. img = Image.open(fullPath2img)
  16. # 获取图片中心点坐标
  17. x=labels_df["Fovea_X"][id_]
  18. y=labels_df["Fovea_Y"][id_]
  19. # 返回图片和中心点坐标
  20. label=(x,y)
  21. return img,label
  22. # 定义标签文件路径
  23. path2labels=os.path.join(path2data,"Training400","Fovea_location.xlsx")
  24. # 读取标签文件,使用openpyxl引擎,将ID列作为索引
  25. labels_df=pd.read_excel(path2labels,engine='openpyxl',index_col="ID")
  26. # 加载图片和标签,使用标签文件中的第一行数据
  27. img,label=load_img_label(labels_df,1)
  28. # 打印图片和标签的大小
  29. print(img.size, label)
  30. # 调整图片和标签的大小为256x256
  31. img,label=resize_img_label(img,label,target_size=(256,256))
  32. # 打印调整后的图片和标签的大小
  33. print(img.size, label)
  34. # 将图片转换为张量
  35. img=TF.to_tensor(img)
  36. # 将标签缩放到256x256
  37. label=scale_label(label,(256,256))
  38. # 打印转换后的图片的形状
  39. print(img.shape)
  40. # 在不计算梯度的情况下,使用模型对图片进行预测
  41. with torch.no_grad():
  42. label_pred=model(img.unsqueeze(0).to(device))[0].cpu()
  43. # 显示图片和标签以及预测结果
  44. show_tensor_2labels(img,label,label_pred)

 

  1. import time
  2. # 定义一个空列表,用于存储每次推理的时间
  3. elapsed_times=[]
  4. # 不计算梯度,进行推理
  5. with torch.no_grad():
  6. # 循环100
  7. for k in range(100):
  8. # 记录开始时间
  9. start=time.time()
  10. # 对输入图片进行推理,并获取预测结果
  11. label_pred=model(img.unsqueeze(0).to(device))[0].cpu()
  12. # 计算推理时间
  13. elapsed=time.time()-start
  14. # 将每次推理的时间添加到列表中
  15. elapsed_times.append(elapsed)
  16. # 打印每次推理的平均时间
  17. print("inference time per image: %.4f s" %np.mean(elapsed_times))

 

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

闽ICP备14008679号