Skip to content

Commit

Permalink
Add new TensorFlow Serving + Flutter text classification codelabs (fl…
Browse files Browse the repository at this point in the history
  • Loading branch information
windmaple committed Mar 21, 2022
1 parent 7c51541 commit a33a380
Show file tree
Hide file tree
Showing 309 changed files with 54,319 additions and 0 deletions.
1 change: 1 addition & 0 deletions flutter_ci_script_beta.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ declare -a CODELABS=(
"star_counter"
"startup_namer"
"testing_codelab"
"tfserving-flutter"
"webview_flutter"
)

Expand Down
1 change: 1 addition & 0 deletions flutter_ci_script_stable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ declare -a CODELABS=(
"star_counter"
"startup_namer"
"testing_codelab"
"tfserving-flutter"
"webview_flutter"
)

Expand Down
8 changes: 8 additions & 0 deletions tfserving-flutter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# tfserving_flutter

This folder contains the codelabs for the TensorFlow Serving Text Classification Learning Pathway (TODO: update link).

The folder is organized as:
- `codelab1` contains the first codelab code to train a spam detection model
- `codelab2` contains the second codelab code to connect Flutter frontend to TensorFlow Serving backend
- `codelab3` contains the third codelab code to enhance the spam detection model to detect specific spam phrases
194 changes: 194 additions & 0 deletions tfserving-flutter/codelab1/SpamCommentsModelMaker.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "SpamCommentsModelMaker.ipynb",
"provenance": [],
"collapsed_sections": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "code",
"metadata": {
"id": "Awq8sMaIFHJ1"
},
"source": [
"# Install Model maker\n",
"!pip install -q tflite-model-maker &> /dev/null"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "2fEAqoLLF6O9"
},
"source": [
"# Imports and check that we are using TF2.x\n",
"import numpy as np\n",
"import os\n",
"\n",
"from tflite_model_maker import configs\n",
"from tflite_model_maker import ExportFormat\n",
"from tflite_model_maker import model_spec\n",
"from tflite_model_maker import text_classifier\n",
"from tflite_model_maker.text_classifier import DataLoader\n",
"\n",
"import tensorflow as tf\n",
"assert tf.__version__.startswith('2')\n",
"tf.get_logger().setLevel('ERROR')"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "lsuDZvjgREsS"
},
"source": [
"# Download the dataset as a CSV and store as data_file\n",
"data_file = tf.keras.utils.get_file(fname='comment-spam.csv', origin='https://storage.googleapis.com/laurencemoroney-blog.appspot.com/lmblog_comments.csv', extract=False)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "pbew43TbG9HQ"
},
"source": [
"# Use a model spec from model maker. Options are 'mobilebert_classifier', 'bert_classifier' and 'average_word_vec'\n",
"# The first 2 use the BERT model, which is accurate, but larger and slower to train\n",
"# Average Word Vec is kinda like transfer learning where there are pre-trained word weights\n",
"# and dictionaries\n",
"spec = model_spec.get('average_word_vec')\n",
"spec.num_words = 2000\n",
"spec.seq_len = 20\n",
"spec.wordvec_dim = 7"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "-WdQmzTKHFVn"
},
"source": [
"# Load the CSV using DataLoader.from_csv to make the training_data\n",
"data = DataLoader.from_csv(\n",
" filename=data_file,\n",
" text_column='commenttext', \n",
" label_column='spam', \n",
" model_spec=spec,\n",
" delimiter=',',\n",
" shuffle=True,\n",
" is_training=True)\n",
"\n",
"train_data, test_data = data.split(0.9)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "qThBoIIyG_Du"
},
"source": [
"# Build the model\n",
"model = text_classifier.create(train_data, model_spec=spec, epochs=50, validation_data=test_data)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "5QXEwKYxdPzs"
},
"source": [
"loss, accuracy = model.evaluate(train_data)"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "In-1-rzW-_9b"
},
"source": [
"# This will export to SavedModel format with the model, vocabulary and labels. \n",
"model.export(export_dir='/mm_spam_savedmodel/', export_format=[ExportFormat.LABEL, ExportFormat.VOCAB, ExportFormat.SAVED_MODEL])\n",
"\n",
"# You can find your files in colab by clicking the 'folder' tab to the left of\n",
"# this code window, and then navigating 'up' a directory to find the root\n",
"# directory listing -- and from there you should see /mm_spam_savedmodel/"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"# Rename the SavedModel subfolder to a version number\n",
"!mv /mm_spam_savedmodel/saved_model /mm_spam_savedmodel/123\n",
"!zip -r mm_spam_savedmodel.zip /mm_spam_savedmodel/ "
],
"metadata": {
"id": "mIhBu3pI_2Xz"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "3UNNrCWbKbxh"
},
"source": [
"# Optional extra\n",
"# You can use this cell to export details for projector.tensorflow.org\n",
"# Where you can explore the embeddings that were learned for this dataset\n",
"embeddings = model.model.layers[0]\n",
"weights = embeddings.get_weights()[0]\n",
"tokenizer = model.model_spec.vocab\n",
"\n",
"import io\n",
"\n",
"out_v = io.open('vecs.tsv', 'w', encoding='utf-8')\n",
"out_m = io.open('meta.tsv', 'w', encoding='utf-8')\n",
"for word in tokenizer:\n",
" #word = tokenizer.decode([word_num])\n",
" value = tokenizer[word]\n",
" embeddings = weights[value]\n",
" out_m.write(word + \"\\n\")\n",
" out_v.write('\\t'.join([str(x) for x in embeddings]) + \"\\n\")\n",
"out_v.close()\n",
"out_m.close()\n",
"\n",
"\n",
"try:\n",
" from google.colab import files\n",
"except ImportError:\n",
" pass\n",
"else:\n",
" files.download('vecs.tsv')\n",
" files.download('meta.tsv')"
],
"execution_count": null,
"outputs": []
}
]
}
1,001 changes: 1,001 additions & 0 deletions tfserving-flutter/codelab1/lmblog_comments.csv

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

�*root"_tf_keras_sequential*�*{"name": "sequential_2", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "must_restore_from_config": false, "class_name": "Sequential", "config": {"name": "sequential_2", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "dtype": "int32", "sparse": false, "ragged": false, "name": "input_3"}}, {"class_name": "Embedding", "config": {"name": "embedding_2", "trainable": true, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "dtype": "float32", "input_dim": 2003, "output_dim": 7, "embeddings_initializer": {"class_name": "RandomUniform", "config": {"minval": -0.05, "maxval": 0.05, "seed": null}}, "embeddings_regularizer": null, "activity_regularizer": null, "embeddings_constraint": null, "mask_zero": false, "input_length": 20}}, {"class_name": "GlobalAveragePooling1D", "config": {"name": "global_average_pooling1d_2", "trainable": true, "dtype": "float32", "data_format": "channels_last", "keepdims": false}}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 7, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}, {"class_name": "Dropout", "config": {"name": "dropout_2", "trainable": true, "dtype": "float32", "rate": 0.2, "noise_shape": null, "seed": null}}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 2, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}}, "bias_initializer": {"class_name": "Zeros", "config": {}}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}}]}, "shared_object_id": 11, "input_spec": [{"class_name": "InputSpec", "config": {"dtype": null, "shape": {"class_name": "__tuple__", "items": [null, 20]}, "ndim": 2, "max_ndim": null, "min_ndim": null, "axes": {}}}], "build_input_shape": {"class_name": "TensorShape", "items": [null, 20]}, "is_graph_network": true, "full_save_spec": {"class_name": "__tuple__", "items": [[{"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 20]}, "int32", "input_3"]}], {}]}, "save_spec": {"class_name": "TypeSpec", "type_spec": "tf.TensorSpec", "serialized": [{"class_name": "TensorShape", "items": [null, 20]}, "int32", "input_3"]}, "keras_version": "2.7.0", "backend": "tensorflow", "model_config": {"class_name": "Sequential", "config": {"name": "sequential_2", "layers": [{"class_name": "InputLayer", "config": {"batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "dtype": "int32", "sparse": false, "ragged": false, "name": "input_3"}, "shared_object_id": 0}, {"class_name": "Embedding", "config": {"name": "embedding_2", "trainable": true, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "dtype": "float32", "input_dim": 2003, "output_dim": 7, "embeddings_initializer": {"class_name": "RandomUniform", "config": {"minval": -0.05, "maxval": 0.05, "seed": null}, "shared_object_id": 1}, "embeddings_regularizer": null, "activity_regularizer": null, "embeddings_constraint": null, "mask_zero": false, "input_length": 20}, "shared_object_id": 2}, {"class_name": "GlobalAveragePooling1D", "config": {"name": "global_average_pooling1d_2", "trainable": true, "dtype": "float32", "data_format": "channels_last", "keepdims": false}, "shared_object_id": 3}, {"class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 7, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "shared_object_id": 6}, {"class_name": "Dropout", "config": {"name": "dropout_2", "trainable": true, "dtype": "float32", "rate": 0.2, "noise_shape": null, "seed": null}, "shared_object_id": 7}, {"class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 2, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 8}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 9}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "shared_object_id": 10}]}}, "training_config": {"loss": "sparse_categorical_crossentropy", "metrics": [[{"class_name": "MeanMetricWrapper", "config": {"name": "accuracy", "dtype": "float32", "fn": "sparse_categorical_accuracy"}, "shared_object_id": 13}]], "weighted_metrics": null, "loss_weights": null, "optimizer_config": {"class_name": "RMSprop", "config": {"name": "RMSprop", "learning_rate": 0.0010000000474974513, "decay": 0.0, "rho": 0.8999999761581421, "momentum": 0.0, "epsilon": 1e-07, "centered": false}}}}2
�root.layer_with_weights-0"_tf_keras_layer*�{"name": "embedding_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "stateful": false, "must_restore_from_config": false, "class_name": "Embedding", "config": {"name": "embedding_2", "trainable": true, "batch_input_shape": {"class_name": "__tuple__", "items": [null, 20]}, "dtype": "float32", "input_dim": 2003, "output_dim": 7, "embeddings_initializer": {"class_name": "RandomUniform", "config": {"minval": -0.05, "maxval": 0.05, "seed": null}, "shared_object_id": 1}, "embeddings_regularizer": null, "activity_regularizer": null, "embeddings_constraint": null, "mask_zero": false, "input_length": 20}, "shared_object_id": 2, "build_input_shape": {"class_name": "TensorShape", "items": [null, 20]}}2
� root.layer-1"_tf_keras_layer*�{"name": "global_average_pooling1d_2", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "GlobalAveragePooling1D", "config": {"name": "global_average_pooling1d_2", "trainable": true, "dtype": "float32", "data_format": "channels_last", "keepdims": false}, "shared_object_id": 3, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": 3, "max_ndim": null, "min_ndim": null, "axes": {}}, "shared_object_id": 14}}2
�root.layer_with_weights-1"_tf_keras_layer*�{"name": "dense_4", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_4", "trainable": true, "dtype": "float32", "units": 7, "activation": "relu", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 4}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 5}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "shared_object_id": 6, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 7}}, "shared_object_id": 15}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 7]}}2
� root.layer-3"_tf_keras_layer*�{"name": "dropout_2", "trainable": true, "expects_training_arg": true, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dropout", "config": {"name": "dropout_2", "trainable": true, "dtype": "float32", "rate": 0.2, "noise_shape": null, "seed": null}, "shared_object_id": 7}2
�root.layer_with_weights-2"_tf_keras_layer*�{"name": "dense_5", "trainable": true, "expects_training_arg": false, "dtype": "float32", "batch_input_shape": null, "stateful": false, "must_restore_from_config": false, "class_name": "Dense", "config": {"name": "dense_5", "trainable": true, "dtype": "float32", "units": 2, "activation": "softmax", "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null}, "shared_object_id": 8}, "bias_initializer": {"class_name": "Zeros", "config": {}, "shared_object_id": 9}, "kernel_regularizer": null, "bias_regularizer": null, "activity_regularizer": null, "kernel_constraint": null, "bias_constraint": null}, "shared_object_id": 10, "input_spec": {"class_name": "InputSpec", "config": {"dtype": null, "shape": null, "ndim": null, "max_ndim": null, "min_ndim": 2, "axes": {"-1": 7}}, "shared_object_id": 16}, "build_input_shape": {"class_name": "TensorShape", "items": [null, 7]}}2
�Hroot.keras_api.metrics.0"_tf_keras_metric*�{"class_name": "Mean", "name": "loss", "dtype": "float32", "config": {"name": "loss", "dtype": "float32"}, "shared_object_id": 17}2
�Iroot.keras_api.metrics.1"_tf_keras_metric*�{"class_name": "MeanMetricWrapper", "name": "accuracy", "dtype": "float32", "config": {"name": "accuracy", "dtype": "float32", "fn": "sparse_categorical_accuracy"}, "shared_object_id": 13}2
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 2 additions & 0 deletions tfserving-flutter/codelab1/mm_spam_savedmodel/labels.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
false
true
Loading

0 comments on commit a33a380

Please sign in to comment.