当前位置: 代码网 > it编程>前端脚本>Python > Python进阶-部署Flask项目(以TensorFlow图像识别项目WSGI方式启动为例)

Python进阶-部署Flask项目(以TensorFlow图像识别项目WSGI方式启动为例)

2024年07月28日 Python 我要评论
本文详细介绍了如何通过WSGI方式部署一个基于TensorFlow图像识别的Flask项目。首先简要介绍了Flask框架的基本概念及其特点,其次详细阐述了Flask项目的部署流程,涵盖了服务器环境配置、Flask应用的创建与测试、WSGI服务器的安装与配置等内容。本文旨在帮助读者掌握Flask项目的部署方法,解决在部署过程中可能遇到的问题,确保项目能够稳定高效地运行。

本文详细介绍了如何通过wsgi方式部署一个基于tensorflow图像识别的flask项目。首先简要介绍了flask框架的基本概念及其特点,其次详细阐述了flask项目的部署流程,涵盖了服务器环境配置、flask应用的创建与测试、wsgi服务器的安装与配置等内容。本文旨在帮助读者掌握flask项目的部署方法,解决在部署过程中可能遇到的问题,确保项目能够稳定高效地运行。

一、flask简介

flask是一个轻量级的web应用框架,由python语言编写。它是基于werkzeug wsgi工具包和jinja2模板引擎的,并且采用bsd许可证。flask的设计哲学是“微核”,也就是说其核心保持简洁,功能通过扩展实现。这使得flask非常灵活,能够满足从小型单一页面应用到大型复杂项目的不同需求。

flask的主要特点包括:

  1. 轻量级和灵活:flask仅提供核心功能,开发者可以根据需要引入各种扩展。
  2. 易于学习和使用:flask的api设计非常简洁明了,即使是初学者也能快速上手。
  3. 强大的扩展能力:flask的生态系统中有许多可用的扩展,可以轻松添加数据库、表单验证、用户认证等功能。
  4. 社区支持:flask拥有活跃的社区,大量的教程和文档可以帮助开发者解决问题。

二、flask项目部署流程

1. 准备工作

在开始部署flask项目之前,需要完成以下准备工作:

① 服务器安装anaconda

anaconda是一个用于科学计算的python发行版,支持多种数据科学包的快速安装。它还包含了conda,这是一种包管理器和环境管理器,能够轻松创建和管理不同的python环境。

首先,下载并安装anaconda。可以从anaconda官网下载适用于windows的安装包。安装过程非常简单,按照提示进行即可。

② anaconda创建python环境

安装完成后,使用conda创建一个新的python环境。这可以帮助你隔离项目的依赖,确保环境的一致性。打开终端(或命令提示符),输入以下命令创建一个名为opencv的环境,并指定python版本:

conda create -n opencv python=3.8

创建完成后,激活这个环境:

conda activate opencv

在这里插入图片描述

③ anaconda环境安装相关包

在激活的环境中,安装flask、flask-cors、tensorflow、scikit-learn和opencv等必要的包:

conda install flask flask-cors tensorflow scikit-learn opencv

这些包包含了构建和运行flask应用及其依赖的所有工具。

2. 创建flask应用

在本地编写并测试flask应用代码。以下是一个简单的flask应用示例,它使用tensorflow的mobilenetv2模型进行图像分类和相似度计算:

from flask import flask, request, jsonify
from flask_cors import cors
import numpy as np
import cv2
from tensorflow.keras.applications.mobilenet_v2 import mobilenetv2, preprocess_input, decode_predictions
from tensorflow.keras.preprocessing import image
from sklearn.metrics.pairwise import cosine_similarity

app = flask(__name__)
cors(app)

# 加载预训练的mobilenetv2模型
model = mobilenetv2(weights='imagenet', include_top=true)

def classify_image(img):
    img = cv2.resize(img, (224, 224))  # mobilenetv2的输入尺寸为224x224
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    preds = model.predict(x)
    return decode_predictions(preds, top=1)[0][0][1], model.predict(x)  # 返回类别名称和特征向量

def calculate_similarity(feature1, feature2):
    return cosine_similarity(feature1, feature2)[0][0]

@app.route('/compare', methods=['post'])
def compare_images():
    file1 = request.files['image1']
    file2 = request.files['image2']

    npimg1 = np.frombuffer(file1.read(), np.uint8)
    npimg2 = np.frombuffer(file2.read(), np.uint8)

    img1 = cv2.imdecode(npimg1, cv2.imread_color)
    img2 = cv2.imdecode(npimg2, cv2.imread_color)

    # 分类和特征提取
    class1, feature1 = classify_image(img1)
    class2, feature2 = classify_image(img2)

    if class1 != class2:
        similarity = 0.0
        risk_level = "低"
        intervention = "否"
    else:
        similarity = calculate_similarity(feature1, feature2)
        risk_level = "高" if similarity > 0.8 else "中" if similarity > 0.5 else "低"
        intervention = "是" if similarity > 0.8 else "否"

    return jsonify({
        'similarity': f'{similarity * 100:.2f}%',
        'risk_level': risk_level,
        'intervention': intervention,
        'class1': class1,
        'class2': class2
    })

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

在确保代码在本地运行正常。

3、本地运行flask服务器

在本地anaconda中启动opencv环境的终端,运行以下命令启动flask服务器:

python app.py

在这里插入图片描述
服务器启动后,将会监听在本地的5000端口。

① 页面前端代码实现

创建一个html文件(test.html),实现图片上传和结果展示功能,全部代码如下:

<!doctype html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>图片对比</title>
    <style>
        body {
            font-family: arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            margin: 0;
            padding: 20px;
        }
        .container {
            display: flex;
            justify-content: space-between;
            width: 80%;
            margin-bottom: 20px;
        }
        .image-box {
            width: 45%;
            border: 2px dashed #ccc;
            padding: 10px;
            text-align: center;
            position: relative;
        }
        .image-box img {
            max-width: 100%;
            max-height: 200px;
            display: none;
        }
        .image-box input {
            display: none;
        }
        .upload-btn {
            cursor: pointer;
            color: #007bff;
            text-decoration: underline;
        }
        .loading-bar {
            width: 80%;
            height: 20px;
            background-color: #f3f3f3;
            border: 1px solid #ccc;
            margin-top: 10px;
            display: none;
            position: relative;
        }
        .loading-bar div {
            width: 0;
            height: 100%;
            background-color: #4caf50;
            position: absolute;
            animation: loading 5s linear forwards;
        }
        @keyframes loading {
            to {
                width: 100%;
            }
        }
        .result {
            display: none;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>图片对比</h1>
    <div class="container">
        <div class="image-box" id="box1">
            <label for="upload1" class="upload-btn">上传图片</label>
            <input type="file" id="upload1" accept="image/*">
            <img id="image1" alt="左边文本抓取图片">
        </div>
        <div class="image-box" id="box2">
            <label for="upload2" class="upload-btn">上传图片</label>
            <input type="file" id="upload2" accept="image/*">
            <img id="image2" alt="右边文本数据库图片">
        </div>
    </div>
    <button id="compare-btn">人工智能对比</button>
    <div class="loading-bar" id="loading-bar">
        <div></div>
    </div>
    <div class="result" id="result">
        <p>相似百分比: <span id="similarity">0%</span></p>
        <p>相似度: <span id="risk-level"></span></p>
        <p>相同个体推测: <span id="intervention"></span></p>
        <p>1种类: <span id="class1">-</span></p>
        <p>2种类: <span id="class2">-</span></p>
    </div>

    <script>
        document.getelementbyid('upload1').addeventlistener('change', function(event) {
            loadimage(event.target.files[0], 'image1', 'box1');
        });

        document.getelementbyid('upload2').addeventlistener('change', function(event) {
            loadimage(event.target.files[0], 'image2', 'box2');
        });

        function loadimage(file, imgid, boxid) {
            const reader = new filereader();
            reader.onload = function(e) {
                const img = document.getelementbyid(imgid);
                img.src = e.target.result;
                img.style.display = 'block';
                document.queryselector(`#${boxid} .upload-btn`).style.display = 'none';
            }
            reader.readasdataurl(file);
        }

        document.getelementbyid('compare-btn').addeventlistener('click', function() {
            const loadingbar = document.getelementbyid('loading-bar');
            const result = document.getelementbyid('result');
            const image1 = document.getelementbyid('upload1').files[0];
            const image2 = document.getelementbyid('upload2').files[0];

            if (!image1 || !image2) {
                alert('请上传两张图片进行对比');
                return;
            }

            const formdata = new formdata();
            formdata.append('image1', image1);
            formdata.append('image2', image2);

            loadingbar.style.display = 'block';
            result.style.display = 'none';

            fetch('http://localhost:5000/compare', {
                method: 'post',
                body: formdata
            })
            .then(response => response.json())
            .then(data => {
                loadingbar.style.display = 'none';
                result.style.display = 'block';
                document.getelementbyid('similarity').innertext = data.similarity;
                document.getelementbyid('risk-level').innertext = data.risk_level;
                document.getelementbyid('intervention').innertext = data.intervention;
                document.getelementbyid('class1').innertext = data.class1;
                document.getelementbyid('class2').innertext = data.class2;
            })
            .catch(error => {
                loadingbar.style.display = 'none';
                alert('对比过程中发生错误,请重试');
                console.error('error:', error);
            });
        });
    </script>
</body>
</html>

② 运行网页

双击运行,刚刚创建的test.html文件,效果如图:
在这里插入图片描述
上传左右图片,比较两只相同品种的狗的相似度:
在这里插入图片描述

可以看到系统识别出了两只狗的种类相同,相似比也高达75.2%,但因为没有达到我们设置的80%的阈值,所以判断非同一个体。当然,这里的80%非常牵强,实际操作中难免误差较大。由于本文算法使用的是mobilenetv2预训练模型,并没有根据实际应用场景大量训练和调参,所以如果投入应用,仍需重新训练并根据实际效果定义阈值。

确认本地运行正常,接下来就可以进行部署了。

4. 安装waitress服务器

waitress是一个python wsgi服务器,适用于在生产环境中部署flask应用。它简单易用,适合部署中小型应用。使用pip安装waitress:

pip install waitress

在这里插入图片描述

5. 修改代码以使用waitress

将flask应用代码保存为 compare.py,并确保在本地测试通过。然后创建一个批处理文件 start.cmd,内容如下:

@echo off
python -m waitress --listen=*:8000 compare:app
pause

确保 compare.py 文件中的flask应用对象名为 app,例如:

from flask import flask, request, jsonify
from flask_cors import cors
import numpy as np
import cv2
from tensorflow.keras.applications.mobilenet_v2 import mobilenetv2, preprocess_input, decode_predictions
from tensorflow.keras.preprocessing import image
from sklearn.metrics.pairwise import cosine_similarity

app = flask(__name__)
cors(app)

# 加载预训练的mobilenetv2模型
model = mobilenetv2(weights='imagenet', include_top=true)

def classify_image(img):
    img = cv2.resize(img, (224, 224))  # mobilenetv2的输入尺寸为224x224
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    preds = model.predict(x)
    return decode_predictions(preds, top=1)[0][0][1], model.predict(x)  # 返回类别名称和特征向量

def calculate_similarity(feature1, feature2):
    return cosine_similarity(feature1, feature2)[0][0]

@app.route('/compare', methods=['post'])
def compare_images():
    file1 = request.files['image1']
    file2 = request.files['image2']

    npimg1 = np.frombuffer(file1.read(), np.uint8)
    npimg2 = np.frombuffer(file2.read(), np.uint8)

    img1 = cv2.imdecode(npimg1, cv2.imread_color)
    img2 = cv2.imdecode(npimg2, cv2.imread_color)

    # 分类和特征提取
    class1, feature1 = classify_image(img1)
    class2, feature2 = classify_image(img2)

    if class1 != class2:
        similarity = 0.0
        risk_level = "低"
        intervention = "否"
    else:
        similarity = calculate_similarity(feature1, feature2)
        risk_level = "高" if similarity > 0.8 else "中" if similarity > 0.5 else "低"
        intervention = "是" if similarity > 0.8 else "否"

    return jsonify({
        'similarity': f'{similarity * 100:.2f}%',
        'risk_level': risk_level,
        'intervention': intervention,
        'class1': class1,
        'class2': class2
    })

6. 运行启动

配置wsgi启动:

python -m waitress --listen=*:5000 compare:app

在这里插入图片描述

你可以通过访问 http://localhost:5000 来测试你的应用。

然后给5000端口配置安全组/防火墙,实现通过公网访问。


三、flask项目部署总结

本文详细介绍了如何通过wsgi方式部署一个基于tensorflow图像识别的flask项目。从安装和配置anaconda环境,到编写和测试flask应用,再到安装和配置wsgi服务器,我们覆盖了部署过程中的每一个步骤。这些步骤帮助确保你的flask应用能够稳定高效地运行,并且在生产环境中易于维护和扩展。

通过遵循这些步骤,你可以确保你的flask应用在各种环境中都能够正常运行,避免了在部署过程中可能遇到的许多常见问题。同时,这种方式也为你提供了一种标准化的部署流程,使得以后部署新的flask项目变得更加简单和高效。希望本文对你的flask开发和部署之旅有所帮助。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com