python常用的Web框架介绍与实战演练

一、python的Web框架介绍

本次实战主要用了Flask、Tornado、FastAPI和Gradio这4个框架,故先介绍
以下是Flask、Tornado、FastAPI和Gradio的详细介绍,以及它们各自的优势和缺点:

1.Flask

Flask是一个轻量级的Python Web框架,使用Werkzeug WSGI工具和Jinja2模板引擎。它以其简洁和灵活性著称,非常适合小型应用和原型开发。

优势:

  • 轻量和灵活:没有过多的默认设置,开发者可以自由选择使用的组件。
  • 简单易学:文档全面,社区支持广泛,适合初学者。
  • 扩展性强:通过Flask扩展可以轻松添加各种功能(如数据库、表单处理、身份验证等)。

缺点:

  • 功能有限:对于大型应用或复杂需求,可能需要大量的手动配置和集成。
  • 性能:不如一些异步框架(如Tornado或FastAPI)高效。

2.Tornado

Tornado是一个Python Web框架和异步网络库,以其非阻塞、异步I/O操作著称,适用于需要处理大量并发连接的应用。

优势:

  • 高并发处理能力:异步I/O使其在处理大量并发请求时表现优异。
  • WebSocket支持:原生支持WebSocket,适合实时应用。
  • 性能高:比大多数同步框架在I/O密集型应用中表现更好。

缺点:

  • 复杂性:异步编程模型相对复杂,不易于调试和测试。
  • 社区和生态系统:相比Flask和Django,社区和可用扩展较少。

3.FastAPI

FastAPI是一个现代、快速的Web框架,基于Starlette和Pydantic,设计用于构建API。它使用Python 3.6+的类型提示,实现了高性能和高可维护性。

优势:

  • 高性能:接近Node.js和Go的速度,适合高性能API开发。
  • 自动生成文档:内置自动生成OpenAPI和JSON Schema文档。
  • 类型安全:利用类型提示进行数据验证和序列化,减少错误。
  • 异步支持:全面支持异步编程,性能优越。

缺点:

  • 新框架:相对较新,生态系统和社区还在发展中。
  • 学习曲线:利用类型提示和异步功能需要一定学习成本。

4.Gradio

Gradio是一个用于创建机器学习模型和数据科学应用的Python库。它使开发者能够快速构建和部署交互式Web界面。

优势:

  • 快速创建界面:无需前端开发经验即可创建交互式Web应用。
  • 易用性:界面构建非常直观,支持多种输入输出组件。
  • 实时部署:可以快速将模型部署到Web界面进行实时交互。
  • 支持多种框架:与TensorFlow、PyTorch等主流机器学习框架兼容。

缺点:

  • 功能有限:主要针对机器学习和数据科学应用,通用Web应用支持不如Flask或FastAPI。
  • 性能:对于高并发或复杂应用场景,性能可能不如专门的Web框架。

小结

  • Flask:轻量灵活,适合小型应用和快速开发,但功能有限。
  • Tornado:高并发和异步处理能力强,适合实时和高负载应用,但编程模型复杂。
  • FastAPI:高性能、类型安全,适合构建现代API,但相对较新,学习曲线较高。
  • Gradio:专注于机器学习和数据科学应用,快速创建交互界面,但通用Web应用支持有限。

选择合适的框架需要根据具体的项目需求、性能要求和开发团队的技能水平来决定。

除了Flask、Tornado、FastAPI和Gradio,Python还有许多其他Web框架。以下是一些主要的Python Web框架及其简介:

5.Django

Django是一个功能强大的高级Web框架,旨在快速开发安全和可维护的应用。它提供了许多开箱即用的功能,包括ORM、认证系统、管理界面等。

优势:

  • 全功能:内置许多常用功能,减少开发时间。
  • 安全性:有多种内置的安全机制来防止常见的Web攻击。
  • 社区和生态系统:庞大的社区和丰富的第三方应用和插件。
  • 管理界面:自动生成的管理后台界面,方便数据管理。

缺点:

  • 重量级:可能对于小型或简单项目来说显得过于复杂和笨重。
  • 学习曲线:全面的功能和配置选项需要一定的学习时间。

6.Pyramid

Pyramid是一个灵活的Web框架,适合从小型应用到大型应用的开发。它允许开发者选择所需的组件和工具。

优势:

  • 灵活性:可以自由选择模板引擎、数据库等组件。
  • 模块化:适合构建复杂和大型应用,支持多种认证和授权方式。
  • 文档齐全:详细的文档和教程,支持多种扩展。

缺点:

  • 复杂性:由于其灵活性,可能需要更多的初始配置和学习。
  • 社区较小:相比Django和Flask,社区和生态系统较小。

7.Bottle

Bottle是一个极简的Web框架,只有一个文件,非常适合小型应用和快速原型开发。

优势:

  • 轻量级:代码库非常小,易于学习和使用。
  • 快速:非常适合小型应用和原型开发。
  • 零依赖:仅依赖Python标准库。

缺点:

  • 功能有限:缺少许多高级功能,适合简单的应用。
  • 不适合大型项目:对于复杂或大型应用,可能需要额外的工具和扩展。

8.CherryPy

CherryPy是一个成熟的Web框架,支持多线程,适合构建高性能的Web应用。

优势:

  • 简单易用:设计简洁,容易上手。
  • 多线程支持:内置多线程服务器,适合高并发应用。
  • 成熟稳定:经过多年的发展,非常稳定。

缺点:

  • 社区较小:相比Django和Flask,社区和第三方资源较少。
  • 功能相对基础:内置功能相对基础,可能需要手动添加扩展。

9.Sanic

Sanic是一个异步Web框架,专注于性能和速度,适合高性能的Web应用。

优势:

  • 高性能:异步框架,支持高并发和快速响应。
  • 简单易用:语法和Flask相似,易于上手。
  • 异步支持:全面支持异步编程,适合实时和高负载应用。

缺点:

  • 新框架:相对较新,生态系统和社区还在发展中。
  • 复杂性:异步编程模型可能增加开发复杂性。

10.Web2py

Web2py是一个全功能的Web框架,带有强大的Web接口和内置的集成开发环境(IDE)。

优势:

  • 全功能:包括内置的Web IDE、数据库抽象层和强大的表单处理。
  • 易用性:设计简单,快速上手。
  • 跨平台:支持多种平台,包括Google App Engine。

缺点:

  • 重量级:可能对于简单应用来说显得过于复杂。
  • 社区较小:相比Django和Flask,社区和第三方资源较少。

这些框架各有其特点和适用场景,选择合适的框架需要根据项目的具体需求、性能要求和开发团队的技能水平来决定。

二、实战

我已训练好了一个图像分类的模型,现在想把它部署到网页上进行推理。
建立相关文件夹:
在这里插入图片描述
在这里插入图片描述

首先前三个框架flask,tornado和fastapi需要编写html语句,它们的统一编写为index5.html,

1.前端html代码

如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>局放图像识别</title>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 40px;
        }
        .container {
            max-width: 600px;
            margin: 0 auto;
            text-align: center;
        }
        .result {
            margin-top: 20px;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 8px;
            display: none;
        }
        img {
            max-width: 100%;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="mt-5">上传图片进行识别</h1>
        <form id="uploadForm" method="post" enctype="multipart/form-data" class="mt-4">
            <div class="form-group">
                <input type="file" class="form-control-file" name="file" id="fileInput" accept=".png, .jpg, .jpeg, .bmp">
            </div>
            <button type="submit" class="btn btn-primary">上传并识别</button>
        </form>
        <div class="result mt-4" id="resultContainer">
            <h2>识别结果</h2>
            <img id="uploadedImage" src="#" alt="Uploaded Image" class="img-fluid mt-3">
            <p id="category" class="mt-3"></p>
            <p id="probability"></p>
            <button class="btn btn-secondary mt-3" onclick="resetForm()">重新上传</button>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script>
        document.getElementById('uploadForm').addEventListener('submit', function(event) {
            event.preventDefault();
            let formData = new FormData(this);
            fetch('/uploadfile/', {
                method: 'POST',
                body: formData
            }).then(response => response.json()).then(data => {
                document.getElementById('resultContainer').style.display = 'block';
                document.getElementById('category').innerText = '预测类别: ' + data.result.category;
                document.getElementById('probability').innerText = '概率值: ' + data.result.probability;
                document.getElementById('uploadedImage').src = 'uploads/' + data.filename;
            }).catch(error => {
                console.error('Error:', error);
            });
        });

        function resetForm() {
            document.getElementById('resultContainer').style.display = 'none';
            document.getElementById('uploadForm').reset();
        }
    </script>
</body>
</html>

界面如下:在这里插入图片描述

2.后端python-flask框架代码

import os
from flask import Flask, request, render_template, jsonify, redirect, url_for, send_from_directory
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
from torch.autograd import Variable

# 初始化Flask应用
app = Flask(__name__)
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}

# 创建上传文件夹(如果不存在)
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

# 设置PyTorch设备(GPU或CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义并加载ResNet50模型
model = models.resnet50(pretrained=False)
num_ftrs = model.fc.in_features
num_classes = 6  # 分类数量(根据训练时的分类数设置)
model.fc = nn.Sequential(
    nn.Linear(num_ftrs, 512),
    nn.ReLU(),
    nn.Dropout(0.2),
    nn.Linear(512, num_classes),
    nn.LogSoftmax(dim=1)
)
model = model.to(device)
model.load_state_dict(torch.load('D:/resnet-torch-main/moni_resnet_model2.pth', map_location=device))
model.eval()  # 设置模型为评估模式

# 定义图像预处理操作
test_transforms = transforms.Compose([
    transforms.ToTensor(),
])

# 定义分类标签
classes = ['干扰噪声', '悬浮电位', '沿面放电', '绝缘件内部气隙放电', '自由金属颗粒放电', '金属尖端放电']

# 检查文件扩展名是否允许
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# 定义图像预测函数
def predict(filepath):
    with open(filepath, 'rb') as file:
        image = Image.open(file)
        image = image.convert('RGB')  # 确保图像为RGB格式
    image_tensor = test_transforms(image).float()  # 预处理图像
    image_tensor = image_tensor.unsqueeze_(0)  # 增加批次维度
    input = Variable(image_tensor)
    input = input.to(device)

    output = model(input)  # 模型预测
    probabilities = torch.exp(output).data.cpu().numpy()  # 计算概率值
    index = probabilities.argmax()  # 获取预测类别索引

    result = {
        "category": classes[index],
        "probability": f"{probabilities[0][index]:.4f}"
    }
    return result  # 返回预测结果

# 定义根路由(显示上传表单)
@app.route('/')
def upload_file():
    return render_template('index5.html')  # 渲染上传页面

# 定义文件上传处理
@app.route('/uploadfile/', methods=['POST'])
def upload_file_post():
    if 'file' not in request.files:
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        return redirect(request.url)
    if file and allowed_file(file.filename):
        filename = file.filename
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        file.save(filepath)
        result = predict(filepath)
        return jsonify(result=result, filename=filename)
    return redirect(request.url)

# 提供上传的图像
@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(UPLOAD_FOLDER, filename)

# 启动Flask应用
if __name__ == '__main__':
    app.run(debug=True, port=5000)

运行后如下:
在这里插入图片描述
点开网址,结果如下:
在这里插入图片描述
选择图像进行识别,结果如下:
在这里插入图片描述

3.后端python-tornado框架代码

import os
import tornado.ioloop
import tornado.web
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
from torch.autograd import Variable
import json

# 定义上传文件的存储文件夹和允许的文件扩展名
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}

# 创建上传文件夹(如果不存在)
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

# 设置PyTorch设备(GPU或CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义并加载ResNet50模型
model = models.resnet50(pretrained=False)
num_ftrs = model.fc.in_features
num_classes = 6  # 分类数量(根据训练时的分类数设置)
model.fc = nn.Sequential(
    nn.Linear(num_ftrs, 512),
    nn.ReLU(),
    nn.Dropout(0.2),
    nn.Linear(512, num_classes),
    nn.LogSoftmax(dim=1)
)
model = model.to(device)
model.load_state_dict(torch.load('D:/resnet-torch-main/moni_resnet_model2.pth', map_location=device))
model.eval()  # 设置模型为评估模式

# 定义图像预处理操作
test_transforms = transforms.Compose([
    transforms.ToTensor(),
])

# 定义分类标签
classes = ['干扰噪声', '悬浮电位', '沿面放电', '绝缘件内部气隙放电', '自由金属颗粒放电', '金属尖端放电']

# 检查文件扩展名是否允许
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# 定义图像预测函数
def predict(filepath):
    with open(filepath, 'rb') as file:
        image = Image.open(file)
        image = image.convert('RGB')  # 确保图像为RGB格式
    image_tensor = test_transforms(image).float()  # 预处理图像
    image_tensor = image_tensor.unsqueeze_(0)  # 增加批次维度
    input = Variable(image_tensor)
    input = input.to(device)

    output = model(input)  # 模型预测
    probabilities = torch.exp(output).data.cpu().numpy()  # 计算概率值
    index = probabilities.argmax()  # 获取预测类别索引

    result = {
        "category": classes[index],
        "probability": f"{probabilities[0][index]:.4f}"
    }
    return result  # 返回预测结果

# 处理文件上传的处理程序
class UploadHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index5.html")  # 渲染上传页面

    def post(self):
        if 'file' not in self.request.files:
            self.redirect("/")
            return
        file_info = self.request.files['file'][0]
        filename = file_info['filename']
        if filename == '' or not allowed_file(filename):
            self.redirect("/")
            return
        filepath = os.path.join(UPLOAD_FOLDER, filename)
        with open(filepath, 'wb') as f:
            f.write(file_info['body'])
        result = predict(filepath)
        self.write(json.dumps({"result": result, "filename": filename}))

# 提供上传的图像
class ImageHandler(tornado.web.RequestHandler):
    def get(self, filename):
        self.write(open(os.path.join(UPLOAD_FOLDER, filename), 'rb').read())

def make_app():
    return tornado.web.Application([
        (r"/", UploadHandler),
        (r"/uploadfile/", UploadHandler),  # 添加处理上传请求的路径
        (r"/uploads/(.*)", ImageHandler),
    ], debug=True, template_path=os.path.join(os.path.dirname(__file__), 'templates'))

if __name__ == "__main__":
    app = make_app()
    app.listen(5000)
    print("Server running at http://127.0.0.1:5000/")
    tornado.ioloop.IOLoop.current().start()

运行界面与结果同falsk,此处省略。

4.后端python-fastapi 框架代码

import os
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import JSONResponse, FileResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from starlette.requests import Request
from fastapi.staticfiles import StaticFiles
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
from torch.autograd import Variable

# 初始化FastAPI应用
app = FastAPI()
UPLOAD_FOLDER = 'uploads'  # 上传文件的存储文件夹
STATIC_FOLDER = 'static'  # 静态文件的存储文件夹
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp'}  # 允许的文件扩展名

# 创建上传和静态文件夹(如果不存在)
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
if not os.path.exists(STATIC_FOLDER):
    os.makedirs(STATIC_FOLDER)

# 设置PyTorch设备(GPU或CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义并加载ResNet50模型
model = models.resnet50(pretrained=False)
num_ftrs = model.fc.in_features
num_classes = 6  # 分类数量(根据训练时的分类数设置)
model.fc = nn.Sequential(
    nn.Linear(num_ftrs, 512),
    nn.ReLU(),
    nn.Dropout(0.2),
    nn.Linear(512, num_classes),
    nn.LogSoftmax(dim=1)
)
model = model.to(device)
model.load_state_dict(torch.load('D:/resnet-torch-main/moni_resnet_model2.pth', map_location=device))
model.eval()  # 设置模型为评估模式

# 定义图像预处理操作
test_transforms = transforms.Compose([
    transforms.ToTensor(),
])

# 定义分类标签
classes = ['干扰噪声', '悬浮电位', '沿面放电', '绝缘件内部气隙放电', '自由金属颗粒放电', '金属尖端放电']

# 定义图像预测函数
def predict(filepath):
    with open(filepath, 'rb') as file:
        image = Image.open(file)
        image = image.convert('RGB')  # 确保图像为RGB格式
    image_tensor = test_transforms(image).float()  # 预处理图像
    image_tensor = image_tensor.unsqueeze_(0)  # 增加批次维度
    input = Variable(image_tensor)
    input = input.to(device)

    output = model(input)  # 模型预测
    probabilities = torch.exp(output).data.cpu().numpy()  # 计算概率值
    index = probabilities.argmax()  # 获取预测类别索引

    result = {
        "category": classes[index],
        "probability": f"{probabilities[0][index]:.4f}"
    }
    return result  # 返回预测结果

# 配置Jinja2模板
templates = Jinja2Templates(directory="templates")

# 上传文件接口
@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    filename = file.filename
    if not ('.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS):
        raise HTTPException(status_code=400, detail="Invalid file extension")
    filepath = os.path.join(UPLOAD_FOLDER, filename)
    with open(filepath, 'wb') as f:
        f.write(file.file.read())
    result = predict(filepath)
    return JSONResponse(content={"result": result, "filename": filename})

# 提供上传的图像
@app.get("/uploads/{filename}")
async def get_uploaded_file(filename: str):
    filepath = os.path.join(UPLOAD_FOLDER, filename)
    if not os.path.exists(filepath):
        raise HTTPException(status_code=404, detail="File not found")
    return FileResponse(filepath)

# 渲染上传页面
@app.get("/", response_class=HTMLResponse)
async def read_index(request: Request):
    return templates.TemplateResponse("index5.html", {"request": request})

# 挂载静态文件夹
app.mount("/static", StaticFiles(directory=STATIC_FOLDER), name="static")

# 启动FastAPI应用
if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

运行界面与结果同falsk,此处省略。

5.后端python-gradio 框架代码

import gradio as gr
import torch
import torch.nn as nn
from torchvision import transforms, models
from PIL import Image
from torch.autograd import Variable
import os

# 设置PyTorch设备(GPU或CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 定义并加载ResNet50模型
model = models.resnet50(weights=None)
num_ftrs = model.fc.in_features
num_classes = 6  # 分类数量(根据训练时的分类数设置)
model.fc = nn.Sequential(
    nn.Linear(num_ftrs, 512),
    nn.ReLU(),
    nn.Dropout(0.2),
    nn.Linear(512, num_classes),
    nn.LogSoftmax(dim=1)
)
model = model.to(device)
model.load_state_dict(torch.load('D:/resnet-torch-main/moni_resnet_model2.pth', map_location=device))
model.eval()  # 设置模型为评估模式

# 定义图像预处理操作
test_transforms = transforms.Compose([
    transforms.ToTensor(),
])

# 定义分类标签
classes = ['干扰噪声', '悬浮电位', '沿面放电', '绝缘件内部气隙放电', '自由金属颗粒放电', '金属尖端放电']

# 定义图像预测函数
def predict(image):
    image = image.convert('RGB')  # 确保图像为RGB格式
    image_tensor = test_transforms(image).float()  # 预处理图像
    image_tensor = image_tensor.unsqueeze_(0)  # 增加批次维度
    input = Variable(image_tensor)
    input = input.to(device)

    output = model(input)  # 模型预测
    probabilities = torch.exp(output).data.cpu().numpy()  # 计算概率值
    index = probabilities.argmax()  # 获取预测类别索引

    result = {
        "category": classes[index],
        "probability": f"{probabilities[0][index]:.4f}"
    }
    return result["category"], result["probability"]  # 返回预测结果

# 创建Gradio界面
iface = gr.Interface(
    fn=predict,
    inputs=gr.Image(type="pil"),
    outputs=[gr.Textbox(label="Category"), gr.Textbox(label="Probability")],
    title="局放图像识别",
    description="上传图像进行识别"
)

# 启动Gradio应用
iface.launch()

运行后,复制下面链接
在这里插入图片描述
界面如下:
在这里插入图片描述
然后选择图片进行推理:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值