一 . 编译 darknet 库文件
建立根目录 gpu_based 作为这里的整体根目录:
# cd ~/
# mkdir gpu_based
二 . 编译 darknet 库文件
1. 下载 darknet , 用于编译 GPU 版本的 darknet :
# cd ~/gpu_based
# git clone https://github.com/pjreddie/darknet
# cd darknet
2. 修改配置 Makefile, 并进行编译
修改下面这行
GPU=0
为下面这行
GPU=1
表示使用 GPU,然后执行编译命令
# make
这个时候如果出现错误 “ nvcc: command not found ”, 表示找不到 nvcc 这个命令。而我们发现 /usr/local/cuda/bin 目录下有 nvcc 这个可执行文件。我们继续修改 Makefile
修改下面这行
NVCC=nvcc
为下面这行
NVCC=/usr/local/cuda/bin/nvcc
再执行编译命令
# make
这个时候如果出现错误 “ ... cannot find -lcuda ”, 表示没有找到 lcuda. 这个库, 我们查找使用这个库的地方 " -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand -lstdc++ ", 表示在 /usr/local/cuda/lib64 这个目录下面没有找到 lcuda 这个库文件,然后我们继续修改 Makefile
修改下面这行
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
为下面两行
LDFLAGS+= -L/usr/local/cuda/lib64/stubs -lcuda
LDFLAGS+= -L/usr/local/cuda/lib64 -lcudart -lcublas -lcurand
再执行编译命令
# make
这个时候, 应该会编译生成 libdarknet.a , 大小为 1.5M , CPU 模式的 libdarknet.a 大小为 485K 。显然 GPU 模式包含更多的信息 。
三 . 建立 YOLO 图片识别工程
1. 建立工程目录和文件
# cd ~/gpu_based
# mkdir project
# cd project
# touch yolo_gpu.py
2. 添加如下代码到代码文件 yolo_gpu.py
#coding:utf-8
from ctypes import *
import math
import random
import os
from PIL import Image
def sample(probs):
s = sum(probs)
probs = [a/s for a in probs]
r = random.uniform(0, 1)
for i in range(len(probs)):
r = r - probs[i]
if r <= 0:
return i
return len(probs)-1
def c_array(ctype, values):
return (ctype * len(values))(*values)
class BOX(Structure):
_fields_ = [("x", c_float),
("y", c_float),
("w", c_float),
("h", c_float)]
class IMAGE(Structure):
_fields_ = [("w", c_int),
("h", c_int),
("c", c_int),
("data", POINTER(c_float))]
class METADATA(Structure):
_fields_ = [("classes", c_int),
("names", POINTER(c_char_p))]
# YOLO class
class YOLO(object):
def __init__(self):
self.lib = CDLL("data/libdarknet.so", RTLD_GLOBAL)
self.lib.network_width.argtypes = [c_void_p]
self.lib.network_width.restype = c_int
self.lib.network_height.argtypes = [c_void_p]
self.lib.network_height.restype = c_int
self.predict = self.lib.network_predict_p
self.predict.argtypes = [c_void_p, POINTER(c_float)]
self.predict.restype = POINTER(c_float)
self.make_boxes = self.lib.make_boxes
self.make_boxes.argtypes = [c_void_p]
self.make_boxes.restype = POINTER(BOX)
self.free_ptrs = self.lib.free_ptrs
self.free_ptrs.argtypes = [POINTER(c_void_p), c_int]
self.num_boxes = self.lib.num_boxes
self.num_boxes.argtypes = [c_void_p]
self.num_boxes.restype = c_int
self.make_probs = self.lib.make_probs
self.make_probs.argtypes = [c_void_p]
self.make_probs.restype = POINTER(POINTER(c_float))
self.detect = self.lib.network_predict_p
self.detect.argtypes = [c_void_p, IMAGE, c_float, c_float, c_float, POINTER(BOX), POINTER(POINTER(c_float))]
self.reset_rnn = self.lib.reset_rnn
self.reset_rnn.argtypes = [c_void_p]
self.load_net = self.lib.load_network_p
self.load_net.argtypes = [c_char_p, c_char_p, c_int]
self.load_net.restype = c_void_p
self.free_image = self.lib.free_image
self.free_image.argtypes = [IMAGE]
self.letterbox_image = self.lib.letterbox_image
self.letterbox_image.argtypes = [IMAGE, c_int, c_int]
self.letterbox_image.restype = IMAGE
self.load_meta = self.lib.get_metadata
self.lib.get_metadata.argtypes = [c_char_p]
self.lib.get_metadata.restype = METADATA
self.load_image = self.lib.load_image_color
self.load_image.argtypes = [c_char_p, c_int, c_int]
self.load_image.restype = IMAGE
self.predict_image = self.lib.network_predict_image
self.predict_image.argtypes = [c_void_p, IMAGE]
self.predict_image.restype = POINTER(c_float)
self.network_detect = self.lib.network_detect
self.network_detect.argtypes = [c_void_p, IMAGE, c_float, c_float, c_float, POINTER(BOX), POINTER(POINTER(c_float))]
self.net = self.load_net("data/yolo.cfg", "data/yolo.weights", 0)
self.meta = self.load_meta("data/coco.data")
def classify(self, im):
out = predict_image(net, im)
res = []
for i in range(self.meta.classes):
res.append((self.meta.names[i], out[i]))
res = sorted(res, key=lambda x: -x[1])
return res
def detect_image(self, image):
im = self.load_image(image, 0, 0)
boxes = self.make_boxes(self.net)
probs = self.make_probs(self.net)
num = self.num_boxes(self.net)
thresh = .5
hier_thresh = .5
nms = .45
self.network_detect(self.net, im, thresh, hier_thresh, nms, boxes, probs)
res = []
for j in range(num):
for i in range(self.meta.classes):
if probs[j][i] > 0:
res.append((self.meta.names[i], probs[j][i], (boxes[j].x, boxes[j].y, boxes[j].w, boxes[j].h)))
res = sorted(res, key=lambda x: -x[1])
self.free_image(im)
self.free_ptrs(cast(probs, POINTER(c_void_p)), num)
return res
def split_image(self, input_image, output_path, infos):
# 处理切分信息
image_count = len(infos)
split_info = []
for i in range(0, image_count):
info = infos[i]
if len(info) < 3:
continue
image_name = str(i) + "_" + info[0] + "_" + str(int(info[1] * 100))
image_metric = (int(info[2][0] - info[2][2] / 2.0),
int(info[2][1] - info[2][3] / 2.0),
int(info[2][0] + info[2][2] / 2.0),
int(info[2][1] + info[2][3] / 2.0))
split_info.append((image_name, image_metric))
# 切分图片
img = Image.open(input_image)
for info in split_info:
crop_img = img.crop(info[1])
crop_img.save(os.path.join(output_path, info[0]+".jpeg"))
# end class YOLO
if __name__ == "__main__":
print('start')
yolo = YOLO()
input_image = "*****************/cpu_based/project/test_image/input/2.jpeg"
infos = yolo.detect_image(input_image)
print infos
output_path = "*****************/cpu_based/project/test_image/output/2"
yolo.split_image(input_image, output_path, infos)
print('end')
3. 建立工程数据目录,并copy步骤一中的一些文件以及make生成的一些文件
# cd ~/gpu_based/project
# mkdir data
拷贝代码所需要的 darknet 中模型文件过来 :
# cp ../darknet/data/coco.names ./data/
# cp ../darknet/cfg/coco.data ./data/
# cp ../darknet/cfg/yolo.cfg ./data/
# cp ../darknet/libdarknet.so ./data/
4. 下载 YOLO 预训练的模型, 放置到 data 目录中 :
# wget https://pjreddie.com/media/files/yolo.weights
# mv yolo.weights ./data/
5. 建立测试图片目录
# cd ~/gpu_based/project
# mkdir test_image
# cd test_image
# mkdir in
# mkdir out
6. 测试
放置一张待识别的图片(1.jpg)到input目录 ,
修改 main 函数中,变量 input_images 和 变量 output_path 的值 ,
执行 python yolo_gpu.py
如果能正常输出,则完毕。
如果出现错误 " OSError: /lib64/libc.so.6: version `GLIBC_2.18' not found ", 说明需要 2.18 的 glibc 库 , 而系统不能够提供,继续后续步骤。
7. CentOS 上查看 glibc 的版本
[******90 ~]$ /lib64/libc.so.6
GNU C Library (GNU libc) stable release version 2.17, by Roland McGrath et al.
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.5 20150623 (Red Hat 4.8.5-11).
Compiled on a Linux 3.10.0 system on 2017-06-20.
Available extensions:
The C stubs add-on version 2.1.2.
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
RT using linux kernel aio
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
由上可知,glic 的版本为 2.17
8. 这个时候我们编译一个自己版本的 python , 暂时安装在目录 ~/yolo_gpu/jiang
8.1 # cd ~/yolo_gpu/jiang
将 python 源码 Python-2.7.13.tgz 放在此目录下,进行解压缩
# tar -xvf Python-2.7.13.tgz
# ls
Python-2.7.13 Python-2.7.13.tgz
8.2 指定编译使用的 gcc PATH
Centos 上安装一个 linuxbrew ,
然后 linuxbrew 安装 gcc , 这个 gcc 新版本应该就满足需求了
然后指定用新的 gcc 来编译安装 python .
export PATH=~/.linuxbrew/Cellar/gcc/5.3.0/bin:$PATH
8.3 Makefile 相关
建立 python 安装目录
# mkdir python
进行 configure 配置
# cd Python-2.7.13
# ./configure --prefix=/home/JiangMengYa/work/object_detection_1_by_yolo_gpu/jiang/python --enable-unicode=ucs4
然后
# make -j && make install
如果需要安装第三方python库,则指定 target
pip install --target=/home/JiangMengYa/work/object_detection_1_by_yolo_gpu/jiang/python/lib/python2.7/site-packages pillow
8.3 再测试
# cd ~/yolo_gpu/
# LD_LIBRARY_PATH=/usr/lib64/nvidia/:/usr/local/cuda-8.0/lib64/ ./jiang/python/bin/python yolo_gpu.py
( 具体版本路径按照自己的进行修改即可 )
Should be OK !
输出 :
start.
layer filters size input output
0 conv 32 3 x 3 / 1 608 x 608 x 3 -> 608 x 608 x 32
1 max 2 x 2 / 2 608 x 608 x 32 -> 304 x 304 x 32
2 conv 64 3 x 3 / 1 304 x 304 x 32 -> 304 x 304 x 64
3 max 2 x 2 / 2 304 x 304 x 64 -> 152 x 152 x 64
4 conv 128 3 x 3 / 1 152 x 152 x 64 -> 152 x 152 x 128
5 conv 64 1 x 1 / 1 152 x 152 x 128 -> 152 x 152 x 64
6 conv 128 3 x 3 / 1 152 x 152 x 64 -> 152 x 152 x 128
7 max 2 x 2 / 2 152 x 152 x 128 -> 76 x 76 x 128
8 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256
9 conv 128 1 x 1 / 1 76 x 76 x 256 -> 76 x 76 x 128
10 conv 256 3 x 3 / 1 76 x 76 x 128 -> 76 x 76 x 256
11 max 2 x 2 / 2 76 x 76 x 256 -> 38 x 38 x 256
12 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512
13 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256
14 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512
15 conv 256 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 256
16 conv 512 3 x 3 / 1 38 x 38 x 256 -> 38 x 38 x 512
17 max 2 x 2 / 2 38 x 38 x 512 -> 19 x 19 x 512
18 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024
19 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512
20 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024
21 conv 512 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 512
22 conv 1024 3 x 3 / 1 19 x 19 x 512 -> 19 x 19 x1024
23 conv 1024 3 x 3 / 1 19 x 19 x1024 -> 19 x 19 x1024
24 conv 1024 3 x 3 / 1 19 x 19 x1024 -> 19 x 19 x1024
25 route 16
26 conv 64 1 x 1 / 1 38 x 38 x 512 -> 38 x 38 x 64
27 reorg / 2 38 x 38 x 64 -> 19 x 19 x 256
28 route 27 24
29 conv 1024 3 x 3 / 1 19 x 19 x1280 -> 19 x 19 x1024
30 conv 425 1 x 1 / 1 19 x 19 x1024 -> 19 x 19 x 425
31 detection
mask_scale: Using default '1.000000'
Loading weights from cfg/yolo.weights...Done!
[('person', 0.7448253035545349, (424.37799072265625, 212.38552856445312, 49.312339782714844, 55.479007720947266)), ('person', 0.6640925407409668, (499.82525634765625, 213.6302032470703, 51.024715423583984, 47.674110412597656)), ('bus', 0.5649107694625854, (464.27740478515625, 256.5011901855469, 209.6267547607422, 204.2769775390625)), ('car', 0.5556832551956177, (117.6370849609375, 200.8371124267578, 217.79855346679688, 187.41673278808594)), ('person', 0.5407413840293884, (145.47210693359375, 170.56631469726562, 53.51741409301758, 36.210628509521484))]
end.