caffe python接口: 使用训练好的VGG16模型 对 单张图片进行分类,输出置信度

本文介绍了一个基于VGG16网络结构的12种动物分类模型,通过修改输出层并重新训练,实现了80%的Top1准确率和95%的Top5准确率。文中提供了详细的预测流程代码及多进程批量分类实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

部分参考:http://blog.youkuaiyun.com/tangwenbo124/article/details/52725263

说明:数据集是上海BOT大赛的(12种动物),网上下载的vgg16权重文件,并且修改输出类别为12,对最后三层全连接网络训练了8个小时,top1准确率为80%,top5准确率95%

使用的测试图片是一个长颈鹿,类别编号是8,结果如下: 
这里写图片描述

 预测源码

#coding:utf-8
import numpy as np
import caffe

bot_data_root = 'F:/bot_data'

# 设置网络结构
net_file = bot_data_root + '/myVGG16/VGG_ILSVRC_16_layers_deploy.prototxt'
# 添加训练之后的网络权重参数
caffe_model = bot_data_root + '/myVGG16/myvggmodel__iter_80000.caffemodel'
# 均值文件
mean_file = bot_data_root + '/myVGG16/mean.npy'
# 设置使用gpu
caffe.set_mode_gpu()

# 构造一个Net
net = caffe.Net(net_file, caffe_model, caffe.TEST)
# 得到data的形状,这里的图片是默认matplotlib底层加载的
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
# matplotlib加载的image是像素[0-1],图片的数据格式[weight,high,channels],RGB
# caffe加载的图片需要的是[0-255]像素,数据格式[channels,weight,high],BGR,那么就需要转换

# channel 放到前面
transformer.set_transpose('data', (2, 0, 1))
transformer.set_mean('data', np.load(mean_file).mean(1).mean(1))
# 图片像素放大到[0-255]
transformer.set_raw_scale('data', 255)
# RGB-->BGR 转换
transformer.set_channel_swap('data', (2, 1, 0))
#设置输入的图片shape,1张,3通道,长宽都是224
net.blobs['data'].reshape(1, 3, 224, 224)
# 加载图片
im = caffe.io.load_image(bot_data_root + '/test_min/Testset 1/0a3e66aea7f64597ad851bfffb929c5a.png')

# 用上面的transformer.preprocess来处理刚刚加载图片
net.blobs['data'].data[...] = transformer.preprocess('data', im)

#输出每层网络的name和shape
for layer_name, blob in net.blobs.iteritems():
    print layer_name + '\t' + str(blob.data.shape)

# 网络开始向前传播啦
output = net.forward()

# 找出最大的那个概率
output_prob = output['out'][0]
print '预测的类别是:', output_prob.argmax()

# 找出最可能的前俩名的类别和概率
top_inds = output_prob.argsort()[::-1][:2]
print "预测最可能的前两名的编号: ",top_inds
print "对应类别的概率是: ", output_prob[top_inds[0]], output_prob[top_inds[1]]
  • 多进程版代码
    • 代码的几点说明:
      • Muti_Classify类中的run方法重写了父类的run()方法(标准run()方法)
      • 解析:代码中只在类中重写了run()方法,但没有显式调用的原因:该知识点在于多进程中run()和stat()的区别,start()函数令进程对象开辟一个单独(子)线程并在其中调用run()方法(而非当前所处线程)。其实是在start()处调用了重写后的run()方法。
#coding:utf-8

#> run like:
#>:
# python2 classify.py 20 '/home/spark/grocery/FER/codes/caffe_2classify/test/test_img.txt' '/home/spark/grocery/FER/codes/caffe_2classify/test/res.txt'

import numpy as np
import sys, os
sys.path.append('/home/spark/caffe-master/python')
import caffe
from multiprocessing import Process


def single_classify(proc_num, proc_id, imgs_text, save_txt):
  net_file = '/home/spark/grocery/FER/codes/caffe_2classify/test/size32_2classify_deploy.prototxt'
  caffe_model = "/home/spark/grocery/FER/codes/caffe_2classify/model/size32_2classify_v2_iter_75000.caffemodel"
  net = caffe.Net(net_file, caffe_model, caffe.TEST)
  caffe.set_mode_gpu()

  with open(imgs_text, 'r') as fr:
    for i, img_and_label in enumerate(fr.readlines()):
      if not i % proc_num == proc_id:
        continue
      img_path = img_and_label.strip('\n').split(' ')[0]
      transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
      transformer.set_transpose('data', (2, 0, 1))
      transformer.set_raw_scale('data', 255)
      transformer.set_channel_swap('data', (2, 1, 0))
      net.blobs['data'].reshape(1, 3, 32, 32)

      im = caffe.io.load_image(img_path)
      net.blobs['data'].data[...] = transformer.preprocess('data', im)
      output = net.forward()

      output_prob = output['out'][0]
      with open(save_txt, 'a') as fw:
        fw.write(img_and_label.strip('\n') +  ' ' + str(output_prob.argmax()) + " " + \
        str(output_prob[0]) + ' ' + str( output_prob[1]) + '\n')


class Multi_Classify(Process):
  def __init__(self, proc_num, proc_id, imgs_text, save_txt):
    super(Multi_Classify, self).__init__()
    self.proc_num = proc_num
    self.proc_id = proc_id
    self.imgs_text = imgs_text
    self.save_txt = save_txt

  def run(self):
    single_classify(self.proc_num, self.proc_id, self.imgs_text, self.save_txt)

def batch_classify(proc_num, imgs_text, save_txt):
  proc_list = []
  for i in range(proc_num):
    proc_list.append(Multi_Classify(proc_num, i, imgs_text, save_txt))

  for proc in proc_list:
    proc.start()

  for proc in proc_list:
    proc.join()

if __name__ == '__main__':
  proc_num = int(sys.argv[1])
  imgs_text = sys.argv[2]
  save_txt = sys.argv[3]
  batch_classify(proc_num, imgs_text, save_txt)
  print("ok")
  • 网络结构代码
    • :下面为旧版本caffe定义的结构,如果使用的是caffe的新版本需要进行修改。如layers-->layer;  type对应的字段以及其字段需加引号;还要注意python执行时的版本。  
name: "VGG_ILSVRC_16_layers"
input: "data"
input_dim: 1
input_dim: 3
input_dim: 224
input_dim: 224
layers {
  bottom: "data"
  top: "conv1_1"
  name: "conv1_1"
  type: CONVOLUTION
  convolution_param {
    num_output: 64
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv1_1"
  top: "conv1_1"
  name: "relu1_1"
  type: RELU
}
layers {
  bottom: "conv1_1"
  top: "conv1_2"
  name: "conv1_2"
  type: CONVOLUTION
  convolution_param {
    num_output: 64
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv1_2"
  top: "conv1_2"
  name: "relu1_2"
  type: RELU
}
layers {
  bottom: "conv1_2"
  top: "pool1"
  name: "pool1"
  type: POOLING
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layers {
  bottom: "pool1"
  top: "conv2_1"
  name: "conv2_1"
  type: CONVOLUTION
  convolution_param {
    num_output: 128
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv2_1"
  top: "conv2_1"
  name: "relu2_1"
  type: RELU
}
layers {
  bottom: "conv2_1"
  top: "conv2_2"
  name: "conv2_2"
  type: CONVOLUTION
  convolution_param {
    num_output: 128
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv2_2"
  top: "conv2_2"
  name: "relu2_2"
  type: RELU
}
layers {
  bottom: "conv2_2"
  top: "pool2"
  name: "pool2"
  type: POOLING
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layers {
  bottom: "pool2"
  top: "conv3_1"
  name: "conv3_1"
  type: CONVOLUTION
  convolution_param {
    num_output: 256
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv3_1"
  top: "conv3_1"
  name: "relu3_1"
  type: RELU
}
layers {
  bottom: "conv3_1"
  top: "conv3_2"
  name: "conv3_2"
  type: CONVOLUTION
  convolution_param {
    num_output: 256
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv3_2"
  top: "conv3_2"
  name: "relu3_2"
  type: RELU
}
layers {
  bottom: "conv3_2"
  top: "conv3_3"
  name: "conv3_3"
  type: CONVOLUTION
  convolution_param {
    num_output: 256
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv3_3"
  top: "conv3_3"
  name: "relu3_3"
  type: RELU
}
layers {
  bottom: "conv3_3"
  top: "pool3"
  name: "pool3"
  type: POOLING
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layers {
  bottom: "pool3"
  top: "conv4_1"
  name: "conv4_1"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv4_1"
  top: "conv4_1"
  name: "relu4_1"
  type: RELU
}
layers {
  bottom: "conv4_1"
  top: "conv4_2"
  name: "conv4_2"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv4_2"
  top: "conv4_2"
  name: "relu4_2"
  type: RELU
}
layers {
  bottom: "conv4_2"
  top: "conv4_3"
  name: "conv4_3"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv4_3"
  top: "conv4_3"
  name: "relu4_3"
  type: RELU
}
layers {
  bottom: "conv4_3"
  top: "pool4"
  name: "pool4"
  type: POOLING
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layers {
  bottom: "pool4"
  top: "conv5_1"
  name: "conv5_1"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv5_1"
  top: "conv5_1"
  name: "relu5_1"
  type: RELU
}
layers {
  bottom: "conv5_1"
  top: "conv5_2"
  name: "conv5_2"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv5_2"
  top: "conv5_2"
  name: "relu5_2"
  type: RELU
}
layers {
  bottom: "conv5_2"
  top: "conv5_3"
  name: "conv5_3"
  type: CONVOLUTION
  convolution_param {
    num_output: 512
    pad: 1
    kernel_size: 3
  }
  blobs_lr: 0
  blobs_lr: 0
}
layers {
  bottom: "conv5_3"
  top: "conv5_3"
  name: "relu5_3"
  type: RELU
}
layers {
  bottom: "conv5_3"
  top: "pool5"
  name: "pool5"
  type: POOLING
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}
layers {
  bottom: "pool5"
  top: "fc6"
  name: "fc6"
  type: INNER_PRODUCT
  inner_product_param {
    num_output: 4096
  }
  blobs_lr: 1
  blobs_lr: 2
}
layers {
  bottom: "fc6"
  top: "fc6"
  name: "relu6"
  type: RELU
}
layers {
  bottom: "fc6"
  top: "fc6"
  name: "drop6"
  type: DROPOUT
  dropout_param {
    dropout_ratio: 0.5
  }
}
layers {
  bottom: "fc6"
  top: "fc7"
  name: "fc7"
  type: INNER_PRODUCT
  inner_product_param {
    num_output: 4096
  }
  blobs_lr: 1
  blobs_lr: 2
}
layers {
  bottom: "fc7"
  top: "fc7"
  name: "relu7"
  type: RELU
}
layers {
  bottom: "fc7"
  top: "fc7"
  name: "drop7"
  type: DROPOUT
  dropout_param {
    dropout_ratio: 0.5
  }
}
layers {
  name: "myfc8"
  bottom: "fc7"
  top: "myfc8"
  type: INNER_PRODUCT

  inner_product_param {
    num_output: 12
    weight_filler {  
      type: "gaussian"  
      std: 0.01  
    }  
    bias_filler {  
      type: "constant"  
      value: 0  
    }  
  }
  blobs_lr: 10
  blobs_lr: 20
}
layers {
  bottom: "myfc8"
  top: "out"
  name: "out"
  type: SOFTMAX
}

 

 

 

<think>好的,用户想了解如何使用OpenPose进行关键点预标注。首先我需要回忆一下OpenPpose的相关知识,并参考提供的资料。 根据引用[3],用户提到需要按照OpenPose的安装步骤进行配置。虽然步骤看起来多,但实际可能不需要全部完成。可能需要先安装依赖项,比如CMake、CUDA、cuDNN等。然后,从GitHub仓库克隆代码,进行编译和安装。这部分可能需要详细说明,但用户可能更关心如何运行预训练模型进行标注。 引用[1]提到可以使用训练的OpenPose模型,并根据任务进行微调。这里可能涉及加载模型、输入图像、获取关键点输出。同时,引用[2]指出OpenPose利用关键点之间的先验关系,比如人体部位的连接,这可能影响标注结果的结构。 接下来,用户需要具体的步骤:安装环境、下载模型、运行推理、处理输出。要确保步骤清晰,可能包括代码示例,比如Python脚本调用OpenPose库,或者使用命令行工具处理图像或视频。 另外,用户可能想知道如何处理输出数据,比如保存关键点坐标到文件,或者可视化结果。需要注意不同版本OpenPose的输出格式可能不同,可能需要调整代码。 还需要提醒用户常见问题,比如环境配置中的CUDA版本兼容性,模型路径是否正确,输入图像的尺寸要求等。如果用户需要批量处理,可能需要编写脚本自动化流程。 最后,相关问题的生成应该围绕OpenPose的优化、应用场景、与其他模型的对比等,帮助用户进一步学习。</think>### 使用 OpenPose 进行关键点预标注的方法和步骤 #### 1. **环境配置** - **安装依赖项** 需要 CUDA、cuDNN(GPU 加速)、CMake、Python 等基础环境支持。 ```bash # 示例:Ubuntu 系统安装基础依赖 sudo apt-get install build-essential cmake libopencv-dev ``` - **克隆 OpenPose 仓库** ```bash git clone https://github.com/CMU-Perceptual-Computing-Lab/openpose.git cd openpose ``` - **编译安装** 根据官方文档选择是否启用 GPU 支持,编译完成后生成可执行文件[^3]。 #### 2. **模型下载与准备** - 下载预训练的人体关键点检测模型(通常包含在 OpenPose 的 `models` 目录中)。 - 模型文件包括:`pose_iter_440000.caffemodel`(权重文件)和 `pose_deploy.prototxt`(网络结构文件)。 #### 3. **关键点检测与标注** - **命令行直接运行** 对单张图像或视频进行关键点检测: ```bash ./build/examples/openpose/openpose.bin --image_dir /path/to/images --write_json /output/json_dir ``` 参数说明: - `--image_dir`:输入图像目录 - `--write_json`:输出关键点坐标的 JSON 文件路径 - `--display 0`:关闭实时预览以提升速度 - **Python API 调用** 通过 Python 脚本批量处理: ```python from openpose import pyopenpose as op params = { "model_folder": "models/", "net_resolution": "368x368", "write_json": "output_json/" } opWrapper = op.WrapperPython() opWrapper.configure(params) opWrapper.execute() ``` #### 4. **结果解析与可视化** - **JSON 文件格式** 关键点坐标以 `[x, y, confidence]` 形式存储,按人体部位索引排列(如 0:鼻子,1:颈部等)。 - **可视化标注结果** 使用 OpenCV 绘制关键点和骨骼连接: ```python import cv2 image = cv2.imread("input.jpg") for keypoint in keypoints: x, y, conf = keypoint if conf > 0.2: # 过滤低置信度点 cv2.circle(image, (int(x), int(y)), 3, (0,255,0), -1) cv2.imwrite("output.jpg", image) ``` #### 5. **微调与优化(可选)** - 若需适配特定场景(如动物姿态),可通过修改网络结构或调整损失函数进行模型微调[^1]。 - 调整参数如 `net_resolution` 平衡速度与精度。 --- ### 注意事项 1. **硬件要求**:GPU 可显著加速推理过程(推荐 NVIDIA 显卡)。 2. **输入格式**:支持图像(JPG/PNG)、视频、甚至实时摄像头输入。 3. **输出扩展**:JSON 文件可直接用于训练其他模型(如动作识别、姿态分类)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值