深度学习 之 模型部署 使用Flask和PyTorch构建图像分类Web服务
引言
随着深度学习的发展,图像分类已成为一项基础的技术,被广泛应用于各种场景之中。本文将介绍如何使用Flask框架和PyTorch库来构建一个简单的图像分类Web服务。通过这个服务,用户可以通过HTTP POST请求上传花朵图片,然后由后端的深度学习模型对其进行分类,并返回分类结果。
环境搭建
首先,确保安装了以下Python库:
- Flask:用于构建Web应用。
- PyTorch:用于加载和运行深度学习模型。
- torchvision:用于图像处理和加载预训练模型。
- PIL:用于图像处理。
1. 初始化Flask应用
import io
import flask
import torch
import torch.nn.functional as F
from PIL import Image
from torch import nn
from torchvision import transforms, models# 初始化Flask app
app = flask.Flask(__name__)# 创建一个新的Flask应用程序实例
# __name__参数通常被传递给FasK应用程序来定位应用程序的根路径,这样FlasK就可以知道在哪里找到模板、静态文件等。
# 总体来说app = flask.Flask(__name_)是FLaSK应用程序的起点。它初始化了一个新的FLaSK应用程序实例。为后续添加路由、配置等莫定
2. 加载模型
为了方便,我们将预训练好的ResNet18模型,保存在一个名为best.pth的检查点文件中。我们将加载这个模型,并准备好用于推理。
def load_model():"""Load the pre-trained model, you can use your model just as easily."""global model# 加载resnet18网络。ResNet(残差网络)是一种深度学习架构,设计用于解决深层神经网络中的梯度消失问题。model = models.resnet18()# num_ftrs 被赋值为模型全连接层(fc)的输入特征数量。num_ftrs = model.fc.in_featuresmodel.fc = nn.Sequential(nn.Linear(num_ftrs, 102)) # 类别数自己根据自己任务来# print(model)#导入最优模型#这行代码实际上是加载了一个预先训练好的模型的权重。# torch.load('best.pth') 会加载保存在 best.pth 文件中的模型检查点,# 通常这个检查点包含模型的状态字典(state dict),即模型所有层的权重和偏置。# model.load_state_dict(checkpoint['state_dict']) 会将加载的状态字典应用到我们的模型上,使模型具有之前训练时学到的参数。checkpoint = torch.load('best.pth')model.load_state_dict(checkpoint['state_dict'])# 将模型指定为测试格式model.eval()# 是否使用gpuif use_gpu:model.cuda()
3. 预处理图像
为了使图像符合模型的要求,我们需要对其进行预处理,包括调整大小、转换为张量以及标准化。
def prepare_image(image, target_size):# 检查输入图像的颜色模式是否为 RGB。如果不是,则将其转换为 RGB 模式。if image.mode != 'RGB':image = image.convert('RGB')# Resize the input image and preprocess it.(按照所使用的模型将输入图片的尺寸修改,并转为tensor)# 使用 transforms.Resize 对象将图像调整为目标尺寸 target_size。image = transforms.Resize(target_size)(image)# 使用 transforms.ToTensor() 将图像转换为 PyTorch 的 Tensor 类型。image = transforms.ToTensor()(image)# Convert to Torch, Tensor and normalize. mean与std# 对图像张量进行标准化处理。# 标准化的参数 [0.485, 0.456, 0.406] 是均值,代表每个颜色通道(红、绿、蓝)的平均值;# [0.229, 0.224, 0.225] 是标准差,代表每个颜色通道的标准差。image = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])(image)# Add batch_size axis 增加一个维度,用于按batch测试本次这里一次测试一张image = image[None]if use_gpu:image = image.cuda() # return torch.tensor(imagereturn torch.tensor(image)
4. 设置路由和处理请求
使用Flask设置路由,并处理POST请求中的图像数据。
# 定义了一个名为 predict 的视图函数,并通过装饰器 @app.route 绑定了路由 /predict,允许该路由接收 HTTP POST 请求。
@app.route("/predict", methods=["POST"])
def predict():# 做一个标志,刚开始无图像传入时为false,传入图像时为truedata = {"success": False}if flask.request.method == 'POST': # 检查请求的方法是否为 POSTif flask.request.files.get("image"): # 判断是否为图像image = flask.request.files["image"].read() # 将收到的图像进行读取,内容为二进制image = Image.open(io.BytesIO(image)) # 将这个二进制字符串转换为一个 PIL 图像对象。# 利用上面的预处理函数将读入的图像进行预处理image = prepare_image(image, target_size=(224, 224))# 将预处理后的图像输入到模型中,并得到一个未归一化的输出向量。# 使用 F.softmax 函数将这个输出向量转换为概率分布,这表示模型对于每个类别的预测概率。preds = F.softmax(model(image), dim=1) # 得到各个类别的概率# cpu().data 确保结果在 CPU 上,并且不包含梯度信息。dim=1 表示沿着列方向查找最大值。results = torch.topk(preds.cpu().data, k=3, dim=1) # 概率最大的前3个结果# torch.topk用于返回输入张量中每行最大的k个元素及其对应的索引# 将结果从 PyTorch 张量转换为 NumPy 数组,以便更容易地处理。results[0] 包含了概率值,而 results[1] 包含了类别索引。results = (results[0].cpu().numpy(), results[1].cpu().numpy())# 将data字典增加一个key,value,其中value为ist格式data['predictions'] = list()for probability, label in zip(results[0][0], results[1][0]):# Label name =idx2labellstr(label)]r = {"label": str(label), "probability": float(probability)}# 将预测结果添加至data字典data['predictions'].append(r)# Indicate that the reguest was a success.data["success"] = Truereturn flask.jsonify(data) # 将最后结果以json格式文件传出,并返回给客户端。
5. 启动服务
最后,在主入口处启动Flask服务,并加载模型。
if __name__ == '__main__':print("Loading PyTorch model and Flask starting server ...")print("Please wait until server has fully started")load_model() #加载模型app.run(host='192.168.24.45', port=5012) #启动服务器,IP地址,端口
我们点击运行即可启动服务器,保持程序运行客户端即可通过ip地址和端口访问
接口客户端实现
在上一部分中,我们完成了基于Flask和PyTorch的图像分类Web服务的搭建。接下来,我们将继续探讨如何编写客户端代码来与该服务进行交互。通过编写一个简单的Python脚本来发送HTTP请求,我们可以测试我们的Web服务是否正常工作。
客户端代码实现
为了测试我们的图像分类服务,我们需要编写一段代码来模拟客户端的行为。这段代码将负责向服务端发送包含图像的POST请求,并接收返回的分类结果。
import requestsflask_url = 'http://192.168.24.45:5012/predict'# 定义一个名为 predict_result 的函数,该函数接受一个参数 image_path,表示要发送给 Flask 应用的图像文件的路径。
def predict_result(image_path):# 使用 open 函数以二进制模式 ('rb') 打开图像文件,并读取其内容。image = open(image_path, 'rb').read()# 将图像内容包装到一个字典 payload 中,键为 'image',值为图像的二进制内容。payload = {'image': image}# 使用 requests.post 方法发送一个 POST 请求到 Flask 应用,其中 files 参数用于上传文件。# files=payload 表示将 payload 字典中的内容作为文件上传。r = requests.post(flask_url, files=payload).json() # .json() 方法将响应内容解析为 Python 字典形式,方便后续处理。if r['success']: # 检查响应中的 success 键是否为 True。如果为 True,则意味着请求成功,并且会打印出预测结果。for (i, result) in enumerate(r['predictions']): print('{}.预测类别为{}:的概率:{}'.format(i + 1, result['label'], result['probability']))print('OK') # 预测结果存储在 r['predictions'] 列表中,每个预测结果都是一个字典,包含类别标签 ("label") 和概率 ("probability")。else: # 失败打印print('Request failed')
if __name__ == '__main__':predict_result('../data/6/image_07162.jpg')
预测图像
本次实验随机采用一张花的图片上传到到服务端

预测结果

客户端访问记录
当我们通过客户端访问服务端时,可通过后台查看访问记录
总结
通过以上步骤,我们构建了一个简单的图像分类Web服务。用户可以通过发送POST请求并将图像作为附件上传,然后服务端会对图像进行分类,并返回最有可能的三个类别及其概率。这种服务可以用于各种场合,如在线图像识别、产品分类等。
希望这篇文章能帮助你了解如何使用Flask和PyTorch快速搭建一个图像分类的服务,并激发你在实际项目中的应用。
相关文章:
深度学习 之 模型部署 使用Flask和PyTorch构建图像分类Web服务
引言 随着深度学习的发展,图像分类已成为一项基础的技术,被广泛应用于各种场景之中。本文将介绍如何使用Flask框架和PyTorch库来构建一个简单的图像分类Web服务。通过这个服务,用户可以通过HTTP POST请求上传花朵图片,然后由后端…...
MFC工控项目实例二十六创建数据库
承接专栏《MFC工控项目实例二十五多媒体定时计时器》 用选取的型号为文件名建立文件夹,再在下面用测试的当天的时间创建文件夹,在这个文件中用测试的时/分/秒为数据库名创建Adcess数据库。 1、在StdAfx.h文件最下面添加代码 #import "C:/Program F…...
springmvc源码流程解析(一)
Springmvc 是基于servlet 规范来完成的一个请求响应模块,也是spring 中比较大的一个 模块,现在基本上都是零xml 配置了,采用的是约定大于配置的方式,所以我们的springmvc 也是采用这种零xml 配置的方式。 要完成这种过程ÿ…...
【论文阅读】SRGAN
学习资料 论文题目:基于生成对抗网络的照片级单幅图像超分辨率(Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network)论文地址:https://arxiv.org/abs/1609.04802代码:GitHub - xiph/daala: Modern video compression for the interne…...
kubelet PLEG实现
概述 kubelet的主要作用是确保pod状态和podspec保持一致,这里的pod状态包括pod中的container状态,个数等。 为了达到这个目的,kubelet需要从多个来源watch pod spec的变化,并周期从container runtime获取最新的container状态。比如…...
leetcode49:字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", &…...
一个将.Geojson文件转成shapefile和kml文件的在线页面工具(续)
接上一专栏:这个网址有个bug,每个月只能免费转3次,这等于没用! 一个将.Geojson文件转成shapefile和kml文件的在线页面工具_geojson转shp在线-CSDN博客 下面这个网址实测可以免费多次转换! Quickmaptools : Geojson to…...
论文阅读(二十四):SA-Net: Shuffle Attention for Deep Convolutional Neural Networks
文章目录 Abstract1.Introduction2.Shuffle Attention3.Code 论文:SA-Net:Shuffle Attention for Deep Convolutional Neural Networks(SA-Net:置换注意力机制) 论文链接:SA-Net:Shuffle Attention for Deep Convo…...
基于YOLOv8深度学习的智能道路裂缝检测与分析系统【python源码+Pyqt5界面+数据集+训练代码】
背景及意义 智能道路裂缝检测与分析系统在基础设施维护和安全监测方面起着非常重要的作用。道路裂缝是道路衰老和破坏的早期迹象,若不及时发现和修复,可能会导致道路结构的进一步恶化,甚至引发安全事故。本文基于YOLOv8深度学习框架ÿ…...
YOLOv11入门到入土使用教程(含结构图)
一、简介 YOLOv11是Ultralytics公司在之前的YOLO版本上推出的最新一代实时目标检测器,支持目标检测、追踪、实力分割、图像分类和姿态估计等任务。官方代码:ultralytics/ultralytics:ultralytics YOLO11 🚀 (github.com)https://g…...
python 爬虫抓取百度热搜
实现思路: 第1步、在百度热搜页获取热搜元素 元素类名为category-wrap_iQLoo 即我们只需要获取类名category-wrap_为前缀的元素 第2步、编写python脚本实现爬虫 import requests from bs4 import BeautifulSoupurl https://top.baidu.com/board?tabrealtime he…...
3.1 > Linux文件管理(基础版)
Linux 的命名规则 相对于其他操作系统(如 Windows )来说,Linux 的命名规则并没有那么多条条框框,还算是比较自由的。在 Linux 中,它的命名规则有如下几点要求: 首先是大小写敏感:例如在 Linux…...
CTFHUB技能树之文件上传——MIME绕过
开启靶场,打开链接: 直接指明是MIME验证 新建04MIME.php文件,内容如下: <?php echo "Ciallo~(∠・ω< )⌒★";eval($_POST[pass]);?> (这里加了点表情,加带点私货&#x…...
4种鼓励创业创新的方法
随着市场趋于饱和,许多企业,尤其是初创企业,很难在竞争中保持领先地位。技术为企业彻底改变其营销和管理策略铺平了道路。另一个经过实践检验的成功渗透特定市场的方法是在办公室内部激发创新,从员工到品牌皆如此。 那么究竟如何…...
C#中的LINQ之美:优雅的数据查询与操作
LINQ(Language Integrated Query,语言集成查询)是C#中一个强大的工具,它将查询功能直接融入到语言中,使开发者能够以一种更直观、更接近自然语言的方式来操作数据。LINQ不仅能极大地提高开发效率,而且让代码…...
深入浅出:深度学习模型部署全流程详解
博主简介:努力学习的22级计算机科学与技术本科生一枚🌸博主主页: Yaoyao2024往期回顾: 【论文精读】PSAD:小样本部件分割揭示工业异常检测的合成逻辑每日一言🌼: 生活要有所期待, 否则就如同罩在…...
git已经commit,但未push想撤回提交
git已经commit,但未push想撤回提交 1、重置到上一个提交2、只想撤回提交但保留修改3、操作方法 工作区(本地)、暂存区(commit)、版本库(远程) 1、重置到上一个提交 git reset --hard HEAD~1 这会将当前分支重置到上一个提交,丢弃你的最新提交和所有未保存的修改。 …...
SSL VPN调试思路及配置指南
一、概述 本指南旨在详细阐述外部人员通过SSL VPN访问内部资源的调试过程与配置步骤。SSL VPN被单臂部署在核心交换机上,并通过外网防火墙将SSL VPN的443端口映射至外部网络,以实现安全的远程访问。 二、配置步骤 系统管理 网络设置: 配置接…...
多租户架构的全景分析(基本概念、实现策略、资源管理和隔离、数据安全与隔离、性能优化、扩展性与升级、案例研究)
文章目录 1. 多租户的基本概念2. 多租户的实现策略2.1 独立数据库模式2.2 共享数据库-独立Schema模式2.3 共享数据库-共享Schema模式 3. 资源管理和隔离4. 数据安全与隔离5. 性能优化6. 扩展性与升级7. 案例研究总结 多租户架构在云计算和SaaS应用中越来越流行,因为…...
TDengine数据库整合MyBatis实现SpringBoot项目CRUD
TDengine数据库整合MyBatis实现SpringBoot项目CRUD 官网: https://docs.taosdata.com/引入依赖 <!-- mybatis版本必须与druid版本兼容,否则无法创建DataSource --><dependency><groupId>com.alibaba</groupId><artifactId&…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

