本文我将带领大家构建一个Web应用程序以对榴莲进行分类,在这里(https://durian-classifier.herokuapp.com/) 可以查看相关信息。

如果你不知道榴莲是什么,那我向你说明一下。

它是一种质地乳脂状、气味刺鼻(见下图)和外表刺眼的水果(在新加坡我们称之为水果之王),这意味着刺鼻的气味让人要么讨厌它,要么绝对喜欢它(很明显,我属于后者)。如果你觉得它闻起来很香,那么它的味道可能会更好。

问题陈述

是的,这个项目的动力源于我对榴莲的热爱。你一定想知道,我们到底在分类什么?

你会发现,榴莲有很多种,它们的味道、质地和颜色各不相同。对于此项目,我们将对四种不同类型的榴莲进行分类,即:

  • 猫山王

  • 金凤凰

  • D24

  • 红虾

下表总结了这些榴莲的不同之处:

榴莲的品种还有很多,但我认为这些榴莲的细微差别可能会让我们的模型难以学习。

数据收集

每个项目都从数据收集开始。由于我们将部署的模型用于个人和教育目的,因此我们将从google获取图像,如果你将图片用于其他用途,请检查版权。

我们将使用此API(https://github.com/ultralytics/google-images-download) 来获取图像。

只需按照repo上的说明安装软件包。在说明的第3步中,我们将针对特定的用例运行此命令(将路径替换为chromedriver):

python3 bing_scraper.py --url 'https://www.bing.com/images/search?q=mao+shan+wang' --limit 100 --download --chromedriver <path_to_chromedriver>

在这里,我们将下载的图片数量限制在100张,因为没有多少具体的“猫山王”图片。我们重复以上步骤三次,用其他品种的榴莲进行搜索。请注意,由于我们在API中修改了搜索URL,查询中的空格将替换为“+”(即mao+shan+wang,red+prawn+durian等)。

当然,你可以对任何要分类的图像执行此步骤。

数据清理

在我们的用例中,由于没有公开的榴莲图像,因此下载的许多图像可能与正确的榴莲品种不符(例如,在搜索“ mao shan wang”时可能会找到通用的“未标记”榴莲) )。

因此,我需要手动检查所有下载的图像,以确保图片的质量,毕竟拥有高质量(即正确标记)的数据胜过大数量的数据,对吧?

此步骤确实需要一些领域知识,并且可能会花费一些时间。(但是,数据清理是机器学习管道中的基本步骤,反映了数据科学家和AI工程师的实际情况。)

清除数据后,剩下55张 D24、39张金凤,59张猫山王和68张红虾图像。

训练榴莲分类器

我选择使用TensorFlow框架,我相信大多数实践者都已经熟练使用了(当然,可以随意使用Pytorch)。由于我们只有很少的图像,我们无疑必须使用一个预先训练好的模型,并在我们的数据集上对其进行微调。

首先,确保你有下面的文件夹结构,这是之后使用 flow_from_directory 所必需的。

train|-- d24|-- golden-phoenix|-- mao-shan-wang|-- red-prawnvalid|-- d24|-- golden-phoenix|-- mao-shan-wang|-- red-prawn

让我们开始构建分类器!

# Import relevant libraries we will be usingimport numpy as np
from tensorflow.keras.initializers import glorot_uniformfrom tensorflow.keras.regularizers import l2from tensorflow.keras.preprocessing.image import ImageDataGeneratorfrom tensorflow.keras.applications import Xceptionfrom tensorflow.keras.layers import (    Flatten,    Dense,    AveragePooling2D,    Dropout)from tensorflow.keras.optimizers import SGDfrom tensorflow.keras.preprocessing import imagefrom tensorflow.keras import Modelfrom tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.callbacks import (    EarlyStopping,    ModelCheckpoint,    LearningRateScheduler)

如上所示,我们将使用的基本模型是Xception,让我们实例化它并添加一些全连接层。因为我们有很多图像,所以我们将使用较小的批处理大小8。我们还需要警惕我们的小型数据集过度拟合。

SHAPE = 224BATCH_SIZE = 8
model = Xception(    input_shape=(SHAPE, SHAPE, 3),    include_top=False,    weights='imagenet')
x = model.outputx = AveragePooling2D(pool_size=(2, 2))(x)x = Dense(32, activation='relu')(x)x = Dropout(0.1)(x)x = Flatten()(x)x = Dense(4, activation='softmax',          kernel_regularizer=l2(.0005))(x)
model = Model(inputs=model.inputs, outputs=x)
opt = SGD(lr=0.0001, momentum=.9)model.compile(loss='categorical_crossentropy',              optimizer=opt,              metrics=['accuracy'])

在此之后,让我们使用TensorFlow的ImageDataGenerator及其flow_from_directory创建图像生成器对象。由于我们没有足够的训练图像,图像增强比以往任何时候都更重要。

train_datagen = ImageDataGenerator(    rescale=1./255,    rotation_range=15,    width_shift_range=0.1,    height_shift_range=0.1,    horizontal_flip=True)
valid_datagen = ImageDataGenerator(    rescale=1./255,    rotation_range=0,    width_shift_range=0.0,    height_shift_range=0.0,    horizontal_flip=False)
train_generator = train_datagen.flow_from_directory(    'train/',    target_size=(SHAPE, SHAPE),    shuffle=True,    batch_size=BATCH_SIZE,    class_mode='categorical',)
valid_generator = valid_datagen.flow_from_directory(    'valid/',    target_size=(SHAPE, SHAPE),    shuffle=True,    batch_size=BATCH_SIZE,    class_mode='categorical',)
>>> Found 178 images belonging to 4 classes.>>> Found 42 images belonging to 4 classes.

让我们在.fit()即我们的模型之前定义一些回调函数。

earlystop = EarlyStopping(monitor='val_loss',                          patience=4,                          verbose=1)
checkpoint = ModelCheckpoint(    "model-weights/xception_checkpoint.h5",    monitor="val_loss",    mode="min",    save_best_only=True,    verbose=1)

我们的模型终于开始训练了!

history = model.fit_generator(    train_generator,    epochs=30,    callbacks=[earlystop, checkpoint],    validation_data=valid_generator)
# Save our model for inferencemodel.save("model-weights/xception.h5")

不幸的是,由于我们拥有的图像数量有限,我们的模型在验证集上无法获得非常好的准确性,但是,模型微调并不是本文的重点,因此我们不会对此进行过多介绍。

选择我们的Web框架

在这个项目中,我选择使用streamlit(https://www.streamlit.io/) ,因为它可以实现机器学习应用程序的超快速可视化,并且科可以方便地用Python编写。建立好这些之后,剩下要做的就是部署它。

首先,导入所需的库并指定模型权重的路径,同样由于我们使用了flow_from_directory ,TensorFlow按字母顺序分配类编号,因此,D24将为0类,依此类推。

import numpy as np
from PIL import Imagefrom tensorflow.keras.models import load_modelfrom tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.preprocessing import imageimport streamlit as st
PATH = "model-weights/"WEIGHTS = "xception.h5"CLASS_DICT = {    0: 'D24',    1: 'JIN FENG',    2: 'MAO SHAN WANG',    3: 'RED PRAWN'}

接下来,我们创建一个函数,将上传的图像转换为模型要使用的格式。我们使用PIL中的Image类,因为上传的图像是BytesIO格式的。

def load_img(input_image, shape):    img = Image.open(input_image).convert('RGB')    img = img.resize((shape, shape))    img = image.img_to_array(img)    return np.reshape(img, [1, shape, shape, 3])/255

Streamlit的工作方式是,用户指定参数的每一次更改,脚本都会从上到下重新运行(因此它是交互式的UI),因此它以st.cache形式提供了一个缓存装饰器来缓存加载的对象。

缓存通常用于数据加载步骤或任何需要长时间计算/处理的步骤。请记住,我们使用allow_output_variation=True参数,因为默认情况下这是False,如果输出对象以任何方式发生了变化,则应用程序将被重新加载。

在我们的例子中,模型对象将在每次预测中发生变化,因此我们将    allow_output_variation的参数设置为True。我们之所以要缓存我们的模型是因为我们不希望每次用户选择不同的图像时都加载它(即只加载一次模型)。

@st.cache(allow_output_mutation=True)def load_own_model(weights):    return load_model(weights)

最后,我们只需要向UI添加一些代码即可:

if __name__ == "__main__":    result = st.empty()    uploaded_img = st.file_uploader(label='upload your image:')    if uploaded_img:        st.image(uploaded_img, caption="your sexy durian pic",                 width=350)        result.info("please wait for your results")        model = load_own_model(PATH + WEIGHTS)        pred_img = load_img(uploaded_img, 224)        pred = CLASS_DICT[np.argmax(model.predict(pred_img))]        result.success("The breed of durian is " + pred)

我们用Python创建的web应用程序不需要太多的代码行。你可以确保它(假设它会被调用应用程序副本)可以通过在命令行中输入以下命令在本地运行:

streamlit run app.py

将我们的模型部署到Heroku

就我个人而言,部署不是我最喜欢的部分,但是,如果web应用程序不在web上,那它还有什么意义呢?我们开始吧。

你可以通过多种方式为web应用程序提供服务,也可以使用许多云服务提供商来托管它。在这种情况下,我选择使用Heroku主要是因为我以前没有尝试过。

什么是Heroku?

Heroku是一个云平台即服务(PaaS),支持多种编程语言,允许开发人员完全在云中构建、运行和操作应用程序。下面这篇文章解释得很清楚。

  • 文章链接:https://devcenter.heroku.com/articles/how-heroku-works

在Heroku部署

为了部署应用程序,我们总是需要某种版本控制,以确保我们的应用程序运行在一个不同的服务器上,而不是在本地计算机上。为此,许多人使用Docker容器,指定所需的可运行应用程序和包。

使用Heroku进行部署类似于同时使用Docker容器和web托管服务,但是,它使用Git作为部署应用程序的主要手段。我们不需要将所有必需的文件打包到Docker容器中,而是创建一个用于版本控制的git存储库,然后我们可以使用熟悉的git push,但是要用到heroku远程。

Heroku随后使用了相同的容器技术,以dyno的形式进行。每个应用程序都放在一个dyno(或容器)中,每个应用程序都消耗“dyno hours”。

每个Heroku帐户都有一些可用的空闲小时数,消耗的小时数取决于应用程序的活动/流量。如果你的应用程序不需要大量流量,那么免费套餐应已足够了。

另外值得注意的是,当Heroku接收到应用程序源时,它会启动应用程序的构建(例如在requirements.txt创建必要的资产等),被组装成一个slug。

术语解释:slug是源代码、获取的依赖项、语言运行时和编译生成的系统输出的捆绑包—为执行做准备。

要在Heroku上部署,我们需要以下文件:

(1)setup.sh

  • 创建必要的目录并将一些信息(例如端口号)写入.toml文件

mkdir -p ~/.streamlit/
echo "\[server]\n\headless = true\n\port = $PORT\n\enableCORS = false\n\\n\" > ~/.streamlit/config.toml

(2) Procfile

  • 类似于Dockerfile,包含我们要执行的指令。我们将首先在setup.sh中执行一些bash命令,然后执行streamlit run app.py命令。

web: sh setup.sh && streamlit run app.py

(3) requirements.txt

  • 包含应用程序所需的所有包依赖项。请注意,这些是我正在使用的版本。你可以通过终端中的conda list或使用pip freeze > requirements.txt获取环境当前使用的软件包的详尽列表。

numpy==1.18.1spacy==2.2.4pandas==1.0.1Pillow==7.1.2streamlit==0.61.0tensorflow-cpu==2.2.0

我们的文件夹目录应如下所示:

app.pyProcfileREADME.mdrequirements.txtsetup.shmodel-weights|-- xception.h5

如果你以前从未创建过Github存储库,请按照以下一些简单步骤进行操作:

  1. 创建一个新的存储库<repo_name>

  1. 复制红色框中的URL

  1. 在终端上,运行以下命令:

# Clone the repository into our local machinegit clone <repo URL in step 2>
# Enter the directory we just clonedcd <repo_name>
  1. 将之前创建的文件复制到此文件夹中,然后在终端中运行以下命令:

# Add all the files we just copied over to be committedgit add .
# Commit the files, along with a commit messagegit commit -m "deploy app"
# Push to master branch on our github repogit push origin master

我们就快到了!这是最后的步骤。

(1)创建一个Heroku帐户并进行验证

(2)在此处(https://devcenter.heroku.com/articles/heroku-cli) 安装Heroku CLI

(3)通过终端登录到你的Heroku帐户。将打开一个浏览器窗口,供你进行身份验证。

heroku login

(4)创建一个Heroku应用

heroku create <project-name>

完成此步骤后,你将能够在终端中看到指向你的项目的链接。

(5)将git repo推送到Heroku遥控器。在我们的github存储库的同一目录中,运行以下命令:

git push heroku master

我们完成了!构建完成后,你应该能够在上面的链接中看到部署的应用程序!

参考链接:https://towardsdatascience.com/how-to-build-and-deploy-a-machine-learning-web-application-in-a-day-f194fdbd4a5f

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 mthler」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

如何在一天内构建和部署机器学习web应用程序 — 榴莲分类相关推荐

  1. 在Tomcat中部署Java Web应用程序几种方式

    在Tomcat中部署Java Web应用程序有两种方式:静态部署和动态部署.在下文中$CATALINA_HOME指的是Tomcat根目录.  一.静态部署       静态部署指的是我们在服务器启动之 ...

  2. 为什么将表格的method改为post后就无法工作_用Python将Keras深度学习模型部署为Web应用程序...

    构建一个很棒的机器学习项目是一回事,但归根结底,你希望其他人能够看到你的辛勤工作.当然,你可以将整个项目放在GitHub上,但是怎么让你的祖父母也看到呢?我们想要的是将深度学习模型部署为世界上任何人都 ...

  3. 构建meteor应用程序_我构建了一个渐进式Web应用程序并将其发布在3个应用程序商店中。 这是我学到的。...

    构建meteor应用程序 by JudahGabriel Himango 犹大(Gabriel Himango) 我构建了一个渐进式Web应用程序并将其发布在3个应用程序商店中. 这是我学到的. (I ...

  4. 【转】Tomcat中部署java web应用程序

    http://www.blogjava.net/jiafang83/archive/2009/06/02/279644.html 转载: 今天给大家介绍怎样在Tomcat5.5.9中部署Java We ...

  5. 使用Eclipse在Amazon Ec2中部署Java Web应用程序的完整指南

    嗨,读者们, 今天,我将向您展示如何使用Eclipse IDE在Amazon EC2中部署简单的Java Web应用程序. 在我们开始之前,我们需要一些必需的东西, Eclipse Java EE I ...

  6. 使用Synology群晖内置web station和榴莲壳发布自己的网站(三)如何访问自己服务器里的网页

    使用Synology群晖内置web station和榴莲壳发布自己的网站(三)如何访问自己服务器里的网页 配置 榴莲壳的申请 榴莲壳设置 Web Station完成最后一步设置 internet顺利访 ...

  7. 使用Synology群晖内置web station和榴莲壳发布自己的网站(二)设置Web Station

    使用Synology群晖内置web station和榴莲壳发布自己的网站(二)设置Web Station 配置 设置群晖Web Station 打开Web Station设置 安装Apache HTT ...

  8. 使用Synology群晖内置web station和榴莲壳发布自己的网站(一)安装Web Station

    使用Synology群晖内置web station和榴莲壳发布自己的网站(一)安装Web Station 配置 自己用html写一个简单网站用于test 群晖安装web station 自从入手了群晖 ...

  9. Nest的基本概念,以及如何使用Nest CLI来构建一个简单的Web应用程序

    Nest是一个用于构建高效.可扩展的Node.js服务器端应用程序的框架.它是基于Express.js构建的,并且提供了多种新特性和抽象层,可以让开发者更加轻松地构建复杂的应用程序. 本文将介绍Nes ...

最新文章

  1. VS2008 VS2010发布网站时如何产生固定命名的 Dll 文件
  2. oracle10g資料庫調效,資料庫 | 簡睿隨筆 | 學習過程的紀錄與備忘
  3. [LGP4859,...] 一类奇怪的容斥套DP
  4. 制作U盘启动盘将Ubuntu 12.04升级为14.04的方法
  5. rabbitmq的安装和使用
  6. java连接mysql实现增删改查_JDBC之Java连接mysql实现增删改查
  7. The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local Machine 完美解决
  8. ARM平台AMBA总线uart驱动和console初始化
  9. html5--select与HTML5新增的datalist元素
  10. 华佳慧科技:OSN500设备ERPS相切环组网介绍
  11. Unity3D 制作绿草地,草坪,模型表面生成草地,草地效果Shader实现 草着色器 Brute Force - Grass Shader
  12. 魔兽和星际最大差别是什么?
  13. Android手机卡顿原因
  14. 毕业论文完成,感谢帮助过我的人
  15. 记录Guava版本冲突而出现项目启动失败的问题
  16. 自定义注解校验List集合数据
  17. ROS专题----tf和tf2坐标变换
  18. 抖音怎么上热门 怎样修改视频的md5
  19. HTML网页开发手册
  20. 小程序直播带货系统优势—直播带货的技巧

热门文章

  1. 儿童书写台灯哪个牌子比较好?盘点护眼学生用台灯品牌排行
  2. ArcGIS中各版本ArcMap安装OpenStreetMap编辑工具集插件ArcGIS Editor for OSM
  3. XV6实验(2020)
  4. SAP ABAP 处理 Excel 的标准函数 TEXT_CONVERT_XLS_TO_SAP 介绍试读版
  5. Modernizr的简单使用
  6. 10年前旧文:编程的美感
  7. 泛微OA字段联动设置
  8. 分享一款用HTML5+CSS+JavaScript写的射击游戏
  9. android camera2 闪光灯,Camera2 闪光灯梳理
  10. Navicat Premium 历史版本下载地址