import os
PROJECT = "cloud-training-demos" # REPLACE WITH YOUR PROJECT ID
BUCKET = "cloud-training-demos-ml" # REPLACE WITH YOUR BUCKET NAME
REGION = "us-central1" # REPLACE WITH YOUR BUCKET REGION e.g. us-central1
MODEL_TYPE = "cnn"

# Do not change these
os.environ["PROJECT"] = PROJECT
os.environ["BUCKET"] = BUCKET
os.environ["REGION"] = REGION
os.environ["MODEL_TYPE"] = MODEL_TYPE
os.environ["TFVERSION"] = "1.13"  # Tensorflow version

%%bash
gcloud config set project $PROJECT
gcloud config set compute/region $REGION

"""
Explanation: Flowers Image Classification with TensorFlow on Cloud ML Engine
This notebook demonstrates how to do image classification from scratch on a flowers dataset using the Estimator API.
End of explanation
"""


%%bash
rm -rf flowersmodel.tar.gz flowers_trained
gcloud ml-engine local train \
    --module-name=flowersmodel.task \
    --package-path=${PWD}/flowersmodel \
    -- \
    --output_dir=${PWD}/flowers_trained \
    --train_steps=5 \
    --learning_rate=0.01 \
    --batch_size=2 \
    --model=$MODEL_TYPE \
    --augment \
    --train_data_path=gs://cloud-ml-data/img/flower_photos/train_set.csv \
    --eval_data_path=gs://cloud-ml-data/img/flower_photos/eval_set.csv

"""
Explanation: Input functions to read JPEG images
The key difference between this notebook and the MNIST one is in the input function.
In the input function here, we are doing the following:
* Reading JPEG images, rather than 2D integer arrays.
* Reading in batches of batch_size images rather than slicing our in-memory structure to be batch_size images.
* Resizing the images to the expected HEIGHT, WIDTH. Because this is a real-world dataset, the images are of different sizes. We need to preprocess the data to, at the very least, resize them to constant size.
Run as a Python module
Since we want to run our code on Cloud ML Engine, we've packaged it as a python module.
The model.py and task.py containing the model code is in <a href="flowersmodel">flowersmodel</a>
Complete the TODOs in model.py before proceeding!
Once you've completed the TODOs, run it locally for a few steps to test the code.
End of explanation
"""


%%bash
OUTDIR=gs://${BUCKET}/flowers/trained_${MODEL_TYPE}
JOBNAME=flowers_${MODEL_TYPE}_$(date -u +%y%m%d_%H%M%S)
echo $OUTDIR $REGION $JOBNAME
gsutil -m rm -rf $OUTDIR
gcloud ml-engine jobs submit training $JOBNAME \
    --region=$REGION \
    --module-name=flowersmodel.task \
    --package-path=${PWD}/flowersmodel \
    --job-dir=$OUTDIR \
    --staging-bucket=gs://$BUCKET \
    --scale-tier=BASIC_GPU \
    --runtime-version=$TFVERSION \
    -- \
    --output_dir=$OUTDIR \
    --train_steps=1000 \
    --learning_rate=0.01 \
    --batch_size=40 \
    --model=$MODEL_TYPE \
    --augment \
    --batch_norm \
    --train_data_path=gs://cloud-ml-data/img/flower_photos/train_set.csv \
    --eval_data_path=gs://cloud-ml-data/img/flower_photos/eval_set.csv

"""
Explanation: Now, let's do it on ML Engine. Note the --model parameter
End of explanation
"""


from google.datalab.ml import TensorBoard
TensorBoard().start("gs://{}/flowers/trained_{}".format(BUCKET, MODEL_TYPE))

for pid in TensorBoard.list()["pid"]:
    TensorBoard().stop(pid)
    print("Stopped TensorBoard with pid {}".format(pid))

"""
Explanation: Monitoring training with TensorBoard
Use this cell to launch tensorboard
End of explanation
"""


%%bash
MODEL_NAME="flowers"
MODEL_VERSION=${MODEL_TYPE}
MODEL_LOCATION=$(gsutil ls gs://${BUCKET}/flowers/trained_${MODEL_TYPE}/export/exporter | tail -1)
echo "Deleting and deploying $MODEL_NAME $MODEL_VERSION from $MODEL_LOCATION ... this will take a few minutes"
#gcloud ml-engine versions delete --quiet ${MODEL_VERSION} --model ${MODEL_NAME}
#gcloud ml-engine models delete ${MODEL_NAME}
gcloud ml-engine models create ${MODEL_NAME} --regions $REGION
gcloud ml-engine versions create ${MODEL_VERSION} --model ${MODEL_NAME} --origin ${MODEL_LOCATION} --runtime-version=$TFVERSION

"""
Explanation: Here are my results:
Model | Accuracy | Time taken | Run time parameters
--- | :---: | ---
cnn with batch-norm | 0.582 | 47 min | 1000 steps, LR=0.01, Batch=40
as above, plus augment | 0.615 | 3 hr | 5000 steps, LR=0.01, Batch=40
What was your accuracy?
Deploying and predicting with model
Deploy the model:
End of explanation
"""


%%bash
IMAGE_URL=gs://cloud-ml-data/img/flower_photos/sunflowers/1022552002_2b93faf9e7_n.jpg

# Copy the image to local disk.
gsutil cp $IMAGE_URL flower.jpg

# Base64 encode and create request message in json format.
python -c 'import base64, sys, json; img = base64.b64encode(open("flower.jpg", "rb").read()).decode(); print(json.dumps({"image_bytes":{"b64": img}}))' &> request.json

"""
Explanation: To predict with the model, let's take one of the example images that is available on Google Cloud Storage <img src="http://storage.googleapis.com/cloud-ml-data/img/flower_photos/sunflowers/1022552002_2b93faf9e7_n.jpg" />
The online prediction service expects images to be base64 encoded as described here.
End of explanation
"""


%%bash
gcloud ml-engine predict \
  --model=flowers \
  --version=${MODEL_TYPE} \
  --json-instances=./request.json

"""
Explanation: Send it to the prediction service
End of explanation
"""


