Xem bài hướng dẫn YOLO trước đó
Phải công nhận tác giả đầu tiên của YOLO, Joseph Redmond là một thiên tài vì đã nghĩ ra một thuật quá đỉnh. YOLO 1 lên 3 có quá nhiều cải tiến hay. Tuy nhiên tác giả có vẻ như bận rộn nghiên cứu những ý tưởng mới hơn nên YOLO3 còn rất nhiều điểm bất cập:

  • Không hỗ trợ Windows
  • Tốc độ chưa phải tối ưu
  • Không hỗ trợ OpenCV bản 4.x yêu cầu C++ 11
  • Không hỗ trợ nhận dạng live camera và trả về kết quả trực tuyến....

Alexey AB, một thanh niên người Nga quyết định ra tay giải cứu thế giới lập trình viên (có đến 95% những kẻ chỉ ngồi chờ thư viện ngon để xài lại, trong đó có tôi, bảo vệ trông xe, đón khách, chạy xe ôm có chút thời gian mọn học lập trình là quá mừng nói gì đến việc giải cứu thế giới). Alexey AB phân nhanh (fork) mã nguồn của Joseph Redmon và tạo ra một phiên bản YOLO Darknet https://github.com/AlexeyAB/darknet chạy tốt trên Windows, Linux, Mac và thêm rất nhiều thứ hay ho. Cộng đồng góp sức cũng đông thế nên đây có lẽ là bản fork YOLO tốt nhất hiện nay.

Bài viết này chia sẻ lại kinh nghiệm biên dịch AlexeyAB/darknet trên MacOSX, làm sao để Nvidia CUDA, CUDA Neural Network và cả OpenCV bản 4.1 mới nhất.

Bước 1: Tải mã nguồn về biên dịch

git clone --depth=1 https://github.com/AlexeyAB/darknet
cd darknet
nano Makefile

Trước khi gõ lệnh make hãy chỉnh lại Makefile đã.

Bước 2: Hiểu cơ chế biên dịch mã nguồn mở, giúp bạn xử lý hầu hết các lỗi
Bài viết này thực ra chả liên quan gì đến thuật toán hay kiến thức xử lý ảnh, học máy cả. Nó chỉ xoay quanh vấn đề làm sao biên dịch thành công một dự án viết bằng ngôn ngữ C/C++ liên kết với các thư viện ngoài như OpenCV.

Để biên dịch dự án C/C++ ta cần trình make và Makefile. Makefile là file cấu hình chỉ ra file chạy sẽ phải import header file nào và link đến thư viện nào thế thôi. Bạn hiểu rõ cách thức biên dịch C/C++ trên Linux, Mac, thì sau này dự án mã nguồn mở nào cũng chơi được hết. Ý tôi, tay bảo vệ ngày trông xe, tối học code là vậy.

Một vài YouTube về makefile để các bạn tham khảo

Bước 3: Sửa Makefile của AlexeyAB/darknet
Phần đầu của Makefile bạn có thể bật những lựa chọn sau đây

GPU=1
CUDNN=1
CUDNN_HALF=1
OPENCV=1
AVX=1
OPENMP=0
LIBSO=0
ZED_CAMERA=0

Giải thích từng lựa chọn một nhé

  1. GPU: tận dụng card đồ hoạ Nvidia để tính toán thay vì phụ thuộc vào CPU. Nên bật. Yêu cầu máy có card đồ hoạ Nvidia, đời càng mới càng tốt
  2. CUDNN: thư viện do chính Nvidia để tận dụng GPU cho mạng deep neural network. Tham khảo link này https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html
  3. CUDNN_HALF: Theo như tác giả nói sẽ tăng tốc gấp 2 đến 3 lần trên GPU kiến trúc Volta improved neural network performance Detection 3x times, Training 2 x times on GPU Volta (Tesla V100, Titan V, ...) using Tensor Cores if CUDNN_HALF defined. Vâng con card đồ hoạ TitanV chỉ có 119 triệu đồng thôi các bạn ạ. Lương bảo vệ trông xe, 5 triệu bao ăn uống bữa trưa. Cứ tầm 2 năm chịu khó chạy xe ôm buổi tối là mình mua được TitanV rồi.
  4. OPENCV: tích hợp với thư viện OpenCV. Điểm dễ nhận thấy nhất khi bật chức năng này, nhận dạng sang, là tự bật luôn ảnh kết quả lên thay vì chỉ lưu ra file predicion.
  5. AVX: tập lệnh xử lý tính toán ma trận Intel Avanced Vector Extension. Nếu không dùng GPU, mà bật AVX thì tốc độ xử lý cũng tăng lên Yolo3 85%, Yolo2 20%. Quá tốt còn gì !
  6. OPENMP: thư viện xử lý song song trên nhiều Core. Cái này mình đã thử bật lên nó toàn báo lỗi clang: error: unsupported option '-fopenmp'. Nếu trên Linux lỗi này chữa ngon. Còn trên Mac, các bạn tham khảo bài viết này nhé https://daijiang.name/en/2017/06/21/fopenmp-option-of-clang-error/ . Tạm thời mình tắt nó.
  7. LIBSO: nếu bạn muốn viết một ứng dụng C/C++ hoàn chỉnh tận dụng lại Darknet Yolo thì bật lựa chọn này lên, nó xuất ra thư viện Dynamic Link Library, khi biên dịch thì nhúng vào. Ví dụ mẫu một app console dùng Yolo đây. Lập trình C++ nhìn chung là nhàn nhưng giờ mình có Python rồi nên buổi sau mình viết hướng dẫn lập trình Python gọi vào YOLO nhé.
  8. ZED_CAMERA: chỉ bật nếu bạn dùng ZED camera nhìn được chiều sâu 3D. Loại này chỉ có 499 $ thôi, đặt mua họ gửi đến tận nhà.

Tác giả cũng đã chú thích ở đây rất kỹ rồi
# set GPU=1 and CUDNN=1 to speedup on GPU
# set CUDNN_HALF=1 to further speedup 3 x times (Mixed-precision on Tensor Cores) GPU: Volta, Xavier, Turing and higher
# set AVX=1 and OPENMP=1 to speedup on CPU (if error occurs then set AVX=0)

Nếu bạn dùng những GPU cao cấp của Nvidia thì lệnh ARCH= -gencode arch=compute_XX,code=[sm_XX,compute_XX] . Lệnh này sẽ giúp tận dụng triệt để các tập lệnh tính toán trên từng dòng GPU.

Bước 4: Tích hợp với OpenCV
Đầu tiên cài đặt OpenCV bản mới nhất lên Mac đã. Hướng dẫn cài đặt mình viết ở đây. Darknet/Yolo nguyên gốc của Joseph Redmond chỉ hỗ trợ OpenCV 3.x vì OpenCV 4.x yêu cầu bật lựa chọn hỗ trợ C++11 khi biên dịch. Bản Darknet của Alexey BB hỗ trợ C++11 nên mình rất là ưng.

Tuy nhiên bạn phải sửa đoạn này trong Makefile nếu bạn cài OpenCV 4.x

ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv`
COMMON+= `pkg-config --cflags opencv`
endif

thành (thêm số 4 vào opencv). Bản chất là lúc biên dịch giai đoạn link, make sẽ tìm đến thư mục /usr/local/lib, OpenCV thấp hơn 4 thì là opencv, còn từ bản 4.x sẽ có file /usr/local/lib/opencv4

ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv4`
COMMON+= `pkg-config --cflags opencv4`
endif

Bước 5: Bật CUDNN
Vào đây https://developer.nvidia.com/cudnn tải thư viện cudnn về, bung file nén ra và copy vào thư mục /usr/local/cudnn/
Sửa đoạn này Makefile

ifeq ($(CUDNN), 1)
COMMON+= -DCUDNN
ifeq ($(OS),Darwin) #MAC
CFLAGS+= -DCUDNN -I/usr/local/cuda/include
LDFLAGS+= -L/usr/local/cuda/lib -lcudnn

thành

ifeq ($(CUDNN), 1)
COMMON+= -DCUDNN
ifeq ($(OS),Darwin) #MAC
CFLAGS+= -DCUDNN -I/usr/local/cudnn/include
LDFLAGS+= -L/usr/local/cudnn/lib -lcudnn

Cách 2 là bạn copy header cudnn.h vào /usr/local/cuda/include và toàn bộ file trong thư mục lib của cudnn vào /usr/local/cuda/lib

Bước 6: CUDNN_HALF=1 và AVX=1
Bước này chỉ cần bật lên, mà không phải làm gì cả

Bước 7: Sửa biến môi trường trong bash shell
Mình dùng zsh và OhMyZSH nên gõ

nano ~/.zshrc

Thêm những đoạn lệnh sau. Tất nhiên bạn cần có chút kiến thức Linux, Bash Shell để chỉnh phù hợp với đường dẫn thực tế trên máy của bạn

export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib:/usr/local/cudnn/lib
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig

Bước 8: Biên dịch bằng lệnh make
Lỗi đâu ta lại Google, StackOverflow sửa đến đó. Ví dụ tôi gặp lỗi này
dyld: Library not loaded: /usr/local/opt/ceres-solver/lib/libceres.1.dylib
Đây là lỗi thường gặp khi file binary gọi đến một dynamic library nhưng nó lại chưa được cài đặt. Cách xử lý là tim đúng file mà cài

brew install ceres-solver

Bước 9: Chạy thử

Bạn nhớ đổi tên file data/giaothong.jpg thành đường dẫn đúng đến file ảnh có trên máy tính của bạn

./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/giaothong.jpg

Kết quả là

Nhận dạng bằng AlexeyAB/Darknet - YOLO3
Nhận dạng bằng AlexeyAB/Darknet - YOLO3

Đánh giá hiệu năng AlexeyAB/darknet

Tốc độ xử lý một ảnh bây giờ 228 miliseconds, so với https://pjreddie.com/darknet/yolo/ 0.43 second. Như vậy AlexeyAB/darknet nhanh hơn bản gốc 1.88 lần. Rất đáng kể phải không nào. Hẹn các bạn ở bài tiếp theo binding Yolo với Python nhé hoặc nhận dạng video trực tiếp từ Web Cam.