Kai - Golang實現的目標檢測雲端服務

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

YOLO/Darknet是目前比較流行的Object Detection演算法(後面統一稱為Darknet),在GPU上的表現不但速度快而且準確率很高。但是使用起來不方便,只提供了命令列介面和簡單的Python介面。所以我想用RESTful來實現一個雲端的Darknet服務kai。

選擇用Go的原因不是考慮並發,而是goroutine之間的同步能方便的處理,適合實現Pipeline的功能。問題來了,Darknet是c語言實現的,那Go必須得用cgo進行封裝,才能調用c函數。目標是為了實現三個準系統:1. 圖片檢測 2. 視頻檢測 3. 網路攝影機檢測。為了方便使用我修改了Darknet的部分代碼,然後重新定義下面幾個函數:

// Set a gpu devicevoid set_gpu(int gpu);// Recognize a imagevoid image_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename,    float thresh, float hier_thresh, char *outfile);// Recognize a videovoid video_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename,    float thresh, float hier_thresh, char *outfile);// Recognize a camera streamvoid camera_detector(char *datacfg, char *cfgfile, char *weightfile, int camindex,        float thresh, float hier_thresh, char *outpath);

有了這幾個函數,就好辦了,下面用cgo匯入相應的庫和標頭檔即可:

// #cgo pkg-config: opencv// #cgo linux LDFLAGS: -ldarknet -lm -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand -lcudnn// #cgo darwin LDFLAGS: -ldarknet// #include "yolo.h"import "C"// SetGPU set a gpu device you wantfunc SetGPU(gpu int) {    C.set_gpu(C.int(gpu))}// ImageDetector recognize a imagefunc ImageDetector(dc, cf, wf, fn string, t, ht float64, of ...string) {    ...}// VideoDetector recognize a videofunc VideoDetector(dc, cf, wf, fn string, t, ht float64, of ...string) {    ...}// CameraDetector recognize a camera streamfunc CameraDetector(dc, cf, wf string, i int, t, ht float64, of ...string) {    ...}

這樣對Darknet的封裝go-yolo就完成了。

下面進入主題,介紹一下kai的實現。

kai的設計目標如下:

  • 後端基於Darknet(不支援訓練)
  • 提供RESTful介面進行圖片和視頻的檢測
  • 支援Amazon S3下載和上傳
  • 支援Ftp下載和上傳
  • 支援檢測結果持久化到MongoDB

架構圖是這樣的

這裡重點介紹一下Kai的Pipeline機制,這裡的Pipeline包括下載(Download),檢測(Yolo)和上(Upload)傳這一系列流程。
先上個圖:

這裡的痛點在於下載(Download),檢測(Yolo)和上傳(Upload)這三個步驟可以配置不同的Goroutine數量,而這三步之間是一個同步操作。

  • 首先需要定義3個buffered channel來進行同步
// KaiServer represents the server for processing all job requeststype KaiServer struct {    net.Listener    logger        *logging.Logger    config        types.ServerConfig    listenAddr    string    listenNetwork string    router        *Router    server        *http.Server    db            db.Storage    // jobDownBuff is the buffered channel for job downloading    jobDownBuff chan types.Job    // jobDownBuff is the buffered channel for job todo    jobTodoBuff chan types.Job    // jobDownBuff is the buffered channel for job done    jobDoneBuff chan types.Job}
  • Pipeline的執行流程如下
// Pipeline contains downloading, processing and uploading a jobfunc Pipeline(logger *logging.Logger, config types.ServerConfig, dbInstance db.Storage, jobDownBuff chan types.Job,    jobTodoBuff chan types.Job, jobDoneBuff chan types.Job, job types.Job) {    logger.Infof("pipeline-job %+v", job)    // download a job    setupAndDownloadJob(logger, config.System, dbInstance, job, jobDownBuff)    // jobDownBuff -> jobTodoBuff -> jobDoneBuff    yoloJob(logger, config, dbInstance, jobDownBuff, jobTodoBuff, jobDoneBuff)    // upload a job    uploadJob(logger, dbInstance, jobDoneBuff)}
  • 下載(Download)
// setupAndDownloadJob setup and download jobs into jobDownBufffunc setupAndDownloadJob(logger *logging.Logger, config types.SystemConfig,    dbInstance db.Storage, job types.Job, jobDownBuff chan<- types.Job) {    go func() {        logger.Infof("start setup and download a job: %+v", job)        newJob, err := SetupJob(logger, job.ID, dbInstance, config)        job = *newJob        if err != nil {            logger.Error("setup-job failed", err)            return        }        downloadFunc := downloaders.GetDownloadFunc(job.Source)        if err := downloadFunc(logger, config, dbInstance, job.ID); err != nil {            logger.Error("download failed", err)            job.Status = types.JobError            job.Details = err.Error()            dbInstance.UpdateJob(job.ID, job)            return        }        jobDownBuff <- job    }()}
  • 檢測(Yolo)
func yoloJob(logger *logging.Logger, config types.ServerConfig, dbInstance db.Storage,    jobDownBuff <-chan types.Job, jobTodoBuff chan types.Job, jobDoneBuff chan types.Job) {    go func() {        job, ok := <-jobDownBuff        if !ok {            logger.Info("job download buffer is closed")            return        }        logger.Infof("start a yolo job: %+v", job)        // limit the number of job in the jobTodoBuff        jobTodoBuff <- job        jobTodo, ok := <-jobTodoBuff        if !ok {            logger.Info("job todo buffer is closed")            return        }        nGpu := config.System.NGpu        t := yolo.NewTask(config.Yolo, jobTodo.Media.Cate, nGpu, jobTodo.LocalSource, jobTodo.LocalDestination)        logger.Debugf("yolo task: %+v", *t)        yolo.StartTask(t, logger, dbInstance, jobTodo.ID)        jobDoneBuff <- job    }()}
  • 上傳(Upload)
func uploadJob(logger *logging.Logger, dbInstance db.Storage, jobDoneBuff <-chan types.Job) {    go func() {        jobDone, ok := <-jobDoneBuff        if !ok {            logger.Info("job done buffer is closed")            return        }        logger.Infof("start a upload job: %+v", jobDone)        uploadFunc := uploaders.GetUploadFunc(jobDone.Destination)        if err := uploadFunc(logger, dbInstance, jobDone.ID); err != nil {            logger.Error("upload failed", err)            jobDone.Status = types.JobError            jobDone.Details = err.Error()            dbInstance.UpdateJob(jobDone.ID, jobDone)            return        }        logger.Info("erasing temporary files")        if err := CleanSwap(dbInstance, jobDone.ID); err != nil {            logger.Error("erasing temporary files failed", err)        }        jobDone.Status = types.JobFinished        dbInstance.UpdateJob(jobDone.ID, jobDone)        logger.Infof("end a job: %+v", jobDone)    }()}

到此,這個項目主要機制都已經介紹完了,如果大家有興趣的可以去點擊下面的項目首頁。

項目連結:
go-yolo: https://github.com/ZanLabs/go...
kai: https://github.com/ZanLabs/kai

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.