Darknet (二) YOLO 基于 CentOS GPU 的部署使用

一 . 编译 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.



猜你喜欢

转载自blog.csdn.net/jiangmengya1/article/details/78192133