From 76fd91c16bd784a060b4b9270ef5d75a128e96f4 Mon Sep 17 00:00:00 2001 From: Putu Widyantara Artanta Wibawa Date: Tue, 19 Dec 2023 00:16:15 +0800 Subject: [PATCH 1/5] [#3] feat: initial model for food recommendation --- MamMates_Food_Recommendation.ipynb | 1279 ++++++++++++++++++++++++++++ 1 file changed, 1279 insertions(+) create mode 100644 MamMates_Food_Recommendation.ipynb diff --git a/MamMates_Food_Recommendation.ipynb b/MamMates_Food_Recommendation.ipynb new file mode 100644 index 0000000..544917b --- /dev/null +++ b/MamMates_Food_Recommendation.ipynb @@ -0,0 +1,1279 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "authorship_tag": "ABX9TyP0JCX49ckXYwZmiLthlXQ1", + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YFM6rA9WjU7T" + }, + "outputs": [], + "source": [ + "!pip install -q tensorflow-recommenders" + ] + }, + { + "cell_type": "code", + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import tensorflow as tf\n", + "import tensorflow_recommenders as tfrs" + ], + "metadata": { + "id": "C9BSA2Z2jjiy" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "dataset_link = \"https://docs.google.com/spreadsheets/d/1o0f663wcmMfta_PAILOJzkvn09_Mbjw5zBxgcDk1Au0\"\n", + "\n", + "df_dataset = pd.read_csv(f'{dataset_link}/export?gid=0&format=csv')\n", + "df_dataset" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 424 + }, + "id": "7kknJDXajsut", + "outputId": "7a078d83-b752-48bd-e3f4-85dec11e5333" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " id_user id_food rating\n", + "0 63 15 1\n", + "1 66 20 2\n", + "2 37 1 2\n", + "3 39 13 3\n", + "4 52 18 1\n", + ".. ... ... ...\n", + "995 35 17 3\n", + "996 79 20 1\n", + "997 92 1 1\n", + "998 1 14 3\n", + "999 29 15 2\n", + "\n", + "[1000 rows x 3 columns]" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
id_userid_foodrating
063151
166202
23712
339133
452181
............
99535173
99679201
9979211
9981143
99929152
\n", + "

1000 rows × 3 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 3 + } + ] + }, + { + "cell_type": "code", + "source": [ + "df_food_info = pd.read_csv(f'{dataset_link}/export?gid=1905501804&format=csv')\n", + "df_food_info.head()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "qbOMD77hsuHF", + "outputId": "23bc3cdd-8ffa-4ce7-ae82-f614a82fdb50" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " id_food food_name\n", + "0 1 Donat Ubi Mawar\n", + "1 2 Donat Ubi Mawar\n", + "2 3 Kue Cubit Maniez\n", + "3 4 Kue Cubit Maniez\n", + "4 5 Kue Lapis Legit" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
id_foodfood_name
01Donat Ubi Mawar
12Donat Ubi Mawar
23Kue Cubit Maniez
34Kue Cubit Maniez
45Kue Lapis Legit
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "
\n", + "
\n" + ] + }, + "metadata": {}, + "execution_count": 4 + } + ] + }, + { + "cell_type": "code", + "source": [ + "len(df_dataset.id_user.unique())" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "KX6diJUZqX1U", + "outputId": "bc0d8e21-8bc4-4ed1-a5ca-c63f15165db8" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "100" + ] + }, + "metadata": {}, + "execution_count": 5 + } + ] + }, + { + "cell_type": "code", + "source": [ + "len(df_dataset.id_food.unique())" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "_kMQeQv4qeXV", + "outputId": "e115df20-5317-4344-ae5e-6fb9c5ff7fe7" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "20" + ] + }, + "metadata": {}, + "execution_count": 6 + } + ] + }, + { + "cell_type": "code", + "source": [ + "ratings = tf.data.Dataset.from_tensor_slices(\n", + " {\"user_id\": df_dataset.id_user.astype(str),\n", + " \"food_id\": df_dataset.id_food.astype(str)}\n", + ")" + ], + "metadata": { + "id": "8xw6PBsCp0Ka" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "for x in ratings.take(2).as_numpy_iterator():\n", + " print(x)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "g_RTUa3It83W", + "outputId": "925b2f7a-d7c8-43c9-8322-64d3f1282fc2" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{'user_id': b'63', 'food_id': b'15'}\n", + "{'user_id': b'66', 'food_id': b'20'}\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "foods = tf.data.Dataset.from_tensor_slices(\n", + " df_food_info.id_food.astype(str)\n", + ")" + ], + "metadata": { + "id": "W9Itp9hsuDT4" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "for x in foods.take(2).as_numpy_iterator():\n", + " print(x)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hGAjf97yuJl2", + "outputId": "e95d0796-7740-4cf8-b752-854cdfa560ea" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "b'1'\n", + "b'2'\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "tf.random.set_seed(42)\n", + "shuffled = ratings.shuffle(1000, seed=42, reshuffle_each_iteration=False)\n", + "train = shuffled.take(800)\n", + "test = shuffled.skip(800).take(200)" + ], + "metadata": { + "id": "Xl6EzRnludse" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "food_ids = foods.batch(32)\n", + "user_ids = ratings.batch(32).map(lambda x: x[\"user_id\"])\n", + "\n", + "unique_food_ids = np.unique(np.concatenate(list(food_ids)))\n", + "unique_user_ids = np.unique(np.concatenate(list(user_ids)))\n", + "\n", + "unique_food_ids[:10]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dLBIUlGSumyR", + "outputId": "8f5cc627-b4cc-4708-927b-765e5b694c1e" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "array([b'1', b'10', b'11', b'12', b'13', b'14', b'15', b'16', b'17',\n", + " b'18'], dtype=object)" + ] + }, + "metadata": {}, + "execution_count": 12 + } + ] + }, + { + "cell_type": "code", + "source": [ + "embedding_dimension = 32" + ], + "metadata": { + "id": "wllc3TqVlLRQ" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "user_model = tf.keras.Sequential([\n", + " tf.keras.layers.StringLookup(\n", + " vocabulary=unique_user_ids, mask_token=None),\n", + " tf.keras.layers.Embedding(len(unique_user_ids) + 1, embedding_dimension)\n", + "])" + ], + "metadata": { + "id": "oP1EClIRlzaE" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "food_model = tf.keras.Sequential([\n", + " tf.keras.layers.StringLookup(\n", + " vocabulary=unique_food_ids, mask_token=None),\n", + " tf.keras.layers.Embedding(len(unique_food_ids) + 1, embedding_dimension)\n", + "])" + ], + "metadata": { + "id": "cMOy7PcSl1mx" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "metrics = tfrs.metrics.FactorizedTopK(\n", + " candidates=foods.batch(32).map(food_model)\n", + ")" + ], + "metadata": { + "id": "pP5WvcaLl6Z7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "task = tfrs.tasks.Retrieval(\n", + " metrics=metrics\n", + ")" + ], + "metadata": { + "id": "86P6Q0oZl78d" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "from typing import Dict, Text\n", + "\n", + "class MamMatesModel(tfrs.Model):\n", + "\n", + " def __init__(self, user_model, food_model):\n", + " super().__init__()\n", + " self.food_model: tf.keras.Model = food_model\n", + " self.user_model: tf.keras.Model = user_model\n", + " self.task: tf.keras.layers.Layer = task\n", + "\n", + " def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> tf.Tensor:\n", + " user_embeddings = self.user_model(features[\"user_id\"])\n", + " positive_food_embeddings = self.food_model(features[\"food_id\"])\n", + "\n", + " return self.task(user_embeddings, positive_food_embeddings)" + ], + "metadata": { + "id": "eyvpoKQKvZib" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "class NoBaseClassMammatesModel(tf.keras.Model):\n", + "\n", + " def __init__(self, user_model, food_model):\n", + " super().__init__()\n", + " self.food_model: tf.keras.Model = food_model\n", + " self.user_model: tf.keras.Model = user_model\n", + " self.task: tf.keras.layers.Layer = task\n", + "\n", + " def train_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:\n", + "\n", + " with tf.GradientTape() as tape:\n", + "\n", + " user_embeddings = self.user_model(features[\"user_id\"])\n", + " positive_food_embeddings = self.food_model(features[\"food_id\"])\n", + " loss = self.task(user_embeddings, positive_food_embeddings)\n", + "\n", + " regularization_loss = sum(self.losses)\n", + "\n", + " total_loss = loss + regularization_loss\n", + "\n", + " gradients = tape.gradient(total_loss, self.trainable_variables)\n", + " self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))\n", + "\n", + " metrics = {metric.name: metric.result() for metric in self.metrics}\n", + " metrics[\"loss\"] = loss\n", + " metrics[\"regularization_loss\"] = regularization_loss\n", + " metrics[\"total_loss\"] = total_loss\n", + "\n", + " return metrics\n", + "\n", + " def test_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:\n", + "\n", + " user_embeddings = self.user_model(features[\"user_id\"])\n", + " positive_food_embeddings = self.food_model(features[\"food_id\"])\n", + " loss = self.task(user_embeddings, positive_food_embeddings)\n", + "\n", + " regularization_loss = sum(self.losses)\n", + "\n", + " total_loss = loss + regularization_loss\n", + "\n", + " metrics = {metric.name: metric.result() for metric in self.metrics}\n", + " metrics[\"loss\"] = loss\n", + " metrics[\"regularization_loss\"] = regularization_loss\n", + " metrics[\"total_loss\"] = total_loss\n", + "\n", + " return metrics" + ], + "metadata": { + "id": "0VojqHclvu1K" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "model = MamMatesModel(user_model, food_model)\n", + "model.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate=0.1))" + ], + "metadata": { + "id": "FfU1Jjgmv6kG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "cached_train = train.shuffle(1000).batch(32).cache()\n", + "cached_test = test.batch(32).cache()" + ], + "metadata": { + "id": "a8QxhPIJwNP3" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "model.fit(cached_train, epochs=3)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "NBy9ts6NwQJx", + "outputId": "ead9bd3c-1cae-491e-f206-3bba7de320b1" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/3\n", + "25/25 [==============================] - 4s 49ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0000e+00 - factorized_top_k/top_5_categorical_accuracy: 0.2025 - factorized_top_k/top_10_categorical_accuracy: 0.4787 - factorized_top_k/top_50_categorical_accuracy: 1.0000 - factorized_top_k/top_100_categorical_accuracy: 1.0000 - loss: 110.9281 - regularization_loss: 0.0000e+00 - total_loss: 110.9281\n", + "Epoch 2/3\n", + "25/25 [==============================] - 3s 102ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0012 - factorized_top_k/top_5_categorical_accuracy: 0.3237 - factorized_top_k/top_10_categorical_accuracy: 0.6488 - factorized_top_k/top_50_categorical_accuracy: 1.0000 - factorized_top_k/top_100_categorical_accuracy: 1.0000 - loss: 109.5470 - regularization_loss: 0.0000e+00 - total_loss: 109.5470\n", + "Epoch 3/3\n", + "25/25 [==============================] - 4s 149ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0088 - factorized_top_k/top_5_categorical_accuracy: 0.4137 - factorized_top_k/top_10_categorical_accuracy: 0.7500 - factorized_top_k/top_50_categorical_accuracy: 1.0000 - factorized_top_k/top_100_categorical_accuracy: 1.0000 - loss: 105.0930 - regularization_loss: 0.0000e+00 - total_loss: 105.0930\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 22 + } + ] + }, + { + "cell_type": "code", + "source": [ + "model.evaluate(cached_test, return_dict=True)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3k7U2ERXwQ_q", + "outputId": "ee35229a-5ed3-41c4-9516-40bdbdc7ade8" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "7/7 [==============================] - 1s 94ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0250 - factorized_top_k/top_5_categorical_accuracy: 0.2400 - factorized_top_k/top_10_categorical_accuracy: 0.4800 - factorized_top_k/top_50_categorical_accuracy: 1.0000 - factorized_top_k/top_100_categorical_accuracy: 1.0000 - loss: 90.3494 - regularization_loss: 0.0000e+00 - total_loss: 90.3494\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "{'factorized_top_k/top_1_categorical_accuracy': 0.02500000037252903,\n", + " 'factorized_top_k/top_5_categorical_accuracy': 0.23999999463558197,\n", + " 'factorized_top_k/top_10_categorical_accuracy': 0.47999998927116394,\n", + " 'factorized_top_k/top_50_categorical_accuracy': 1.0,\n", + " 'factorized_top_k/top_100_categorical_accuracy': 1.0,\n", + " 'loss': 16.14521026611328,\n", + " 'regularization_loss': 0,\n", + " 'total_loss': 16.14521026611328}" + ] + }, + "metadata": {}, + "execution_count": 23 + } + ] + }, + { + "cell_type": "code", + "source": [ + "index = tfrs.layers.factorized_top_k.BruteForce(model.user_model)\n", + "index.index_from_dataset(\n", + " tf.data.Dataset.zip((foods.batch(32), foods.batch(32).map(model.food_model)))\n", + ")\n", + "\n", + "_, titles = index(tf.constant([\"14\"]))\n", + "print(f\"Recommendations for user with ID 14: {titles[0, :3]}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6F3hGUB9wUvW", + "outputId": "9e0ba438-b825-4b5b-acb4-455447008c92" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Recommendations for user with ID 14: [b'13' b'14' b'12']\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "list_titles = titles.numpy().astype(int).tolist()\n", + "list_titles[0]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XXxgMglnwiMR", + "outputId": "50ac6086-4244-4c69-d9d7-6cce9bcaaa9e" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "[13, 14, 12, 2, 18, 20, 11, 10, 7, 9]" + ] + }, + "metadata": {}, + "execution_count": 25 + } + ] + }, + { + "cell_type": "code", + "source": [ + "filtered_foods = df_food_info[df_food_info['id_food'].isin(list_titles[0])]\n", + "\n", + "id_to_food = dict(zip(filtered_foods['id_food'], filtered_foods['food_name']))\n", + "\n", + "food_names = [id_to_food.get(id) for id in list_titles[0]]\n", + "print(f\"Recommendations for user with ID 14: {food_names[:3]}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-4UbSuDbw9Jz", + "outputId": "0bf494a4-ad22-42c8-d32a-e0fd73fd340f" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Recommendations for user with ID 14: ['Roti Bakar Cokelat Keju', 'Roti Bakar Niqmat', 'Donat Ubi Rasa Cinta']\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import tempfile\n", + "import os\n", + "\n", + "MODEL_DIR = tempfile.gettempdir()\n", + "version = 1\n", + "export_path = os.path.join(MODEL_DIR, str(version))\n", + "print('export_path = {}\\n'.format(export_path))\n", + "\n", + "tf.saved_model.save(index, export_path)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pHQo33U_xTHh", + "outputId": "c77e8768-b53c-4e57-bbf2-1d9fa7337e0c" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "export_path = /tmp/1\n", + "\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "WARNING:tensorflow:Model's `__init__()` arguments contain non-serializable objects. Please implement a `get_config()` method in the subclassed Model for proper saving and loading. Defaulting to empty config.\n", + "WARNING:tensorflow:Model's `__init__()` arguments contain non-serializable objects. Please implement a `get_config()` method in the subclassed Model for proper saving and loading. Defaulting to empty config.\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!zip -r model.zip /tmp/1/" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "A4Am38VZzEYW", + "outputId": "8292736f-8e9e-4422-b46a-5d63cc20c391" + }, + "execution_count": null, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "updating: tmp/1/ (stored 0%)\n", + "updating: tmp/1/fingerprint.pb (stored 0%)\n", + "updating: tmp/1/variables/ (stored 0%)\n", + "updating: tmp/1/variables/variables.index (deflated 34%)\n", + "updating: tmp/1/variables/variables.data-00000-of-00001 (deflated 15%)\n", + "updating: tmp/1/assets/ (stored 0%)\n", + "updating: tmp/1/saved_model.pb (deflated 84%)\n" + ] + } + ] + } + ] +} \ No newline at end of file From 2a7cbd90273f731ad437400ba53b48038edae036 Mon Sep 17 00:00:00 2001 From: Putu Widyantara Artanta Wibawa Date: Tue, 19 Dec 2023 00:24:28 +0800 Subject: [PATCH 2/5] [#3] feat: initial saved model for food recommendation --- model/fingerprint.pb | 1 + model/saved_model.pb | Bin 0 -> 51541 bytes model/variables/variables.data-00000-of-00001 | Bin 0 -> 18136 bytes model/variables/variables.index | Bin 0 -> 331 bytes 4 files changed, 1 insertion(+) create mode 100644 model/fingerprint.pb create mode 100644 model/saved_model.pb create mode 100644 model/variables/variables.data-00000-of-00001 create mode 100644 model/variables/variables.index diff --git a/model/fingerprint.pb b/model/fingerprint.pb new file mode 100644 index 0000000..07b1255 --- /dev/null +++ b/model/fingerprint.pb @@ -0,0 +1 @@ +ΊY߭ЊS ߾(ǔܶ2 \ No newline at end of file diff --git a/model/saved_model.pb b/model/saved_model.pb new file mode 100644 index 0000000000000000000000000000000000000000..919373b50c91606abe8bfb994f8d27498e21b5cc GIT binary patch literal 51541 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 Yl&0)l_%IlQWm73=t|COAg?8}&0eVu~+W-In literal 0 HcmV?d00001 diff --git a/model/variables/variables.data-00000-of-00001 b/model/variables/variables.data-00000-of-00001 new file mode 100644 index 0000000000000000000000000000000000000000..df569425743ff154e77be2c3d8209a06b48e72b3 GIT binary patch literal 18136 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%0DY_n<fPdBq z{eRMkf&WvD_#0Iws=CQ4`Z#+}aCY%@^Y?M~oZ0=8@%MjmI!1rDF(WMhyGN@2o8tY}KcV7T{q2o@E1tAaC;tZgUell7|3D)C z*Qnof4iQSm;J>m}S=vBVJ|a3gd`XOd{BLt9?6gBv*lWl?%a7rICO<>}bNMm)>x1N_ zjsHo0O#Y|xBQ#WY9|L@G!@P9R1 z|Iex>Fa5vNEmL9Q^V?pG_!IckGFkqK_}yytC-9$Grr(727Wyme-~K8} z=mi5JLRSRE%Bo3^R8{t07#k$?Rzl++7ri8Q;cw43O6axz(N9)g+D27HsBCfZvC+%_ z-cLB^KRKa)0{+fg+y9ESqyNHMyT7t_%zwvP`+sHa|FahS@5SCo+T?%CS|uUB9RB2& zrI3if5!_!9ziIc|@@V~==hyzz^8CjC`Tbv8mj7Vj?>T=j0{*&)-w6Ca5srUF{JE6> Z?01mRGCBRlLkdCXe}LA1c^Tmh{~sRd>iz%# literal 0 HcmV?d00001 diff --git a/model/variables/variables.index b/model/variables/variables.index new file mode 100644 index 0000000000000000000000000000000000000000..341379c3032670041131c0624575d562e28c7f10 GIT binary patch literal 331 zcmZQzVB=tvV&Y(Akl~Ma_HcFf4)FK%3vqPvagFzP@^W@dr<^#AL5)8%B{i=kGc7Z<2(NZ_Ar_E!4Rh1muaAi_sEL;)7G)+T`Wg QNEv<*{=1=DrPTd40JQi_U;qFB literal 0 HcmV?d00001 From 025e9ab273303b9fe1d68e8e612e7b6a6795b12f Mon Sep 17 00:00:00 2001 From: Putu Widyantara Artanta Wibawa Date: Tue, 19 Dec 2023 00:29:47 +0800 Subject: [PATCH 3/5] [#3] build: create `Dockerfile` for serving model --- Dockerfile | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a45e401 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM tensorflow/serving:2.14.0 + +ENV MODEL_NAME=food_rec +ENV TF_CPP_VMODULE=http_server=1 + +COPY /model /models/${MODEL_NAME}/1/ + +CMD ["tensorflow_model_server", "--rest_api_port=8504", "--model_name=food_rec", "--model_base_path=/models/food_rec"] From ce2c4dece43704503ccaecd2cbda8a929cbe55d8 Mon Sep 17 00:00:00 2001 From: Putu Widyantara Artanta Wibawa Date: Tue, 19 Dec 2023 00:35:30 +0800 Subject: [PATCH 4/5] [#3] build: setup dependabot for gh actions and docker --- .github/dependabot.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9568d48 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 7 + commit-message: + prefix: "[deps-gh]: " + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 7 + commit-message: + prefix: "[deps-docker]: " From 112cff9a20283347546a35d6945248f29c0d7dfc Mon Sep 17 00:00:00 2001 From: Putu Widyantara Artanta Wibawa Date: Tue, 19 Dec 2023 00:36:57 +0800 Subject: [PATCH 5/5] [#3] build: create ci for publishing docker image --- .github/workflows/docker.yml | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..81a6a0a --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,37 @@ +name: Publish Docker Image + +on: + workflow_dispatch: + push: + branches: + - "main" + tags: + - "v*" + pull_request: + branches: + - "main" + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: putuwaw/mammates-food-recommendation + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }}