tensorflow网页版手写数字识别-使用flask进行网络部署
tensorflow如何将训练好的模型部署在网页中呢,在python中可以很方便的使用django或者flask框架来进行搭建。这里我使用轻量级的flask框架进行搭建。
首先模型已经放在了checkpoint目录下,想要知道模型怎么保存的,可以查看我往期的博客
使用flask需要两个文件夹:
一个是static,存放静态文件,例如图片,音乐之类的
还有一个是templates,前端网页的模板就放在这个文件夹中
主要思路:在前端页面提供一个上传按钮,可以将图片下载到本地。flask后台代码将图片进行处理,识别出数字之后,输出到前端页面中。
接下来是python的flask后台代码:
from flask import Flask, render_template, request, flash, redirect, url_for, make_response from flask_bootstrap import Bootstrap import os from werkzeug.utils import secure_filename from PIL import Image #导入图片模块 import numpy as np #导入科学计算库 import tensorflow as tf #导入机器学习框架 model_save_path = './checkpoint/mnist.ckpt' #训练好的模型路径 model = tf.keras.models.Sequential([ #实现前向传播 tf.keras.layers.Flatten(), tf.keras.layers.Dense(128, activation = "relu"), tf.keras.layers.Dense(10, activation = "softmax") ]) model.load_weights(model_save_path) #加载参数 def yuce(uploadpath): image_path = uploadpath img = Image.open(image_path) img = img.resize((28, 28), Image.ANTIALIAS) # 把输入图片resieze成28*28尺寸的图片,转换为灰度图 img_arr = np.array(img.convert('L')) # img_arr = 255 - img_arr #颜色取反 for i in range(28): # 让图片变为只有黑色和白色的高对比图 for j in range(28): if img_arr[i][j] < 200: img_arr[i][j] = 255 # 像素点小于200的全部变为255,纯白色 else: img_arr[i][j] = 0 # 像素点大于200的全部变为0,纯黑色 img_arr = img_arr / 255.0 # 归一化处理 x_predict = img_arr[tf.newaxis, ...] # 添加一个维度,变为三个维度 result = model.predict(x_predict) # 预测结果 pred = tf.argmax(result, axis=1) #获取结果 # print("\n") # tf.print(pred) return pred #返回预测值 app = Flask(__name__) #新建flask实例 bootstrap = Bootstrap(app) #引用了bootstrap app.config['SECRET_KEY'] = os.urandom(24) basedir = os.path.abspath(os.path.dirname(__file__)) uploadDir = os.path.join(basedir, 'static/uploads') #存储文件地址 def address(filename): #获得地址和文件名,也就是获得文件地址 uploadpath = os.path.join(uploadDir, filename) return uploadpath @app.route('/', methods=['POST', 'GET']) def process(): if request.method == 'POST': f = request.files.get('selectfile') #得到表单 if not os.path.exists(uploadDir): os.makedirs(uploadDir) #新建文件夹 if f: filename = secure_filename(f.filename) #安全设置 types = ['jpg', 'png', 'tif'] #指定格式 if filename.split('.')[-1] in types: # uploadpath = os.path.join(uploadDir, filename) uploadpath = address(filename) #存储文件的地址 f.save(uploadpath) #保存文件 #前向传播 pred = yuce(uploadpath) #调用函数,进行前向传播预测 flash('Upload Load Successful!', 'success') #前端进行输出,说明上传成功 return render_template('base.html', imagename=filename, predvalue = pred) #渲染模板 else: flash('Unknown Types!', 'danger') else: flash('No File Selected.', 'danger') return render_template('base.html') if __name__ == '__main__': app.run(debug=True)
前端模板代码:
这里使用了bootstrap的框架进行了优化,大家可以随意搭建自己的前端模板
{% extends "bootstrap/base.html" %} {% block title %}Flask-Upload{% endblock %} {% block content %} <div class="container"> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category in ["success","danger"] %} <div class="alert alert-{{ category }}"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> {{ message }} </div> {% endif %} {% endfor %} {% endif %} {% endwith %} <form method="post" enctype="multipart/form-data"> <input id="lefile" type="file" style="display:none" name="selectfile"> <div class="input-append form-inline"> <input id="photoCover" class="input-large form-control" type="text" style="height:34px;width:60vw;border:2px #337ab7 solid" placeholder="请选择影像"> <a class="btn btn-primary" onclick="$('input[id=lefile]').click();">浏览</a> <button type="submit" class="btn btn-primary">上传</button> </div> </form> {% if imagename %} <img src="{{ url_for('static',filename='uploads/'+imagename) }}" width="300px" height="300px"/> {% endif %} <div> {% if predvalue %} 预测的数字为:{{predvalue}} {% endif %} </div> </div> {% endblock %} {% block scripts %} {{ super() }} <script type="text/javascript"> $('input[id=lefile]').change(function () { $('#photoCover').val($(this).val()); }); $("#photoCover").attr('autocomplete', 'off') </script> {% endblock %}
结果为: