学习随笔:部署机器学习的Web APP

Ch9:Embedding a Machine Learning Model into a Web Application

前面的ML模型都是在本地运行计算的,此chapter介绍如何将模型应用在Web app上以获得实时学习、应用
这一章主要偏机器学习功能Web的简单开发,与算法关系不大。没有跳过反而收获不少。不得不佩服作者在构思’算法+系统‘时所作出的为读者充分考虑的思想

本章主要实现下列功能:(将情感分析学习器上线Web,使之能即时搜集新数据、学习新数据、更新学习器、做出预测。最后作者还提供了一种上传到公共Web空间的一种简便方式)

  • Saving the current state of a trained machine learning model
  • Using databases for data storage
  • Developing a web application using the popular Flask web framework
  • Deploying a machine learning application to a public web server

Serializing fitted scikit-learn estimators

这里应用的是 sentiment analysis 中的out_of_core.py中训练的线上模型为例,关于这个学习模型主要是一个one_line的学习模式,就是所有数据不在本地内存中。

即时学习的方法

fit 是全部学习所有的数据,而estimator的part_fit(X_new)方法可以在原来的学习器基础上学习新数据,更新新性能。

序列化

序列化将本地变量(如estimator)存储为二进制pkl文件,当大型的estimator需要在网络空间使用时直接dump出pkl,这一过程的速度回很快。(想想上章节中本地memory学习器学习完需要40min,而on_line训练完成也需要3min,这放在Web服务器上是不可能的,所以序列化是必要的)

import pickle
import os
dest = os.path.join('movieclassifier', 'pkl_objects')
if not os.path.exists(dest):
    os.makedirs(dest)
# 为了方便,将停用词也序列化
pickle.dump(stop,open(os.path.join(dest, 'stopwords.pkl'),'wb'),protocol=4)
pickle.dump(clf,open(os.path.join(dest, 'classifier.pkl'), 'wb'),protocol=4)

数据库

作者用的是Sqlite,emmmmmm一言难尽啊

Sqlite ,对就是Django初始化使用的轻量级数据库,不需要额外的配置接口什么的,可以像访问一个文件一样地访问他。。。 多么厉害友好!

所以,我决定换掉它,用Mysql

至于为啥,习惯吧...... 作者的初衷是好的,因为这样免去了学习新数据库的成本和连接耽误的风险,作者面向的对象是没有Web开发经验的人,所以这一点是值得肯定的。

Flask框架

Why Flask??作者是这样回答的:

Flask is also known as a microframework, which means that its core is kept lean
and simple but can be easily extended with other libraries. Although the learning
curve of the lightweight Flask API is not nearly as steep as those of other popular
Python web frameworks, such as Django, I encourage you to take a look at the
official Flask documentation at http://flask.pocoo.org/docs/0.12/ to learn more about
its functionality.

哦,你说Flask比Django简单,好吧那就用Flask吧!

控制层

本质上讲 Flask也是用的MVC理论。

Flask最主要的就是app.py文件 相当于Django的views.py ,不同的是他还负责路径和数据库(Flask数据库靠依赖三方库,所以还需要开发者自行编写SQL语句)的问题。而在Django中路径需要有专门的配置文件,数据库可以用ORM。

这么一对比Django的好处是数据库可以用映射关系避免写sql,模块功能更加清楚分明。

但Flask也一定有很多比Django好很多的地方,刚接触Flask希望在未来慢慢体验吧

app.py代码,重要地方我做了注释:

from flask import Flask, render_template, request
from wtforms import Form, TextAreaField, validators
import pickle
import pymysql
import os
import numpy as np

# import HashingVectorizer from local dir
from vectorizer import vect

app = Flask(__name__)

######## Preparing the Classifier 必要的函数准备
cur_dir = os.path.dirname(__file__)
clf = pickle.load(open(os.path.join(cur_dir,
                 'pkl_objects',
                 'classifier.pkl'), 'rb'))
# db = os.path.join(cur_dir, 'reviews.sqlite')

def classify(document):
    label = {0: 'negative', 1: 'positive'}
    # 转化词袋模型
    X = vect.transform([document])
    # 得到预测结果
    y = clf.predict(X)[0]
    # 得到预测结果的准确率
    proba = np.max(clf.predict_proba(X))
    return label[y], proba

def train(document, y):
    X = vect.transform([document])
    # 即时学习新的数据
    clf.partial_fit(X, [y])

def mysql_entry(document, y):
    # 这个模块不解释,添加新影评进入数据库
    conn = pymysql.connect(host = 'yzk.mysql.pythonanywhere-services.com',user = 'yzk',password = '',db = 'ML')
    c = conn.cursor()
    sql = 'insert into movie_text values(%s,%s)'
    c.execute(sql,(document,y))
    # c.execute("INSERT INTO review_db (review, sentiment, date)"\
    # " VALUES (?, ?, DATETIME('now'))", (document, y))
    conn.commit()
    conn.close()

######## 从这里Flask部分开始,下面会调用上面的函数
class ReviewForm(Form):
    moviereview = TextAreaField('',
                                [validators.DataRequired(),
                                validators.length(min=15)])
# Flask用装饰器控制路径和方法
# 用户输入评论模块
 @app.route('/')
def results():
    form = ReviewForm(request.form)
    if request.method == 'POST' and form.validate():
        # 得到评论 这个movieriew名称是怎么来的,下面我会在前端做下解释
        review = request.form['moviereview']
        y, proba = classify(review)
        # 在前端渲染结果
        return render_template('results.html',
                                content=review,
                                prediction=y,
                                probability=round(proba*100, 2))
    return render_template('reviewform.html', form=form)
# 反馈功能模块,用户点击是否情感判断正确,将用户给的正确标签和评论添加到数据库中,并使学习器学习
@app.route('/thanks', methods=['POST'])
def feedback():
    # 这些名称同样我在下面将前端时讲述
    feedback = request.form['feedback_button']
    review = request.form['review']
    prediction = request.form['prediction']

    inv_label = {'negative': 0, 'positive': 1}
    y = inv_label[prediction]
    if feedback == 'Incorrect':
        y = int(not(y))
    train(review, y)
    mysql_entry(review, y)
    return render_template('thanks.html')

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

前端

Flask的前端跟Django的理念差不多,渲染模板。这里讲一下上段代码中Form 在前端的表现问题:

关于输入文本框没有那么简单,还需要很多额外的功能,如限定最大最小字符数,错误返回,样式等等一系列问题,这些再去编写相关css\js麻烦,Flask和Django都会用到一些如Jinja的成熟模板:

<!-- _formhelpers.html是引入Jinja -->
{% from "_formhelpers.html" import render_field %}

<form method=post action="/results">
  <dl>
     <!-- 这里传入了样式参数 ,表单名称就是从这里来的-->
    {{ render_field(form.moviereview, cols='30', rows='10') }}
  </dl>
  <div>
      <input type=submit value='Submit review' name='submit_btn'>
  </div>
</form>

前端与后端 参数传递 也跟Django的模式差不多。

在本地运行起来吧!

输入影评

image

得到结果

image

可以看到得出了高概率的消极结果,....What??? 这里先对模型准确性不做判述;用户点击正确或者不正确可以添加新数据到数据库中,然后学习器及时学习他。

循环测试了四次,发现此分类器对于短一些的情感色彩不那么明显的评论是无能为力的

打开本地Mysql后台,测试一下是否添加新数据:

image

嗯成功添加了。

上传到公共空间吧!

其实作者写道这里是画蛇添足了,没必要继续下去了,本地运行成功的学习成本已经很大了。不过他就写了两页,我看完之后打开了新世界。。。

作者推荐了pythonAnywhere平台,跟google\amozon之类的云平台不同,他主要面对python的Web服务,在这里你可以免费\付费 地部署自己的Python - Web 应用,Flask,Django都可以。因为专门针对Python,所以对于开发者来说极大的便利就是:不需要再搭建环境!,只需要吧我们上面本地做好的文件上传就可以访问我们的机器学习应用啦!

点这里访问上线的情感分析程序
就像这样:

image

然后再Web中创建自己的应用:

image

简直不能再方便了,上图中可以看到:通用网关、日志文件、静态文件路径都给你放好了...... 真的省了一堆麻烦.

等等!,数据库咋办? 总不能局域网访问吧??(看到这里对作者为何使用Sqlite恍然大悟)

这个问题pythonAnywhere当然想到了,你可以在他们云端免费申请一个Mysql或者Postgres数据库。

image

上图可知,简直不需要你再做什么了,唯一需要做的就是,他没有给你数据库的GUI(如果这个再有的话,emmmmmm一言难尽)

你需要自己打开数据库的命令行来创建表:

image

免费的用户不能使用SSH链接,也就意味着免费试用者智能在Web端访问他们的bash,数据库和下面将要说道的服务器bash都是一样的。 这样的缺点是网页的console特别慢。。。。。

数据库搞定,访问提供的免费域名,emmmm出错了,不过错误日志很方便查看:

image

emmmm 没有pymysql,前面刚说了不用再搭环境了,这一秒打脸???

好吧,好在官网给出了解决方案,就是在网页打开服务器bash,你自己手动装一个....pip就OK...

好了 这下可以了:

image

小结

说说作者的这套技术路线吧

算法 + 系统 也是我的专业最好的结合方式,这里作者给出了一个初步的web解决方案,只使用一种语言、一种工具。总的来讲是很棒的。但是有一个大问题就是学习器的加速,整个框架文件学习器体积最大,io效率最慢。如果要更变参数又得重新学习,时间成本很大。如果未来机器学习算法程序真的要面向用户,我认为作者提出的此套技术路径是不太适合大型项目的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容