{"id":60,"date":"2024-12-30T17:18:43+00:00","date_gmt":"2024-12-30T17:18:43+00:00","guid":{"rendered":"https:\/\/ragecognito.digital\/?p=60"},"modified":"2024-12-29T16:14:09+00:00","modified_gmt":"2024-12-29T16:14:09+00:00","slug":"building-the-interactive-web-app","status":"publish","type":"post","link":"https:\/\/ragecognito.digital\/?p=60","title":{"rendered":"Building the Interactive Web App"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>Welcome back (<a href=\"https:\/\/ragecognito.digital\/?p=49\" target=\"_blank\" rel=\"noopener\" title=\"\">previous post<\/a>) to my machine learning journey! In the last post, I explained the setup environment and demonstrated the first steps of building an interactive machine learning model. Today, I&#8217;ll attempt to (with my limited knowledge) explain creating the web application using <a href=\"https:\/\/flask.palletsprojects.com\/en\/3.0.x\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Flask<\/a>. It serves as an example of the many ways you could interact with a model in real-time.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Introduction to Flask<\/h3>\n\n\n\n<p>Flask is a lightweight web framework for Python that&#8217;s perfect for building simple web applications quickly and efficiently. It provides the tools needed to set up routes, handle requests, and render templates.<\/p>\n\n\n\n<p>To get started with Flask, you&#8217;ll need to install it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>bashCopy code<code>pip install Flask<\/code><\/code><\/pre>\n\n\n\n<p>Once installed, you can create a basic Flask app by defining routes that handle different actions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Creating Routes for Querying and Labeling Instances<\/h3>\n\n\n\n<p>The core functionality of our web app revolves around querying instances from the pool and allowing users to label them. Let&#8217;s set up the necessary routes and create HTML templates for user interaction.<\/p>\n\n\n\n<p>Here&#8217;s the basic structure of our Flask app:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopy code<code>import numpy as np\nimport joblib\nfrom flask import Flask, request, render_template, redirect, url_for\nfrom modAL.models import ActiveLearner\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import train_test_split\n\n# Load the ActiveLearner model\nlearner = joblib.load('active_learner_model.pkl')\n\n# Load the pool data\nX_pool, y_pool = joblib.load('X_y_pool.pkl')\n\n# Split the pool data into train and test sets\nX_pool, X_test, y_pool, y_test = train_test_split(X_pool, y_pool, test_size=0.2, random_state=42)\n\n# Initialize Flask app\napp = Flask(__name__)\n\n# Global variable to store labeled instances\nlabeled_instances = []\n\n@app.route('\/')\ndef home():\n    return render_template('index.html')\n\n@app.route('\/query', methods=['GET', 'POST'])\ndef query():\n    global X_pool, y_pool, query_instance, query_idx, labeled_instances\n\n    if request.method == 'POST':\n        # Get the label from the user\n        label = int(request.form['label'])\n\n        # Teach the model the new label\n        learner.teach(X_pool[query_idx].reshape(1, -1), np.array([label]))\n\n        # Store the labeled instance and its label\n        labeled_instances.append((X_pool[query_idx].reshape(1, -1), label))\n\n        # Remove the queried instance from the pool\n        X_pool = np.delete(X_pool, query_idx, axis=0)\n        y_pool = np.delete(y_pool, query_idx, axis=0)\n\n        # Evaluate the model\n        accuracy = learner.score(X_test, y_test)\n\n        # Query the model for the next instance\n        query_idx, query_instance = learner.query(X_pool)\n\n        return render_template('query.html', instance=query_instance.tolist(), accuracy=accuracy)\n\n    # Initial query\n    query_idx, query_instance = learner.query(X_pool)\n    accuracy = learner.score(X_test, y_test)\n\n    return render_template('query.html', instance=query_instance.tolist(), accuracy=accuracy)\n\n@app.route('\/review')\ndef review():\n    accuracy = learner.score(X_test, y_test)\n    return render_template('review.html', labeled_instances=labeled_instances, accuracy=accuracy, enumerate=enumerate)\n\n@app.route('\/correct', methods=['POST'])\ndef correct():\n    global labeled_instances, learner, X_pool, y_pool\n\n    try:\n        # Get the index and new label from the form\n        index = int(request.form['index'])\n        new_label = int(request.form['new_label'])\n\n        # Ensure the index is within the valid range\n        if 0 &lt;= index &lt; len(labeled_instances):\n            # Update the label in the labeled instances\n            instance, _ = labeled_instances[index]\n            labeled_instances[index] = (instance, new_label)\n\n            # Recreate the dataset with corrected labels\n            X_corrected = np.vstack([instance for instance, label in labeled_instances])\n            y_corrected = np.array([label for instance, label in labeled_instances])\n\n            # Clear and reinitialize the learner with corrected data\n            learner = ActiveLearner(\n                estimator=RandomForestClassifier(),\n                X_training=X_corrected,\n                y_training=y_corrected\n            )\n\n            accuracy = learner.score(X_test, y_test)\n\n            return render_template('review.html', labeled_instances=labeled_instances, accuracy=accuracy, enumerate=enumerate)\n        else:\n            return f\"Error: Index {index} is out of range. Valid range is 0 to {len(labeled_instances) - 1}.\", 400\n    except Exception as e:\n        return str(e), 500\n\nif __name__ == '__main__':\n    app.run(debug=True)\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handling and Correcting Labels<\/h3>\n\n\n\n<p>One of the critical features of our app is the ability to correct labels. This ensures that any mistakes made during the labeling process can be rectified, improving the model&#8217;s learning over time.<\/p>\n\n\n\n<p>In the <code>review<\/code> route, users can see all labeled instances and correct any mistakes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pythonCopy code<code>@app.route('\/review')\ndef review():\n    accuracy = learner.score(X_test, y_test)\n    return render_template('review.html', labeled_instances=labeled_instances, accuracy=accuracy, enumerate=enumerate)\n\n@app.route('\/correct', methods=['POST'])\ndef correct():\n    global labeled_instances, learner, X_pool, y_pool\n\n    try:\n        # Get the index and new label from the form\n        index = int(request.form['index'])\n        new_label = int(request.form['new_label'])\n\n        # Ensure the index is within the valid range\n        if 0 &lt;= index &lt; len(labeled_instances):\n            # Update the label in the labeled instances\n            instance, _ = labeled_instances[index]\n            labeled_instances[index] = (instance, new_label)\n\n            # Recreate the dataset with corrected labels\n            X_corrected = np.vstack([instance for instance, label in labeled_instances])\n            y_corrected = np.array([label for instance, label in labeled_instances])\n\n            # Clear and reinitialize the learner with corrected data\n            learner = ActiveLearner(\n                estimator=RandomForestClassifier(),\n                X_training=X_corrected,\n                y_training=y_corrected\n            )\n\n            accuracy = learner.score(X_test, y_test)\n\n            return render_template('review.html', labeled_instances=labeled_instances, accuracy=accuracy, enumerate=enumerate)\n        else:\n            return f\"Error: Index {index} is out of range. Valid range is 0 to {len(labeled_instances) - 1}.\", 400\n    except Exception as e:\n        return str(e), 500\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Challenges and Reflections<\/h3>\n\n\n\n<p>Creating the web application presented several challenges, from handling data correctly to ensuring that the user interface was intuitive and responsive. Here are some of the key challenges I faced and how I overcame them:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Handling 3D Arrays<\/strong>: Initially, the model expected 2D arrays but received 3D arrays. This was resolved by ensuring data reshaping maintained the correct dimensions.pythonCopy code<code>learner.teach(X_pool[query_idx].reshape(1, -1), np.array([label]))<\/code><\/li>\n\n\n\n<li><strong>Model Accuracy Calculation<\/strong>: To ensure consistent accuracy measurement, I used a fixed test set derived from the initial pool data. This helped in evaluating the model&#8217;s performance on unseen data, providing a more reliable metric.pythonCopy code<code>X_pool, X_test, y_pool, y_test = train_test_split(X_pool, y_pool, test_size=0.2, random_state=42)<\/code><\/li>\n\n\n\n<li><strong>Correcting Labels<\/strong>: The ability to review and correct labels was crucial. By storing labeled instances and allowing corrections, the model could be retrained with updated labels, improving its learning over time.pythonCopy code<code>X_corrected = np.vstack([instance for instance, label in labeled_instances]) y_corrected = np.array([label for instance, label in labeled_instances])<\/code><\/li>\n<\/ol>\n\n\n\n<p>Reflecting on this part of the journey, I realized the importance of building a user-friendly interface and the need for careful data handling. These elements are essential for creating a robust interactive machine learning model.<\/p>\n\n\n\n<p>In the next post, we&#8217;ll explore how visualizing data can help us understand our model better. Stay tuned!<\/p>\n<div class=\"syndication-links\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Welcome back (previous post) to my machine learning journey! In the last post, I explained the setup environment and demonstrated the first steps of building an interactive machine learning model. Today, I&#8217;ll attempt to (with my limited knowledge) explain creating the web application using Flask. It serves as an example of the many ways you&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"mf2_syndication":[],"venue_id":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-60","post","type-post","status-publish","format-standard","hentry","category-uncategorized","kind-"],"kind":false,"_links":{"self":[{"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/posts\/60","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=60"}],"version-history":[{"count":4,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions"}],"predecessor-version":[{"id":73,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions\/73"}],"wp:attachment":[{"href":"https:\/\/ragecognito.digital\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=60"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=60"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ragecognito.digital\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=60"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}