使用Flask部署圖像分類模型

做者|LAKSHAY ARORA
編譯|VK
來源|Analytics Vidhyahtml

概述

  • 瞭解PyTorch和Flask的概況
  • 學習在PyTorch中創建圖像分類模型
  • 瞭解如何使用Flask部署模型。

介紹

當涉及到社交媒體的健康運行時,圖像分類是一個關鍵點。根據特定標籤對內容進行分類能夠代替各類法律法規。它變得很重要,以便對特定的受衆羣體隱藏內容。python

當我在Instagram上瀏覽時,我常常會遇到一些圖片上有「敏感內容」的帖子。我確定你也有。git

任何有關人道主義危機、恐怖主義或暴力的圖片一般被歸類爲「敏感內容」。Instagram如何對圖片進行分類一直讓我很感興趣。這種不斷的好奇心促使我去理解圖像分類的過程。github

大部分圖像是由Instagram部署的圖像分類模型檢測出來的。此外,還有一個基於社區的反饋循環。這是圖像分類最重要的用例之一。web

在本文中,咱們將部署一個圖像分類模型來檢測圖像的類別。json

目錄

  1. 什麼是模型部署?
  2. PyTorch簡介
  3. 什麼是Flask?
  4. 在機器上安裝Flask和PyTorch
  5. 理解問題陳述
  6. 創建預訓練的圖像分類模型
  7. 創建一個圖像Scraper
  8. 建立網頁
  9. 設置Flask項目
  10. 部署模型的工做

什麼是模型部署

在典型的機器學習和深度學習項目中,咱們一般從定義問題陳述開始,而後是數據收集和準備,而後是模型構建,對嗎?flask

一旦咱們成功地構建和訓練了模型,咱們但願它能爲最終用戶所用。後端

所以,咱們必須「部署」模型,以便最終用戶可使用它。模型部署是任何機器學習或深度學習項目的後期階段之一。瀏覽器

在本文中,咱們將在PyTorch中構建一個分類模型,而後學習如何使用Flask部署相同的模型。在咱們進入細節以前,讓咱們先簡單介紹一下PyTorch。服務器

PyTorch簡介

PyTorch是一個基於python的庫,它提供了做爲深度學習開發平臺的靈活性。PyTorch的工做流程與python的科學計算庫NumPy很是接近。

PyTorch被普遍用於構建深度學習模型。如下是PyTorch的一些重要優點

  • 易於使用的API–PyTorch API與python同樣簡單。
  • Python支持—PyTorch與Python完美集成。
  • 動態計算圖——PyTorch爲咱們提供了一個框架來構建計算圖,甚至在運行時改變它們。這對於咱們不知道建立一個神經網絡須要多少內存的狀況頗有價值。

在接下來的章節中,咱們將使用一個預訓練的模型來使用PyTorch來檢測圖像的類別。接下來,咱們將使用Flask進行模型部署。在下一節中,咱們將簡要討論Flask。

什麼是Flask?

Flask是一個用Python編寫的web應用程序框架。它有多個模塊,使web開發人員更容易編寫應用程序,而沒必要擔憂協議管理、線程管理等細節。

Flask爲開發web應用程序提供了多種選擇,併爲咱們提供了構建web應用程序所需的工具和庫。

在機器上安裝Flask和PyTorch

安裝Flask簡單明瞭。這裏,我假設你已經安裝了python3和pip。要安裝Flask,須要運行如下命令:

sudo apt-get install python3-flask

接下來,咱們須要安裝PyTorch。運行本文中提供的代碼不須要有GPU。

!pip install torch torchvision

就這樣!如今讓咱們開始一個問題陳述並創建一個模型。

理解問題陳述

讓咱們討論一下問題陳述,咱們想要建立一個包含以下文本框的網頁(以下所示)。用戶在這裏輸入網址。

這裏的任務是從URL中抓取全部圖像。對於每一個圖像,咱們將使用圖像分類模型預測圖像的類別或類別,並在網頁上按類別呈現圖像。

下面是端到端模型的工做流-

設置項目工做流

  • 模型構建:咱們將使用預訓練的模型Densenet 121來預測圖像類。它能夠在PyTorch的torchvision庫中找到。這裏,咱們的重點不是從頭開始構建一個高度精確的分類模型,而是看看如何部署該模型並在web界面中使用它。
  • 建立一個圖像Scraper:咱們將使用請求和BeautifulSoup庫建立一個web scraper。它將從一個URL下載全部的圖像並將其存儲,這樣咱們就能夠對其進行預測。
  • 設計網頁模板:咱們還將設計一個用戶界面,用戶能夠提交一個網址,也能夠獲得結果,一旦計算。
  • 對圖像進行分類併發送結果:一旦咱們從用戶那裏獲得查詢,咱們將使用該模型預測圖像的類別並將結果發送給用戶。

下面是咱們剛剛看到的步驟的一個表示:

讓咱們討論一下項目所需的全部組成部分:

創建預訓練的圖像分類模型

咱們將使用預訓練的模型Densenet 121對圖像進行分類。

你能夠在這裏下載完整的代碼和數據集。

連接:https://github.com/lakshay-ar...

讓咱們從導入一些必需的庫開始,並從torchvision庫獲取densenet121模型。確保將參數「pretrained」添加爲True。

# 導入所需的庫
import json
import io
import glob
from PIL import Image
from torchvision import models
import torchvision.transforms as transforms

# 將參數「pretraining」傳遞爲「True」,使用預訓練的權重:
model = models.densenet121(pretrained=True)
# 切換到模型到「eval」模式:
model.eval()

如今,咱們將定義一個函數來轉換圖像。它將建立一個轉換管道並根據須要轉換圖像。此方法以字節爲單位獲取圖像數據,並對其應用一系列「轉換」函數並返回張量。這段代碼取自pytorch文檔。

# 定義預處理的函數
def transform_image(image_bytes):
    my_transforms = transforms.Compose([transforms.Resize(255),
                                        transforms.CenterCrop(224),
                                        transforms.ToTensor(),
                                        transforms.Normalize(
                                            [0.485, 0.456, 0.406],
                                            [0.229, 0.224, 0.225])])
    image = Image.open(io.BytesIO(image_bytes))
    return my_transforms(image).unsqueeze(0)

如今,預訓練的模型返回預測類id的索引。PyTorch已經爲它提供了映射,以便咱們能夠看到預測類的名稱。你能夠在這裏下載地圖。它有1000個不一樣的類別。

# 加載由pytorch提供的映射
imagenet_class_mapping = json.load(open('imagenet_class_index.json'))

下面是一個示例:

接下來,咱們將定義一個函數來獲取圖像的類別。爲此,咱們將圖像的路徑做爲惟一的參數傳遞。

首先,它將打開並讀取二進制格式的圖像,而後對其進行轉換。而後將變換後的圖像傳遞給模型,獲得預測類。它將使用映射並返回類名。

# 定義函數來得到圖片的預測
# 它接受參數:圖片路徑並提供預測做爲輸出
def get_category(image_path):
  #以二進制形式讀取圖像
    with open(image_path, 'rb') as file:
        image_bytes = file.read()
    # 變換圖像
    transformed_image = transform_image(image_bytes=image_bytes)
    # 使用模型來預測類
    outputs = model.forward(transformed_image)
    _, category = outputs.max(1)
    # 返回
    predicted_idx = str(category.item())
    return imagenet_class_mapping[predicted_idx]

讓咱們在一些圖像上嘗試此函數:

get_category(image_path='static/sample_1.jpeg')
## ['n02089973', 'English_foxhound']

get_category(image_path='static/sample_2.jpeg')
## ['n11939491', 'daisy']

如今,咱們的模型能夠預測圖像的類。讓咱們從構建圖像Scraper開始。

創建一個圖像Scraper

在本節中,咱們將構建一個web scraper,它將從提供的URL下載圖像。咱們將使用BeautifulSoup庫下載圖像。你能夠自由使用任何其餘庫或API來提供圖像。

咱們將從導入一些必需的庫開始。對於咱們將抓取的每一個url,將建立一個新目錄來存儲圖像。咱們將建立一個函數get_path,它將返回爲該URL建立的文件夾的路徑。

# 導入所需的庫
import requests
from bs4 import BeautifulSoup
import os
import time

def get_path(url):
    return "static/URL_" + str(url.replace("/","_"))
  
headers = {
    'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"
    }

如今,咱們將定義一個函數get_images。它將首先使用get_path函數建立目錄,而後發送對源代碼的請求。從源代碼中,咱們將使用「img」標籤提取源代碼。

在此以後,咱們將只選擇jpeg格式的圖像。也能夠添加png格式的圖像。我已通過濾掉了,由於大多數png格式的圖片都是logo。

最後,啓動計數器並將帶有計數器名稱的圖像保存到指定的目錄中。

# 定義爬取圖像並將其存儲在目錄中的函數
def get_images(url):
   # get the directory path
    path = get_path(url)
    try:
        os.mkdir(path)
    except:
        pass
    # 從URL請求源代碼
    response = requests.request("GET", url, headers=headers)
    # 經過Beautiful Soup解析數據
    data = BeautifulSoup(response.text, 'html.parser')
    # 在源代碼中找到圖像標記
    images = data.find_all('img', src=True)
    # 從全部的圖像標籤中提取src
    image_src = [x['src'] for x in images]
    # 只選擇jpeg
    image_src = [x for x in image_src if x.endswith('.jpeg') ]
    image_count = 1
    # 在指定目錄存儲圖像
    for image in image_src:
        print(image)
        image_file_name = path+'/'+str(image_count)+'.jpeg' 
        print(image_file_name)
        # 以寫入二進制形式打開文件並添加圖像內容來存儲它
        with open(image_file_name, 'wb') as f:
            res = requests.get(image)
            f.write(res.content)
        image_count = image_count+1

讓咱們試試咱們剛剛創造的scraper!

get_images('https://medium.com/@allanishac/9-wild-animals-that-would-make-a-much-better-president-than-donald-trump-b41f960bb171')

如今,建立了一個新目錄,並查看它的外觀。咱們在一個地方下載了全部的圖片。

注意:建議僅根據學習目的使用此圖像Scraper。始終遵循目標網站的robots.txt文件,也稱爲機器人排除協議。這會告訴網絡機器人哪些頁面不能爬。

建立網頁

咱們將建立兩個網頁一個是「home.html另外一個是「image_class.html」.

  • home.html「是默認的,它將有一個文本框,用戶能夠在其中鍵入URL。
  • image_class.html「將幫助咱們按類別渲染圖像。

1.home.html

咱們須要在home.html文件以收集搜索容器中的數據。在form標籤中,咱們將使用post方法,而且數據經過名爲「search」的輸入欄傳遞。

經過這樣作,咱們的後端代碼將可以知道咱們收到了一些名爲「search」的數據。在後端,咱們須要處理併發送數據。

2.image_class.html

在計算結果時,另外一個頁面將呈現以下結果。本頁「image_class.html「將在每次查詢時更新。你能夠看到咱們在網頁上顯示瞭如下信息:

  1. 圖像類別
  2. 圖像
  3. 全部可用圖像類別的頻率計數

下面是執行此操做的代碼:

def get_picture_html(path, tag):
    image_html = """<p> {tag_name} </p> <picture> <img src= "../{path_name}"  height="300" width="400"> </picture>"""
    return image_html.format(tag_name=tag, path_name=path)

# 定義在html文件中添加列表元素的函數
def get_count_html(category, count):
    count_html = """<li> {category_name} : {count_} </li>"""
    return count_html.format(category_name = category, count_ = count)

# 計數
def get_value_count(image_class_dict):
    count_dic = {}
    for category in image_class_dict.values():
        if category in count_dic.keys():
            count_dic[category] = count_dic[category]+1
        else:
            count_dic[category] = 1
    return count_dic

# 函數從image_class字典生成html文件
# 鍵將是圖像的路徑,而值將是與之關聯的類。
def generate_html(image_class_dict):
    picture_html = ""
    count_html = ""
    
    # 循環這些鍵並將圖像添加到html文件中
    for image in image_class_dict.keys():
        picture_html += get_picture_html(path=image, tag= image_class_dict[image])
        
    value_counts = get_value_count(image_class_dict)
    
    # 循環value_counts並向html文件中添加類的計數
    for value in value_counts.keys():
        count_html += get_count_html(value, value_counts[value])

下一步是創建Flask項目,將這些單獨的部分組合起來解決這個挑戰。

設置Flask項目

咱們在項目中完成了如下任務:

  1. 圖像分類模型工做良好,可以對圖像進行分類。
  2. 咱們已經創建了圖像Scraper,將下載圖像並存儲它們。
  3. 咱們已經建立了網頁來獲取並返回結果。

如今咱們須要將全部這些文件鏈接在一塊兒,這樣咱們就能夠有一個工做項目了。

讓咱們看看目錄結構。

注意:請確保將圖像保存在static文件夾和html 文件放在templates文件夾中。Flask只會查找這些名字。若是你改變這些,你會獲得一個錯誤。

運行Flask應用程序

Flask應用程序首先將home.html當有人發送圖像分類請求時,Flask將檢測一個post方法並調用get_image_class函數。

此函數將按如下步驟工做:

  1. 首先,它將發送一個請求來下載並存儲這些圖像。
  2. 接下來,它將把目錄路徑發送到get_prediction.py將計算並以字典形式返回結果的文件。
  3. 最後,它將把這個字典發送給generate_html.py,用戶將返回生成該文件的輸出。

# 導入庫
from flask import Flask, render_template, request, redirect, url_for
from get_images import get_images, get_path, get_directory
from get_prediction import get_prediction
from generate_html import generate_html
from torchvision import models
import json

app = Flask(__name__)

# 映射
imagenet_class_mapping = json.load(open('imagenet_class_index.json'))

# 使用預訓練模型
model = models.densenet121(pretrained=True)
model.eval()

# 定義從url獲取圖像並預測類的函數
def get_image_class(path):
    # 從URL獲取圖像並將其存儲在給定的路徑中
    get_images(path)
    # 根據所提供的目錄預測圖像的圖像類別
    path = get_path(path)
    images_with_tags = get_prediction(model, imagenet_class_mapping, path)
    # 生成html文件以在咱們預測類以後呈現
    generate_html(images_with_tags)

一旦以上步驟完成,咱們就能夠爲用戶提供結果。咱們將調用success函數,該函數將渲染image_class.html文件。

# 根頁面爲"home.html"    
@app.route('/')
def home():
    return render_template('home.html')

@app.route('/', methods=['POST', 'GET'])
def get_data():
    if request.method == 'POST':
        user = request.form['search']
        # 若是搜索按鈕被點擊,調用函數get_image_class
        get_image_class(user)
        #返回image_class.html
        return redirect(url_for('success', name=get_directory(user)))


@app.route('/success/<name>')
def success(name):
    return render_template('image_class.html')


if __name__ == '__main__' :
    app.run(debug=True)

獲取源URL的全部圖像的預測

到目前爲止,咱們已經分別對每幅圖像進行了預測。如今,咱們將用新參數修改get_category函數來解決這個問題。咱們將傳遞包含多個圖像文件的目錄路徑。

如今,咱們將定義另外一個函數get_prediction,它將使用get_category函數並返回字典,其中鍵將是圖像路徑,值將是圖像類。

稍後,咱們將把這個字典發送給generate_html.py將爲咱們建立HTML文件的文件。

# 獲取目錄中出現的全部圖像的類
def get_category(model, imagenet_class_mapping, image_path):
    with open(image_path, 'rb') as file:
        image_bytes = file.read()
    transformed_image = transform_image(image_bytes=image_bytes)
    outputs = model.forward(transformed_image)
    _, category = outputs.max(1)
    
    predicted_idx = str(category.item())
    return imagenet_class_mapping[predicted_idx]

# 它將建立一個圖像路徑和預測類的字典
# 咱們將使用該字典生成html文件。
def get_prediction(model, imagenet_class_mapping, path_to_directory):
    files = glob.glob(path_to_directory+'/*')
    image_with_tags = {}
    for image_file in files:
        image_with_tags[image_file] = get_category(model, imagenet_class_mapping, image_path=image_file)[1]
    return image_with_tags

如今,全部的代碼文件都準備好了,咱們只須要將它們與主文件鏈接起來。

首先,建立一個Flask類的對象,該對象將以當前模塊的名稱做爲參數。route函數將告訴Flask應用程序下一步在網頁上呈現哪一個URL。

部署模型的工做

你能夠在這裏下載完整的代碼和數據集。

連接:https://github.com/lakshay-ar...

如今,咱們運行get_class.py,Flask服務器就能夠在 localhost:5000啓動

打開web瀏覽器並轉到localhost:5000,你將看到默認主頁在那裏呈現。如今,在文本框中輸入任何URL並按search按鈕。這可能須要20-30秒,這取決於網址中的圖片數量和網速。

讓咱們看看部署模型的工做狀況。

視頻:https://cdn.analyticsvidhya.c...

結尾

在本文中,我簡要地解釋了模型部署、Pytorch和Flask的概念。

而後咱們深刻了解了使用PyTorch建立圖像分類模型並將其與Flask一塊兒部署的過程當中涉及的各個步驟。我但願這有助於你構建和部署圖像分類模型。

另外,模型被部署在本地主機上。咱們也能夠把它部署在雲服務上,好比Google Cloud,Amazon,github.io等等,咱們也將在下一篇文章中討論這一點。

原文連接:https://www.analyticsvidhya.c...

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方文檔:
http://sklearn123.com/

歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/

相關文章
相關標籤/搜索