做者|LAKSHAY ARORA
編譯|VK
來源|Analytics Vidhyahtml
當涉及到社交媒體的健康運行時,圖像分類是一個關鍵點。根據特定標籤對內容進行分類能夠代替各類法律法規。它變得很重要,以便對特定的受衆羣體隱藏內容。python
當我在Instagram上瀏覽時,我常常會遇到一些圖片上有「敏感內容」的帖子。我確定你也有。git
任何有關人道主義危機、恐怖主義或暴力的圖片一般被歸類爲「敏感內容」。Instagram如何對圖片進行分類一直讓我很感興趣。這種不斷的好奇心促使我去理解圖像分類的過程。github
大部分圖像是由Instagram部署的圖像分類模型檢測出來的。此外,還有一個基於社區的反饋循環。這是圖像分類最重要的用例之一。web
在本文中,咱們將部署一個圖像分類模型來檢測圖像的類別。json
在典型的機器學習和深度學習項目中,咱們一般從定義問題陳述開始,而後是數據收集和準備,而後是模型構建,對嗎?flask
一旦咱們成功地構建和訓練了模型,咱們但願它能爲最終用戶所用。後端
所以,咱們必須「部署」模型,以便最終用戶可使用它。模型部署是任何機器學習或深度學習項目的後期階段之一。瀏覽器
在本文中,咱們將在PyTorch中構建一個分類模型,而後學習如何使用Flask部署相同的模型。在咱們進入細節以前,讓咱們先簡單介紹一下PyTorch。服務器
PyTorch是一個基於python的庫,它提供了做爲深度學習開發平臺的靈活性。PyTorch的工做流程與python的科學計算庫NumPy很是接近。
PyTorch被普遍用於構建深度學習模型。如下是PyTorch的一些重要優點
在接下來的章節中,咱們將使用一個預訓練的模型來使用PyTorch來檢測圖像的類別。接下來,咱們將使用Flask進行模型部署。在下一節中,咱們將簡要討論Flask。
Flask是一個用Python編寫的web應用程序框架。它有多個模塊,使web開發人員更容易編寫應用程序,而沒必要擔憂協議管理、線程管理等細節。
Flask爲開發web應用程序提供了多種選擇,併爲咱們提供了構建web應用程序所需的工具和庫。
安裝Flask簡單明瞭。這裏,我假設你已經安裝了python3和pip。要安裝Flask,須要運行如下命令:
sudo apt-get install python3-flask
接下來,咱們須要安裝PyTorch。運行本文中提供的代碼不須要有GPU。
!pip install torch torchvision
就這樣!如今讓咱們開始一個問題陳述並創建一個模型。
讓咱們討論一下問題陳述,咱們想要建立一個包含以下文本框的網頁(以下所示)。用戶在這裏輸入網址。
這裏的任務是從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開始。
在本節中,咱們將構建一個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文件以收集搜索容器中的數據。在form標籤中,咱們將使用post方法,而且數據經過名爲「search」的輸入欄傳遞。
經過這樣作,咱們的後端代碼將可以知道咱們收到了一些名爲「search」的數據。在後端,咱們須要處理併發送數據。
在計算結果時,另外一個頁面將呈現以下結果。本頁「image_class.html「將在每次查詢時更新。你能夠看到咱們在網頁上顯示瞭如下信息:
下面是執行此操做的代碼:
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項目,將這些單獨的部分組合起來解決這個挑戰。
咱們在項目中完成了如下任務:
如今咱們須要將全部這些文件鏈接在一塊兒,這樣咱們就能夠有一個工做項目了。
讓咱們看看目錄結構。
注意:請確保將圖像保存在static文件夾和html 文件放在templates文件夾中。Flask只會查找這些名字。若是你改變這些,你會獲得一個錯誤。
Flask應用程序首先將home.html當有人發送圖像分類請求時,Flask將檢測一個post方法並調用get_image_class函數。
此函數將按如下步驟工做:
# 導入庫 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)
到目前爲止,咱們已經分別對每幅圖像進行了預測。如今,咱們將用新參數修改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/