{"id":22039488,"url":"https://github.com/mpolinowski/ml-flask-web-app","last_synced_at":"2026-04-17T15:31:45.947Z","repository":{"id":234831430,"uuid":"620263846","full_name":"mpolinowski/ml-flask-web-app","owner":"mpolinowski","description":"Using Flask to deploy your ML Model as a Web Application","archived":false,"fork":false,"pushed_at":"2023-03-28T10:50:28.000Z","size":269,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-23T13:14:41.613Z","etag":null,"topics":["flask-application","iris-classification","prediction-api","tensorflow2"],"latest_commit_sha":null,"homepage":"https://mpolinowski.github.io/docs/IoT-and-Machine-Learning/AIOps/2023-03-27-deploying-prediction-apis-with-flask/2023-03-27","language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpolinowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-28T10:50:24.000Z","updated_at":"2025-03-04T09:17:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"de59b5a2-b72e-4dc1-b4c5-732b47aff1e5","html_url":"https://github.com/mpolinowski/ml-flask-web-app","commit_stats":null,"previous_names":["mpolinowski/ml-flask-web-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mpolinowski/ml-flask-web-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fml-flask-web-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fml-flask-web-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fml-flask-web-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fml-flask-web-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpolinowski","download_url":"https://codeload.github.com/mpolinowski/ml-flask-web-app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fml-flask-web-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31934328,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T12:37:54.787Z","status":"ssl_error","status_checked_at":"2026-04-17T12:37:25.095Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask-application","iris-classification","prediction-api","tensorflow2"],"created_at":"2024-11-30T11:10:59.592Z","updated_at":"2026-04-17T15:31:45.910Z","avatar_url":"https://github.com/mpolinowski.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\njupyter:\n  jupytext:\n    formats: ipynb,md\n    text_representation:\n      extension: .md\n      format_name: markdown\n      format_version: '1.3'\n      jupytext_version: 1.14.4\n  kernelspec:\n    display_name: Python 3 (ipykernel)\n    language: python\n    name: python3\n---\n\n# Building an ML Model for Deployment\n\n```python\nimport joblib\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelBinarizer, MinMaxScaler\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.models import Sequential, load_model\n```\n\n```python\nSEED = 42\nEPOCHS = 888\nMODEL_PATH=\"./model/full_iris_model.h5\"\nSCALER_PATH=\"./model/iris_data_norm.pkl\"\n```\n\n## IRIS Dataset\n\n\u003e `wget https://gist.githubusercontent.com/Thanatoz-1/9e7fdfb8189f0cdf5d73a494e4a6392a/raw/aaecbd14aeaa468cd749528f291aa8a30c2ea09e/iris_dataset.csv`\n\n```python\niris_dataset = pd.read_csv(\"./data/iris_dataset.csv\")\niris_dataset.head()\n```\n\n```python\n# separate features from labels\nX = iris_dataset.drop('target', axis=1)\nX.head()\n```\n\n```python\ny = iris_dataset['target']\ny.unique()\n```\n\n```python\n# 1-hot encoding labels\nencoder = LabelBinarizer()\ny = encoder.fit_transform(y)\ny[0]\n```\n\n```python\n# create training / testing datasets\nX_train, X_test, y_train, y_test = train_test_split(\n                                        X, y,\n                                        test_size=0.2,\n                                        random_state=SEED)\n```\n\n```python\n# normalize training data\nscaler = MinMaxScaler()\nscaler.fit(X_train)\nX_train_norm = scaler.transform(X_train)\nX_test_norm = scaler.transform(X_test)\n```\n\n## Building the Model\n\n```python\niris_model = Sequential([\n    Dense(units=4, activation='relu', input_shape=[4,]),\n    Dense(units=3, activation='softmax')\n])\n\niris_model.compile(optimizer='adam',\n                  loss='categorical_crossentropy',\n                  metrics=['accuracy'])\n```\n\n```python\n# fitting the model\nearly_stop = EarlyStopping(\n    monitor='val_loss',\n    min_delta=0.0001,\n    patience=10,\n    verbose=0,\n    mode='auto',\n    baseline=None,\n    restore_best_weights=True,\n    start_from_epoch=0)\n```\n\n## Fitting the Model\n\n```python\nhistory_iris_model = iris_model.fit(x=X_train_norm,\n         y=y_train,\n         epochs=EPOCHS,\n         validation_data=(X_test_norm, y_test),\n         callbacks=[early_stop])\n```\n\n```python\n# evaluate the model\niris_model.evaluate(X_test_norm, y_test, verbose=0)\n# [0.334958016872406, 0.8999999761581421]\n```\n\n```python\n# plot the validation accuracy\ndef plot_accuracy_curves(history, title):\n    accuracy = history.history['accuracy']\n    val_accuracy = history.history['val_accuracy']\n    epochs = range(len(history.history['accuracy']))\n\n    # Plot accuracy\n    plt.figure(figsize=(12, 6))\n    plt.plot(epochs, accuracy, label='training_accuracy')\n    plt.plot(epochs, val_accuracy, label='val_accuracy')\n    plt.title(title)\n    plt.xlabel('Epochs')\n    plt.legend();\n```\n\n```python\nplot_accuracy_curves(history_iris_model, \"IRIS Dataset :: Accuracy Curve\")\n```\n\n![Deploying Prediction APIs](https://github.com/mpolinowski/ml-flask-web-app/blob/master/assets/IRIS_Dataset_Model_Deployment_01.png)\n\n\n```python\n# plot the training loss\ndef plot_loss_curves(history, title):\n    loss = history.history['loss']\n    val_loss = history.history['val_loss']\n    epochs = range(len(history.history['loss']))\n\n    # Plot accuracy\n    plt.figure(figsize=(12, 6))\n    plt.plot(epochs, loss, label='training_loss')\n    plt.plot(epochs, val_loss, label='val_loss')\n    plt.title(title)\n    plt.xlabel('Epochs')\n    plt.legend();\n```\n\n```python\nplot_loss_curves(history_iris_model, \"IRIS Dataset :: Loss Curve\")\n```\n\n![Deploying Prediction APIs](https://github.com/mpolinowski/ml-flask-web-app/blob/master/assets/IRIS_Dataset_Model_Deployment_02.png)\n\n\n## Fit all Data\n\n\nAfter reaching a approx. 90% accuracy we can now add the testing data to our model training to increase the dataset variety the model was trained on.\n\n```python\nX_norm =scaler.fit_transform(X)\n```\n\n```python\niris_model_full = Sequential([\n    Dense(units=4, activation='relu', input_shape=[4,]),\n    Dense(units=3, activation='softmax')\n])\n\niris_model_full.compile(optimizer='adam',\n                  loss='categorical_crossentropy',\n                  metrics=['accuracy'])\n```\n\n```python\nhistory_iris_model_full = iris_model_full.fit(X_norm, y, epochs=EPOCHS)\n```\n\n```python\n# evaluate the model\niris_model_full.evaluate(X_norm, y, verbose=0)\n# [0.1931973546743393, 0.9733333587646484]\n```\n\n```python\n# plot the validation and training loss\ndef plot_training_curves(history, title):\n    accuracy = history.history['accuracy']\n    loss = history.history['loss']\n    epochs = range(len(history.history['loss']))\n\n    # Plot accuracy\n    plt.figure(figsize=(12, 6))\n    plt.plot(epochs, accuracy, label='training_accuracy')\n    plt.plot(epochs, loss, label='training_loss')\n    plt.title(title)\n    plt.xlabel('Epochs')\n    plt.legend();\n```\n\n```python\n# plot accuracy and loss curves\nplt.figure(figsize=(12, 6))\nplot_training_curves(history_iris_model_full, \"IRIS Dataset :: Training Curves\")\n```\n\n![Deploying Prediction APIs](https://github.com/mpolinowski/ml-flask-web-app/blob/master/assets/IRIS_Dataset_Model_Deployment_03.png)\n\n\n## Save the Trained Model\n\n```python\n# save the full model with training weights\niris_model_full.save(MODEL_PATH)\n```\n\n```python\n# save data preprocessing\njoblib.dump(scaler, SCALER_PATH)\n```\n\n## Run Predictions\n\n```python\n# load the saved model\nloaded_iris_model = load_model(MODEL_PATH)\nloaded_scaler = joblib.load(SCALER_PATH)\n```\n\n```python\n# verify predictions are the same\nloaded_iris_model.evaluate(X_norm, y, verbose=0)\n```\n\n## Prediction API\n\n```python\n# simulate JSON API call\nflower_example = {\"sepal length (cm)\": 5.1,\n                  \"sepal width (cm)\": 3.5,\n                  \"petal length (cm)\":1.4,\n                  \"petal width (cm)\": 0.2}\n```\n\n```python\n# API function (return class index with highest probability)\ndef return_prediction(model, scaler, json_request):\n    s_len = json_request[\"sepal length (cm)\"]\n    s_wi = json_request[\"sepal width (cm)\"]\n    p_len = json_request[\"petal length (cm)\"]\n    p_w = json_request[\"petal width (cm)\"]\n    \n    measures =[[s_len, s_wi, p_len, p_w]]\n    measures_norm = scaler.transform(measures)\n    \n    flower_class_probabilities = model.predict(measures_norm)\n    flower_class_index=np.argmax(flower_class_probabilities,axis=1)\n                           \n    return flower_class_index\n```\n\n```python\nreturn_prediction(loaded_iris_model, loaded_scaler, flower_example)\n# probabilities array([[9.987895e-01, 7.723020e-04, 4.383073e-04]], dtype=float32)\n# index array([0])\n```\n\n```python\n# API function (return class name)\ndef return_prediction(model, scaler, json_request):\n    s_len = json_request[\"sepal length (cm)\"]\n    s_wi = json_request[\"sepal width (cm)\"]\n    p_len = json_request[\"petal length (cm)\"]\n    p_w = json_request[\"petal width (cm)\"]\n    \n    classes = np.array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'])\n    measures =[[s_len, s_wi, p_len, p_w]]\n    measures_norm = scaler.transform(measures)\n    \n    flower_class_probabilities = model.predict(measures_norm)\n    flower_class_index=np.argmax(flower_class_probabilities,axis=1)\n                       \n    return classes[flower_class_index]\n```\n\n```python\nreturn_prediction(loaded_iris_model, loaded_scaler, flower_example)\n# array(['Iris-setosa'], dtype='\u003cU15')\n```\n\n\n### Prediction Frontend\n\nStart the Flask server:\n\n\n```bash\npython Flask_Server.py\n```\n\n\n![Deploying Prediction APIs](https://github.com/mpolinowski/ml-flask-web-app/blob/master/assets/IRIS_Dataset_Model_Deployment_05.png)\n\n\n![Deploying Prediction APIs](https://github.com/mpolinowski/ml-flask-web-app/blob/master/assets/IRIS_Dataset_Model_Deployment_06.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolinowski%2Fml-flask-web-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpolinowski%2Fml-flask-web-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolinowski%2Fml-flask-web-app/lists"}