电竞比分网-中国电竞赛事及体育赛事平台

分享

幾十行python代碼構建一個前后端分離的目標檢測演示網(wǎng)站,代碼開源

 python_lover 2020-05-25

在深度學習更講究實用和落地的今天,構建一個簡單的,可以利用瀏覽器和后端交互的演示性 Demo 可以說非常重要且實用了。本文我們將簡單的介紹如何用幾十行核心代碼構建一個好用的、前后端分離的Demo。

2020年,可以說真的是流年不利。對于人工智能行業(yè)來說,本來就面臨著落地考驗,再加上疫情打擊,很多 AI 企業(yè)甚至面臨現(xiàn)金流壓力。今天元峰得知,“CV四小龍”中兩家,竟然以疫情和集中入職為借口,阻止4月份畢業(yè)的碩士應屆生入職,讓他們推遲到6月份入職,變相讓應屆生主動毀約?;蛟S,他們真的是面臨很大現(xiàn)金流壓力了。

唇亡齒寒,整個行業(yè)不好,瞬間讓筆者也打了個冷戰(zhàn)。作為 AI 領域的一個小小創(chuàng)業(yè)者,衷心希望中國所有的人工智能公司都能走過黎明前的黑暗,走向產(chǎn)品大規(guī)模落地的美好明天。

我們這篇文章還是要介紹技術的,我們開始言歸正傳吧。

1. 為什么要做前后端分離的演示Demo

話說,在2020年,深度學習必須要非常講究落地了。在 AIZOO 成立后這段時間,也有不少客戶聯(lián)系我們合作事宜,其中一個重要的環(huán)節(jié)就是效果演示。在各種演示方式中,最便捷的就是讓用戶在瀏覽器訪問一個網(wǎng)頁,用戶可以自如上的上傳圖片,服務器返回結果,這是最簡單的。

這里再插播一些題外話,我們在  部署了一些利用TensorFlow.js 庫(以下簡稱 TF.js )做的 Demo,但是使用 TF.js 部署,需要把模型下載到用戶的瀏覽器里面運算,對于一些可能要保密的模型,這種方法就無法使用了。我們在開源口罩的 基于TF.js 演示頁面后,筆者在網(wǎng)站后臺看到很多網(wǎng)友把我們的網(wǎng)站扒的一絲不掛,甚至不少開發(fā)者去掉我們的 Logo,部署到了他們的網(wǎng)站上。

對于將模型部署到服務端,一個最簡單的例子就是使用 Flask 框架。Flask 是一個極其簡單的,使用 Python編寫的輕量級 Web 框架, 該框架的使用方法極為簡單,這點,對于后端開發(fā)不太熟悉的算法工程師,可以說是非常友好了。

這里有一個圖像分類的簡單例子,大家可以感受一下 Flask 后端接受一張圖片請求,然后返回結果的方法有多么簡單。

 from flask import Flask, jsonify, request
?
app = Flask(__name__)
?
@app.route('/predict', methods=['POST'])
def predict():
    if request.method == 'POST':
        file = request.files['file']
        print("the file is :", file)
        img_bytes = file.read()  # 讀取文件
        print("file content is:", img_bytes)
        class_id, class_name = get_prediction(image_bytes=img_bytes) # 進行前傳預測
        return jsonify({'class_id': class_id, 'class_name': class_name}) # 返回結果

可以說這樣一個處理邏輯,一目了然,與我們寫的 Python 前傳的代碼差異很小,學習起來很容易。

當然,這只是一個純后端的簡單 Demo,為了方便演示,我們需要有一個前端的頁面。筆者在 Github 上發(fā)現(xiàn)了很多基于 Flask的深度學習演示 Demo,不管是用PyTorch、TF、MXNet還是什么推理框架,他們有一個共同點,那就是基本都是用的Flask的模板頁面做的。

關于模板頁面這種方法,也就是比較典型的前后端不分離的方法,在后端渲染好前端的 HTML 頁面,把結果作為參數(shù)傳給模板的占位符,大家可以感受一下,下面的代碼,就是將分類的額 class_id 和 class_name 傳給 HTML 頁面,渲染一個新的頁面。

 if request.method == 'POST':
     # some inference code.
     return render_template('result.html', class_id=class_id,
                               class_name=class_name)
 return render_template('index.html')

筆者基本不怎么會前端開發(fā),但是總感覺這種方式非常不優(yōu)雅,主要是前后端是綁定的。雖然這種方法很簡單,我們 AIZOO 的合伙人,大概五分鐘就做出來了一個使用這種模板的目標檢測演示 Demo。(關于這位大佬有多牛,大家可以感受一下, 是他一個人利用28天的下班空閑時間開發(fā)出來的,前端、后端、管理端三端一個人搞定, 等我們后面成功了,可以介紹一下元峰的這位朋友,也是我們的合伙人,有多硬核?。?/p>

這種前后端綁定的樣子,筆者不太喜歡,所以筆者就自己學習了一下前后端交互,才發(fā)現(xiàn)其實挺簡單的,幾十行搞定。

下面,我們介紹一下如何做到前后端分離的一個簡單 Demo, 真的非常簡單。

2. 后端代碼

這里的后端還是使用 Flask 框架, 后端的邏輯非常簡單,與剛才的例子基本無異,只需要將前端發(fā)過來的 base64 編碼的圖片解碼,轉成 PIL 的圖像對象,再使用 numpy 轉為矩陣,進行目標檢測的前傳,可以說是非常簡單了。核心代碼如下:

@app.route('/api/', methods=["POST"])
def main_interface():
    # 獲取前端傳送的編碼圖片,去掉無用的字符,例如:"data:image/jpeg;base64,"
    response = request.get_json()
    data_str = response['image']
    point = data_str.find(',')
    base64_str = data_str[point:]  
    
    # 將前端發(fā)過來的base64圖片進行解碼,并轉為 numpy 矩陣 
    image = base64.b64decode(base64_str)       
    img = Image.open(io.BytesIO(image))
    if(img.mode!='RGB'):
        img = img.convert("RGB")
    # convert to numpy array.
    img_arr = np.array(img)
?
    # 進行目標檢測
    results = inference(sess, detection_graph, img_arr, conf_thresh=0.5)
    # 返回結果
    return jsonify(results)

其中inference() 函數(shù)就是進行目標檢測的一個函數(shù),我們使用TensorFlow進行推理,您可以將其替換為PyTorch、MXNet等任意你喜歡的框架。限于篇幅,目標檢測代碼就不展示了,我們將其開源在 Github 上,大家可以去下載查看。

這里,返回給前端的是一個 JSON 字典,如下所示,前端只需在接收這個以后,將 Bounding Box 畫在網(wǎng)頁的 Canvas 控件即可。

{'results': [
     {'name': 'person',
      'conf': '0.7848635', 
      'bbox': [96, 186, 591, 1140]}, 
      {'name': 'person', 
      'conf': '0.6310116', 
      'bbox': [540, 147, 746, 1135]}, 
      {'name': 'handbag',
       'conf': '0.5156933', 
       'bbox': [382, 459, 635, 1125]}]
  }

 

3. 前端怎么做?

對于網(wǎng)頁的前端,只需要設置一個 Button 按鈕控件,用戶點擊上傳圖片以后,將其發(fā)送到后端,等接收到結果以后,將結果畫到 Canvas 上即可。

對于前后端交互,我們使用了 jQuery 中的 ajax 技術。ajax 是一種簡單的進行前后端交互式技術,而 jQuery 庫封裝了很多常用的 JavaScript 方法, 使用起來非常簡單。大家不要被這兩個術語嚇住了,我們的代碼中,用到他們的地方也就十幾行,請看下面代碼:

function communicate(img_base64_url) {
  $.ajax({
    url: "http://localhost:5000/api/",
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({"image": img_base64_url}),
    dataType: "json"
  }).done(function(response_data) {
      drawResult(response_data.results);
  });
}

我們只需要將接收到的 base64 編碼的圖片,使用 ajax發(fā)送到 指定的 URL, 這里是本地的 5000 端口。然后在done函數(shù)中添加回調,也即是處理返回結果的函數(shù),這里的drawResult()函數(shù),也就是將返回的 JSON 結果,畫到canvas控件上。其實,整個前端的核心代碼,也就是前后端交互的核心,就在這 11 行代碼中。

關于怎么畫結果,以及 HTML 如何寫,也都是十幾行代碼搞定的事情。這里就不展示了。大家可以去Github上下載我們的代碼,簡單查看一下就可以了。真的代碼很少、很簡單。

4. 如何運行

大家將代碼從 Github 下載后,在本地只需要運行后端和前端就可以了。

app.py是后端的代碼入口,大家只需要python app.py就可以運行起來了。注意這里大家要先裝好 Flask 和 TensorFlow 1.x版本(1.8 ~1.15應該都可以),沒有的話,只需要用 pip 安裝一下就可以了。

pip install flask 
pip install  tensorflow==1.12 # 1.8 ~ 1.15 理論上都可以,2.x需要修改少量代碼

對于前端部分,index.html 是入口文件,運行也很簡單,如果你使用Python,只需要如下操作:

// python3
python -m http.server
// python2
python -m SimpleHTTPServer

如果你使用 node.js ,只要如下操作:

npm install serve -g // install serve
serve // this will open a mini web serve
// or http-serve
npm install http-server -g
http-server

然后在瀏覽器打開終端顯示的 ip:port 就可以了。頁面長這個樣子:

你可以點擊按鈕上傳,也可以將圖片直接拖到頁面,下面是一個簡單的小動畫。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多