flask部署深度学习pytorch模型

        昨天完用flask成功部署了pytorch模型,成功完成了一个自己的项目,这是我个人生涯的一大步。按照惯例,写下这个备忘贴,主要是为了方便自己回忆的,大家能学到什么各凭本事。

  •         GET方法用于从服务器获取资源,即客户端向服务器请求数据。POST方法用于向服务器提交数据,即客户端向服务器发送数据。
    1.  服务器:一般是指 http://127.0.0.1:8987
    2. 客户端:一般是指网页
  • form表单里点击提交按钮,会触发flask的post请求。


一、Flask部署机器学习模型

        深度学习五花八门,直接用flask部署深度学习pytorch模型,不利于入门,因此我推荐先部署一个极其简单的机器学习模型试试手第一节会教你:我应该这么做,思路是什么。

 web截图: 

 

参考链接:

使用Flask部署机器学习模型

参考代码:

GitHub - YuGong123/Flask_house_price_predict

目录结构:

web界面,page.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div align="center">
    <h2>使用Flask部署机器学习模型Demo——房价预测</h2>
    <br>
    <form action="{{ url_for('predict')}}" method="post">
        <b>房子英尺数</b><input type="text" name="housesize" required />
        <br>
        <button type="submit">预测房价</button>
    </form>
    <br>
    {{ prediction_display_area }}
</div>

</body>
</html>

服务器程序——载入模型,命名app.py 

import numpy as np
from flask import Flask, request, jsonify, render_template
import pickle

app = Flask(__name__)
model = pickle.load(open('model.pkl','rb'))

@app.route('/')
def home():
    return render_template('page.html')

@app.route('/predict', methods=['POST'])
def predict():
    features_list = [float(x) for x in request.form.values()]
    features = np.array(features_list).reshape(1,-1)
    predict_outcome_list = model.predict(features)
    predict_outcome = round(predict_outcome_list[0],2)

    return render_template('page.html',prediction_display_area='预测价格为:{}'.format(predict_outcome))

if __name__ == "__main__":
    app.run(port=80,debug = True)


 二、Flask上传本地图片并在页面上显示

        使用Flask远程上传图片到服务器,并把获取到的图片显示到前端页面上。这个也是我项目代码的模板,简单实用,十分重要。

目录结构:

 

  • 'static/images' 文件夹用来存放上传过来的图片
  • ‘templates’文件夹下的两个html文件定义显示页面
  • upload_pictures.py 是工程代码

 upload_pictures.py 代码:

1)该接口采用 POST 方法,需要登录;
2)接着,检查请求中是否有 'file' 关键词,然后取出文件,判断文件是否为空或是否合法;

# coding:utf-8
 
from flask import Flask, render_template, request, redirect, url_for, make_response,jsonify
from werkzeug.utils import secure_filename
import os
import cv2
import time
 
from datetime import timedelta
 
#设置允许的文件格式
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'JPG', 'PNG', 'bmp'])
 
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
 
app = Flask(__name__)
# 设置静态文件缓存过期时间
app.send_file_max_age_default = timedelta(seconds=1)
 
 
# @app.route('/upload', methods=['POST', 'GET'])
@app.route('/upload', methods=['POST', 'GET'])  # 添加路由
def upload():
    if request.method == 'POST':
        f = request.files['file']
 
        if not (f and allowed_file(f.filename)):
            return jsonify({"error": 1001, "msg": "请检查上传的图片类型,仅限于png、PNG、jpg、JPG、bmp"})
 
        user_input = request.form.get("name")
 
        basepath = os.path.dirname(__file__)  # 当前文件所在路径
 
        upload_path = os.path.join(basepath, 'static/images', secure_filename(f.filename))  # 注意:没有的文件夹一定要先创建,不然会提示没有该路径
        # upload_path = os.path.join(basepath, 'static/images','test.jpg')  #注意:没有的文件夹一定要先创建,不然会提示没有该路径
        f.save(upload_path)
 
        # 使用Opencv转换一下图片格式和名称
        img = cv2.imread(upload_path)
        cv2.imwrite(os.path.join(basepath, 'static/images', 'test.jpg'), img)
 
        return render_template('upload_ok.html',userinput=user_input,val1=time.time())
 
    return render_template('upload.html')
 
 
if __name__ == '__main__':
    # app.debug = True
    app.run(host='0.0.0.0', port=8987, debug=True)

 upload_ok.html 文件代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask上传图片演示</title>
</head>
<body>
    <h1>使用Flask上传本地图片并显示示例一</h1>
    <form action="" enctype='multipart/form-data' method='POST'>
        <input type="file" name="file" style="margin-top:20px;"/>
        <br>
        <i>请输入你当前的心情(开心、超开心、超超开心):</i>
        <input type="text" class="txt_input" name="name"  value="超超开心" style="margin-top:10px;"/>
        <input type="submit" value="上传" class="button-new" style="margin-top:15px;"/>
    </form>
    <h1>阁下的心情是:{{userinput}}!</h1>
    <img src="{{ url_for('static', filename= './images/test.jpg',_t=val1) }}" width="400" height="400" alt="你的图片被外星人劫持了~~"/>
</body>
</html>

        值得注意的一点是:这篇代码没有直接对用户上传的图片进行处理,而是先将他们放到'static/images' 文件夹下保存,这样十分方便我们用path路径等方法进行后续处理。而且,路径是写死的,这样更方便。

 web网页截图:

 参考文章:

Flask上传本地图片并在页面上显示

参考代码:

https://github.com/YuGong123/Flask_upload_pictures

十分重要的2个参考链接:

[python][flask] Flask 图片上传与下载例子(支持漂亮的拖拽上传)

flask文件上传&下载&预览服务案例


 三、python flask将读取的图片返回给web前端

        这篇用了一种巧妙的方法,实现了将python后台制作的图片,放到html等前端显示。原理:Python在后台把图片处理为Base64位的格式,再把Base64格式的图片在html用img控件显示。
 

Python代码:

from flask import Flask, jsonify, request, render_template
from flask_cors import CORS

app = Flask(__name__)  # 实例化,可视为固定格式
app.debug = True  # Flask内置了调试模式,可以自动重载代码并显示调试信息
app.config['JSON_AS_ASCII'] = False  # 解决flask接口中文数据编码问题

#设置可跨域范围
CORS(app, supports_credentials=True)

# 展示Flask如何读取服务器本地图片, 并返回图片流给前端显示的例子
def return_img_stream(img_local_path):
    """
    工具函数:
    获取本地图片流
    :param img_local_path:文件单张图片的本地绝对路径
    :return: 图片流
    """
    import base64
    img_stream = ''
    with open(img_local_path, 'rb') as img_f:
        img_stream = img_f.read()
        img_stream = base64.b64encode(img_stream).decode()
    return img_stream

// 跳转到html页面显示图片   app.route()为跳转路由,类似springboot
@app.route('/index')
def hello_world():
  img_path = 'static/img/demo.png'
  img_stream = return_img_stream(img_path)
  # render_template()函数是flask函数,它从模版文件夹templates中呈现给定的模板上下文。
  return render_template('index.html',img_stream=img_stream)
  
  // 主函数
if __name__ == '__main__':
    # app.run(host, port, debug, options)
    # 默认值:host="127.0.0.1", port=5000, debug=False
    app.run(host="127.0.0.1", port=5010)

        这里十分重要,因为采用static静态文件夹保存图片,我们可以轻易的捕捉到图片路径,再通过传参的方式

return render_template('index.html', img_stream=img_stream)

将后台图片送到前端展示。

html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <img src="data:;base64,{{ img_stream }}">
</body>
</html>

 web网页图:

 

参考代码:

GitHub - YuGong123/Flask_show_images_on_web


四、让用户下载处理后的图片

        图片下载比较简单,就是调用 send_from_directory 函数,就能够把 static 目录下的对应文件发出:(我们一般把各种用于外面访问的静态图片、JS、CSS 等放在 static 文件中)

写法一:用get方法,到指定目录,下载指定文件。

#get方法:指定目录下载文件
@server.route('/download', methods=['get'])#/download路由地址,methods请求方法
def download():
    fpath = request.values.get('path', '') #获取文件路径
    fname = request.values.get('filename', '')  #获取文件名
    if fname.strip() and fpath.strip():
        print(fname, fpath)
        if os.path.isfile(os.path.join(fpath,fname)) and os.path.isdir(fpath):
            return send_from_directory(fpath, fname, as_attachment=True) #返回要下载的文件内容给客户端
        else:
            return '{"msg":"参数不正确"}'
    else:
        return '{"msg":"请输入参数"}'

写法二:下载指定文件,使用默认路径,跳过了路径拼接。

@bp.route('/download/<name>')
def download_file(name):
    return send_from_directory(app.config["UPLOAD_FOLDER"], name) #返回要下载的文件内容给客户端

写法三:

        这是我的写法,直接将路径在后台写死,用户无从选择,只能下载"static/images/test.jpg"。当用户点击“下载预测图”时,无需传参,点击下载就行。

<a href="http://localhost:5000/download">下载预测图</a>
# 注意,下载路径 "download_path" 是写死的
@app.route('/download/', methods=['GET'])
def download():
    return send_from_directory('static/images', 'test.jpg', as_attachment=True)


*五、 图片实时展示,用户能看到自己上传的图片

        可能有人会问,前面不是已经说过了如何展示图片了吗?为什么还要讲?

        我可以告诉你,前面的方法,都是先将用户提供的图片备份到后台。之后,用户不点击提交按钮是看不到的,即不触发"post"请求是看不到图片的。

        这里是告诉你如何用jqury库,来实现图片展示,即,在不点击提交按钮的情况下,如何实时展示图片。

核心代码:

<!DOCTYPE html>
<html>
<head>
    <title>HTML5上传图片并预览</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
</head>
<body>
<!--<h3>请选择图片文件:PNG/JPG/JPEG/SVG/GIF</h3>-->
<div style="text-align: left;margin-left:500px;margin-top:100px;" >
    <div style="float:left;">
        <a href="javascript:;" class="file">选择文件
            <input type="file" name="file" id="file0"><br>
        </a>
        <img src="" id="img0" style="margin-top:20px;width: 35rem;height: 30rem;">
    </div>
    <div style="float:left;margin-left:50px;">
        <input type="button" id="b0" onclick="test()" value="预测">
        <pre  id="out" style="width:320px;height:50px;line-height: 50px;margin-top:20px;"></pre>
    </div>
</div>

<script type="text/javascript">
    $("#file0").change(function(){
        var objUrl = getObjectURL(this.files[0]) ;//获取文件信息
        console.log("objUrl = "+objUrl);
        if (objUrl) {
            $("#img0").attr("src", objUrl);
        }
    });

    function getObjectURL(file) {
        var url = null;
        if(window.createObjectURL!=undefined) {
            url = window.createObjectURL(file) ;
        }else if (window.URL!=undefined) { // mozilla(firefox)
            url = window.URL.createObjectURL(file) ;
        }else if (window.webkitURL!=undefined) { // webkit or chrome
            url = window.webkitURL.createObjectURL(file) ;
        }
        return url ;
    }
</script>
</body>
</html>


核心思想:靠jquery提供的id选择器 "#file0" 找到input文本框,通过js找到图片框"#img0",给它添加src属性,并赋值。

参考代码:

https://github.com/YuGong123/pytorch_flask_service


*六flask无法访问(127.0.0.1:5000)的问题解决

        完成了项目,想向小伙伴炫耀一下,但是只能本地访问,怎么让小伙伴用局域网访问?

 有人说我们可以在程序中设置:

app.run(host='0.0.0.0',port=5000)

但这并无卵用, 解决方案:


然后设置参数:

 

 这样就搞定了。


*七、Pycharm设置Flask模板引擎:Jinja2

        右键点击templates文件夹,之后如图所示:

 


 *八、用pycharm上传代码github上,保存自己的心血

参考链接:

Pycharm如何上传、更新本地代码到github

使用Pycharm将自己的代码上传到github


*九、采取非破解的方法破解pycharm专业版

打开pycharm-->文件-->设置-->插件,点击如图内容

点击加号,输入网址 https://plugins.zhile.io

回到插件主页,搜索eval reset

 在pycharm主页面处,点击帮助,帮助栏下面会多出一个eval reset的选项。

 点击后pycharm低端会出现选择栏目,这里不用在意内容,只需把Auto reset before per restart 打√,这样可以在每一次开启时自动重置试用时间,点击reset

参考链接:

pycharm插件 Eval Reset 安装方法

pycharm 安装 eval reset

pycharm专业版 没有试用30天按钮,需要登录的解决方案

        这里个人推荐去官网下载pycharm-professional-2020.3.3.exe,可以避免无法使用选择 “30天试用” 的情况。

官网地址:

http://www.jetbrains.com/pycharm/download/#section=windows


*十、Pycharm的Terminal进入创建好的虚拟环境

有时候Pycharm的terminal中显示的是硬盘中的项目路径,但没有进入我们创建好的虚拟环境

这时候,我们需要在Pycharm>File>Tools>Terminal中切换powershell.exe为cmd.exe


*十一、 PyCharm中的项目无法识别相对路径的问题

        本人在用pycharm内部的Git上传代码到Github上后,出现了已经一件令人十分悲伤的故事,PyCharm中的项目无法识别相对路径了。

 问题出在PyCharm的Edit Configurations中: ​​​​​​

 解决方法:

参考链接:

PyCharm中的项目无法识别相对路径的问题

  • 7
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值