{"id":61,"date":"2022-09-02T15:15:09","date_gmt":"2022-09-02T14:15:09","guid":{"rendered":"https:\/\/sonic.fabio.org.uk\/?p=61"},"modified":"2022-09-02T15:27:23","modified_gmt":"2022-09-02T14:27:23","slug":"ml-app-with-flask","status":"publish","type":"post","link":"https:\/\/sonic.fabio.org.uk\/?p=61","title":{"rendered":"ML App with Flask"},"content":{"rendered":"\n<p>You built an ML with TensorFlow or Sci-kit learn and now want it deployed on a website. This article is a quick guide on loading an ML model in Python and using it to make predictions on a web app with Flask. This is based on my image classifier app found on my GitHub <a href=\"https:\/\/github.com\/Fabio-RibeiroB\/image_classifier_app\">Fabio-RibeiroB\/image_classifier_app: App to classify happy or sad images (github.com)<\/a>. In this app, the user uploads a file and presses predict. Specifically, the user uploads images for binary classification. It all depends on your model. You can change this code to upload CSV data instead, for example.<\/p>\n\n\n\n<p>I appreciate this article is high-level and lacking detail. It is more than an outline to make it as short-form as possible. To see more, check out my aforementioned repo on GitHub. Anyway, let&#8217;s begin.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Save and Load<\/h2>\n\n\n\n<p>Let&#8217;s say you have a Sequential model that you compiled.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">model = Sequential()\n....some model\n....\nmodel.compile(....)<\/code><\/pre>\n\n\n\n<p>Now save the model, for example, as a .h5 file. I saved mine in a &#8220;models&#8221; folder. You can also use <code class=\"\" data-line=\"\">pickle<\/code> to dump and load models as .pkl files.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">from tensorflow.keras.models import load_model\nimport os\nmodel.save(os.path.join(&#039;models&#039;,&#039;model.h5&#039;))<\/code><\/pre>\n\n\n\n<p>Now load it in your Flask app.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">from flask import Flask, render_template, request, redirect, flash, session # useful flask modules\nfrom werkzeug.utils import secure_filename # security\nimport logging\n\nlogging.basicConfig(level=logging.DEBUG)\nlogging.info(&#039;program starting&#039;)\n\nfrom tensorflow.keras.models import load_model\nmodel = load_model(&#039;models\/model.h5&#039;) # loaded model\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Static Uploads Folder<\/h2>\n\n\n\n<p>We also need a folder where we can upload data for the model. Make a directory called static, and within that, a directory called uploads.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">UPLOAD_FOLDER = &#039;.\/static\/uploads&#039;\nALLOWED_EXTENSIONS = {&#039;png&#039;, &#039;jgp&#039;, &#039;jpeg&#039;} # change depending on model\napp = Flask(__name__)\napp.secret_key = b&#039;somesecretkey&#039;\napp.config&#091;&#039;UPLOAD_FOLDER&#039;] = UPLOAD_FOLDER\n\ndef allowed_file(filename):\n    &quot;&quot;&quot;\n    Check the uploaded data is correct format\n    &quot;&quot;&quot;&quot;\n    return &#039;.&#039; in filename and \\\n          filename.rsplit(&#039;.&#039;, 1)&#091;1].lower() in ALLOWED_EXTENSIONS\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Routes and Prediction<\/h2>\n\n\n\n<p>Now I create the necessary routes in your app that makes a prediction. We will later make a home.html will allow us to start a prediction. The predict.html page shows the results.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">@app.route(&#039;\/&#039;)\ndef home():\n    return render_template(&#039;home.html&#039;)\n\n@app.route(&#039;\/predict&#039;, methods=&#091;&#039;POST&#039;])\ndef predict():\n    file = request.files(&#039;file&#039;)\n    # check uploaded file is okay in upload folder\n    if file and allowed_file(file.filename):\n        filename = secure_filename(file.filename)\n        data_path = os.path.join(app.config&#091;&#039;UPLOAD_FOLDER&#039;], filename)\n   \n        file. save(data_path) # save data\n        # read data in for example with pandas\n        prediction = model.predict(data) # in my example prediction is one number, a probability.\n\n        # remember to delete file after use\n\n        os.remove(data_path)\n        return render_template(&#039;predict.html&#039;, data=prediction)\n   \nif __name__ == &quot;__main__&quot;:\n    app.run(debug=True)<\/code><\/pre>\n\n\n\n<p>The above code saves the valid data in the uploads folder and loads the data. For example, you could load your data into a pandas data frame. The \/predict route passes the prediction variable containing a single prediction. The prediction variable is passed to predict.html to render the result on the web page. If your model outputs a lot of predictions, like a CSV of predictions, these lines will need to be modified. You probably want the user to download the predictions as a CSV instead of displaying the results on the screen. In this case, you need a download button in your HTML. <\/p>\n\n\n\n<p>However, continuing my example, we have a home page called home.html with a form for the user to upload data. I simply removed the rest of my HTML tags to declutter the code snippet below. See my repo for the entire HTML file.<\/p>\n\n\n\n<p>In home.html<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">&lt;form method=&quot;POST&quot; action=&quot;{{url_for(&#039;home&#039;)}}&quot;   enctype=multipart\/form-data&gt;\n    &lt;input type=file name=file&gt;\n    &lt;input type=submit value=predict&gt;\n&lt;\/form&gt;<\/code><\/pre>\n\n\n\n<p>And now for prediction.html. This page will simply output the results with a back button.<\/p>\n\n\n\n<pre class=\"wp-block-code has-light-green-cyan-background-color has-background\"><code class=\"\" data-line=\"\">{{data}}\n&lt;form&gt;\n&lt;input type=&quot;button&quot; value=&quot;Try again&quot; on    click=&quot;history.back()&quot;&gt;\n&lt;\/form&gt;<\/code><\/pre>\n\n\n\n<p>Flask run, and the app should be running in local host.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>You built an ML with TensorFlow or Sci-kit learn and now want it deployed on a website. This article is a quick guide on loading an ML model in Python and using it to make predictions on a web app with Flask. This is based on my image classifier app found on my GitHub Fabio-RibeiroB\/image_classifier_app: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/61"}],"collection":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=61"}],"version-history":[{"count":5,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions"}],"predecessor-version":[{"id":71,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=\/wp\/v2\/posts\/61\/revisions\/71"}],"wp:attachment":[{"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=61"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=61"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sonic.fabio.org.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}