實作流程

  1. git clone Darknet github

    1
    $ git clone https://github.com/AlexeyAB/darknet.git   
  2. 進入 darknet 修改 Makefile

    • GPU, CUDNN, CUDNN_HALF, OPENCV依照自己的需求做修改,由於要與python串接必須要將LIBSO設為1,產生libdarknet.so
      darknet_Makefile_settings
    • 由於dakrnet的Makefile中,在編譯時會使用到CUDA code, 所以要將ARCH這個flag與你最常使用的GPU做匹配,這樣會加快runtime,詳細說明可參考NVIDIA GPU的架构代号,在Matching CUDA arch and CUDA gencode for various NVIDIA architectures中可以找到自己的GPU所使用的架構,Makefile裡都有附只需要將自己的GPU架構反註解就行了
      darknet_Makefile_GPUsetting
  3. 取得yolov4的weights檔

    1
    $ wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
  4. 編寫Dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #這次環境以ubuntu20.04、cuda11.2.0、cudnn8的image為例
    FROM nvidia/cuda:11.2.0-cudnn8-devel-ubuntu20.04
    RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections

    #安裝darknet的必要依賴
    RUN echo "45.43.38.82 developer.download.nvidia.cn" >> /etc/hosts && \
    apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y build-essential libopencv-dev\
    cmake python3-opencv python3-dev nano

    #這邊安裝vim,只是為了後續方便直接在container內做修改
    RUN apt-get install -y vim

    #安裝python
    RUN apt update \
    && apt install -y --no-install-recommends python3 python3-pip \
    && ln -sf python3 /usr/bin/python \
    && ln -sf pip3 /usr/bin/pip \
    && pip install --upgrade pip \
    && pip install wheel setuptools

    #在container中建立資料夾,並將本地端的darknet複製到container,並且編譯
    RUN mkdir -p /workfolder/ \
    && mkdir -p /workfolder/darknet
    COPY ./darknet /workfolder/darknet
    WORKDIR /workfolder/darknet
    RUN make
    WORKDIR /workfolder/
    CMD ["/bin/bash"]
  5. 建立image

    1
    $ sudo docker image build -t yolo:v01 .
  6. 設定xhost +local:docker

    • 設定x視窗的權限,允許docker使用linux GUI介面,以用來顯示圖片
    • 在 local:docker 前加一個加號(+),代表允許接受由 local:docker 所傳來的 X 繪圖指令。
  7. 運行image

    1
    $ sudo docker run --rm --gpus all -it --network=host -e DISPLAY=$DISPLAY yolo:v01
    • --network:可以設定在執行 Docker Container 要使用哪一種的網路模式,網路模式有 none、container、host、bridge、overlay… 等等的模式,它們是透過使用 Linux 的 libnetwork 所建立出來的網路模式
    • -e DISPLAY=$DISPLAY,設定要將畫面呈現到何處,允許docker使用GUI,以用來顯示圖片
  8. 先測試darknet的主要執行檔

    • 由於image在build時,已經編譯過了,運行image後,可以在darknet的資料夾裡ls,確認裡面是否有libdarknet.so以及darknet的主程式
    • 補充:
      • darknet: AlexeyAB/darknet 的主要執行檔。
      • darknet_image.py, darknet.py, darknet_video.py:透過呼叫 libdarknet.so ,可以在 Python 中直接調用 AlexeyAB/darknet 的一些主要功能,如訓練、測試、載入網路結構等。
      • libdarknet.so: AlexeyAB/darknet 使用 c 語言所撰寫的共享函式庫,可供其他程式語言呼叫。
    • 測試指令
      1
      $ ./darknet detector test cfg/coco.data cfg/yolov4.cfg yolov4.weights -ext_output data/dog.jpg
      prediction
  9. python串接

    • 由於有了 libdarknet.so 檔案,我們可以直接引用darknet.py裡面所提供的函式直接做使用,如此一來就可以自己實作了
    • 以下為參考程式:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      import cv2
      import darknet
      cfg_path = './cfg/yolov4.cfg'
      data_path = './cfg/coco.data'
      weight_path = 'yolov4.weights'
      network, class_names, class_colors = darknet.load_network(cfg_path,
      data_path,
      weight_path)

      width = darknet.network_width(network)
      height = darknet.network_height(network)

      def darknet_helper(img, width, height):
      darknet_image = darknet.make_image(width, height, 3)
      img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
      img_resized = cv2.resize(img_rgb, (width, height),
      interpolation=cv2.INTER_LINEAR)

      # get image ratios to convert bounding boxes to proper size
      img_height, img_width, _ = img.shape
      width_ratio = img_width / width
      height_ratio = img_height / height

      # run model on darknet style image to get detections
      darknet.copy_image_from_bytes(darknet_image, img_resized.tobytes())
      detections = darknet.detect_image(network, class_names, darknet_image)
      darknet.free_image(darknet_image)
      return detections, width_ratio, height_ratio

      # run test on person.jpg image that comes with repository
      image = cv2.imread("./data/dog.jpg")
      detections, width_ratio, height_ratio = darknet_helper(image, width, height)

      for label, confidence, bbox in detections:
      left, top, right, bottom = darknet.bbox2points(bbox)
      left, top, right, bottom = int(left * width_ratio), int(top * height_ratio), int(right * width_ratio), int(bottom * height_ratio)
      cv2.rectangle(image, (left, top), (right, bottom), class_colors[label], 2)
      cv2.putText(image, "{} [{:.2f}]".format(label, float(confidence)),
      (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
      class_colors[label], 2)
      while True:
      cv2.imshow('predictions',image)
      key = cv2.waitKey(90)
      if key == ord('q'): # Esc
      print('break')
      break
      python-prediction

Reference