classification_performance_loss_test.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. """
  2. 针对图像分类模型的测试性能损失脚本,通过比较推理过程中CPU、GPU占用、推理时间来进行计算
  3. 需要安装指定python库实现功能
  4. pip install psutil gputil pynvml
  5. """
  6. import argparse
  7. import os
  8. import psutil
  9. import GPUtil
  10. import numpy as np
  11. import time
  12. from threading import Thread
  13. import onnxruntime as ort
  14. from PIL import Image
  15. # 定义监控函数
  16. class UsageMonitor:
  17. def __init__(self, interval=0.5):
  18. self.interval = interval
  19. self.cpu_usage = []
  20. self.gpu_usage = []
  21. self.running = False
  22. def start(self):
  23. self.running = True
  24. self.monitor_thread = Thread(target=self._monitor)
  25. self.monitor_thread.start()
  26. def _monitor(self):
  27. while self.running:
  28. # 记录 CPU 使用率
  29. self.cpu_usage.append(psutil.cpu_percent(interval=None))
  30. # 记录 GPU 使用率
  31. gpus = GPUtil.getGPUs()
  32. if gpus:
  33. self.gpu_usage.append(gpus[0].load * 100) # 获取第一个 GPU 的使用率
  34. else:
  35. self.gpu_usage.append(0) # 若没有 GPU 则记为 0
  36. time.sleep(self.interval)
  37. def stop(self):
  38. self.running = False
  39. self.monitor_thread.join()
  40. def get_average_usage(self):
  41. avg_cpu_usage = np.mean(self.cpu_usage)
  42. avg_gpu_usage = np.mean(self.gpu_usage)
  43. return avg_cpu_usage, avg_gpu_usage
  44. def process_image(image_path, transpose=True):
  45. """
  46. 图片处理
  47. :param image_path: 图片路径
  48. :param transpose: 是否进行维度转换,在使用pytorch框架训练出来的权重需要进行维度转换,tensorflow、keras框架不需要
  49. :return:
  50. """
  51. # 打开图像并转换为RGB
  52. image = Image.open(image_path).convert("RGB")
  53. # 调整图像大小
  54. image = image.resize((224, 224))
  55. # 转换为numpy数组并归一化
  56. image_array = np.array(image) / 255.0 # 将像素值缩放到[0, 1]
  57. # 进行标准化
  58. mean = np.array([0.485, 0.456, 0.406])
  59. std = np.array([0.229, 0.224, 0.225])
  60. image_array = (image_array - mean) / std
  61. if transpose:
  62. image_array = image_array.transpose((2, 0, 1)).copy()
  63. return image_array.astype(np.float32)
  64. def batch_predict_images(session, image_dir, target_class, batch_size=10, pytorch=True):
  65. """
  66. 对指定图片文件夹图片进行批量检测
  67. :param session: onnx runtime session
  68. :param image_dir: 待推理的图像文件夹
  69. :param target_class: 目标分类
  70. :param batch_size: 每批图片数量, 默认为10
  71. :param pytorch: 模型是否使用pytorch框架训练出的权重导出的onnx文件,默认为True
  72. :return: 检测结果
  73. """
  74. image_files = [f for f in os.listdir(image_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
  75. results = {}
  76. input_name = session.get_inputs()[0].name
  77. correct_predictions = 0
  78. total_predictions = 0
  79. for i in range(0, len(image_files), batch_size):
  80. batch_files = image_files[i:i + batch_size]
  81. batch_images = []
  82. for image_file in batch_files:
  83. image_path = os.path.join(image_dir, image_file)
  84. image = process_image(image_path, pytorch)
  85. batch_images.append(image)
  86. # 将批次图片堆叠成 (batch_size, 3, 224, 224) 维度
  87. batch_images = np.stack(batch_images)
  88. # 执行预测
  89. outputs = session.run(None, {input_name: batch_images})
  90. # 提取预测结果
  91. for j, image_file in enumerate(batch_files):
  92. predicted_class = np.argmax(outputs[0][j]) # 假设输出是每类的概率
  93. results[image_file] = predicted_class
  94. total_predictions += 1
  95. # 比较预测结果与目标分类
  96. if predicted_class == target_class:
  97. correct_predictions += 1
  98. # 计算准确率
  99. accuracy = correct_predictions / total_predictions if total_predictions > 0 else 0
  100. return accuracy
  101. # 模型推理函数
  102. def model_inference(model_filename, val_dataset_dir):
  103. """
  104. 模型推理验证集目录下所有图片
  105. :param model_filename: 模型文件
  106. :param val_dataset_dir: 验证集图片目录
  107. :return: 验证集推理准确率
  108. """
  109. # 以下使用GPU进行推理出现问题,需要较新的CUDA版本,默认使用CPU进行推理
  110. # if ort.get_available_providers():
  111. # session = ort.InferenceSession(model_filename, providers=['CUDAExecutionProvider'])
  112. # else:
  113. # session = ort.InferenceSession(model_filename)
  114. session = ort.InferenceSession(model_filename)
  115. accuracy = 0
  116. class_num = 0
  117. index = 0
  118. for class_dir in os.listdir(val_dataset_dir):
  119. class_path = os.path.join(val_dataset_dir, class_dir)
  120. # 检查是否为目录
  121. if not os.path.isdir(class_path):
  122. continue
  123. class_num += 1
  124. is_pytorch = False if "keras" in model_filename or "tensorflow" in model_filename else True
  125. batch_result = batch_predict_images(session, class_path, index, pytorch=is_pytorch)
  126. accuracy += batch_result
  127. index += 1
  128. print(f"class_num: {class_num}, index: {index}")
  129. return accuracy * 1.0 / class_num
  130. if __name__ == '__main__':
  131. parser = argparse.ArgumentParser(description='模型推理性能验证脚本')
  132. parser.add_argument('--origin_model_file', default=None, type=str, help='待测试原始模型的onnx文件')
  133. parser.add_argument('--watermark_model_file', default=None, type=str, help='待测试水印模型的onnx文件')
  134. parser.add_argument('--val_dataset_dir', default=None, type=str, help='验证集目录')
  135. args, _ = parser.parse_known_args()
  136. if args.origin_model_file is None:
  137. raise Exception("待测试模型的onnx文件不可为空")
  138. if args.val_dataset_dir is None:
  139. raise Exception("验证集目录不可为空")
  140. monitor = UsageMonitor(interval=0.5) # 每隔 0.5 秒采样一次
  141. monitor.start()
  142. # 记录推理开始时间
  143. start_time = time.time()
  144. # 进行模型推理
  145. accuracy = model_inference(args.origin_model_file, args.val_dataset_dir)
  146. # 记录推理结束时间
  147. end_time = time.time()
  148. monitor.stop()
  149. # 输出平均 CPU 和 GPU 使用率
  150. avg_cpu, avg_gpu = monitor.get_average_usage()
  151. print("原始模型推理性能:")
  152. print(f"平均 CPU 使用率:{avg_cpu:.2f}%")
  153. print(f"平均 GPU 使用率:{avg_gpu:.2f}%")
  154. print(f"模型推理时间: {end_time - start_time:.2f} 秒")
  155. print(f"准确率: {accuracy * 100:.2f}%")
  156. if args.watermark_model_file: # 加入存在比对模型,进行再次推理,然后统计性能指标
  157. time.sleep(20)
  158. monitor2 = UsageMonitor(interval=0.5) # 每隔 0.5 秒采样一次
  159. monitor2.start()
  160. # 记录推理开始时间
  161. start_time2 = time.time()
  162. # 进行模型推理
  163. accuracy2 = model_inference(args.watermark_model_file, args.val_dataset_dir)
  164. # 记录推理结束时间
  165. end_time2 = time.time()
  166. monitor2.stop()
  167. # 输出平均 CPU 和 GPU 使用率
  168. avg_cpu2, avg_gpu2 = monitor2.get_average_usage()
  169. print("水印模型推理性能:")
  170. print(f"平均 CPU 使用率:{avg_cpu2:.2f}%")
  171. print(f"平均 GPU 使用率:{avg_gpu2:.2f}%")
  172. print(f"模型推理时间: {end_time2 - start_time2:.2f} 秒")
  173. print(f"准确率: {accuracy2 * 100:.2f}%")
  174. print("------------------性能指标如下-------------------------")
  175. print(f"嵌入后模型推理准确率下降值:{(accuracy - accuracy2) * 100:.2f}%")
  176. print(f"算力资源消耗增加值:{(avg_cpu2 - avg_cpu):.2f}%")
  177. print(f"运行效率降低值: {((end_time2 - start_time2) - (end_time - start_time)) * 100 / (end_time - start_time):.2f} %")