<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Neural network hybrid recommendation system on Google Analytics data model and training
This notebook demonstrates how to implement a hybrid recommendation system using a neural network to combine content-based and collaborative filtering recommendation models using Google Analytics data. We are going to use the learned user embeddings from wals.ipynb and combine that with our previous content-based features from content_based_using_neural_networks.ipynb
Now that we have our data preprocessed from BigQuery and Cloud Dataflow, we can build our neural network hybrid recommendation model to our preprocessed data. Then we can train locally to make sure everything works and then use the power of Google Cloud ML Engine to scale it out.
We're going to use TensorFlow Hub to use trained text embeddings, so let's first pip install that and reset our session.
Step1:  Now reset the notebook's session kernel! Since we're no longer using Cloud Dataflow, we'll be using the python3 kernel from here on out so don't forget to change the kernel if it's still python2.
Step2:  <h2> Create hybrid recommendation system model using TensorFlow </h2>
Now that we've created our training and evaluation input files as well as our categorical feature vocabulary files, we can create our TensorFlow hybrid recommendation system model.
Let's first get some of our aggregate information that we will use in the model from some of our preprocessed files we saved in Google Cloud Storage.
Step3:  Create input function for training and evaluation to read from our preprocessed CSV files.
Step4:  Next, we will create our feature columns using our read in features.
Step5:  Now we'll create our model function
Step6:  Now create a serving input function
Step7:  Now that all of the pieces are assembled let's create and run our train and evaluate loop
Step8:  Run train_and_evaluate!
Step9:  Run on module locally
Now let's place our code into a python module with model.py and task.py files so that we can train using Google Cloud's ML Engine! First, let's test our module locally.
Step10:  Run on Google Cloud AI Platform
If our module locally trained fine, let's now use of the power of AI Platform to scale it out on Google Cloud.
Step11:  Let's add some hyperparameter tuning!
Step12:  Now that we know the best hyperparameters, run a big training job!
<ASSISTANT_TASK:>
Python Code:
!pip3 install tensorflow_hub
%%bash
pip install --upgrade tensorflow
Explanation: Neural network hybrid recommendation system on Google Analytics data model and training
This notebook demonstrates how to implement a hybrid recommendation system using a neural network to combine content-based and collaborative filtering recommendation models using Google Analytics data. We are going to use the learned user embeddings from wals.ipynb and combine that with our previous content-based features from content_based_using_neural_networks.ipynb
Now that we have our data preprocessed from BigQuery and Cloud Dataflow, we can build our neural network hybrid recommendation model to our preprocessed data. Then we can train locally to make sure everything works and then use the power of Google Cloud ML Engine to scale it out.
We're going to use TensorFlow Hub to use trained text embeddings, so let's first pip install that and reset our session.
End of explanation
# Import helpful libraries and setup our project, bucket, and region
import os
import tensorflow as tf
import tensorflow_hub as hub
# 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
PROJECT = "qwiklabs-gcp-cbc8684b07fc2dbd" # REPLACE WITH YOUR PROJECT ID
BUCKET = "qwiklabs-gcp-cbc8684b07fc2dbd-bucket" # REPLACE WITH YOUR BUCKET NAME
REGION = "us-east1" # REPLACE WITH YOUR BUCKET REGION e.g. us-central1
# do not change these
os.environ["PROJECT"] = PROJECT
os.environ["BUCKET"] = BUCKET
os.environ["REGION"] = REGION
os.environ["TFVERSION"] = "1.13"
%%bash
gcloud config set project $PROJECT
gcloud config set compute/region $REGION
%%bash
if ! gsutil ls | grep -q gs://${BUCKET}/hybrid_recommendation/preproc; then
    gsutil mb -l ${REGION} gs://${BUCKET}
    # copy canonical set of preprocessed files if you didn't do preprocessing notebook
    gsutil -m cp -R gs://cloud-training-demos/courses/machine_learning/deepdive/10_recommendation/hybrid_recommendation gs://${BUCKET}
fi
Explanation: Now reset the notebook's session kernel! Since we're no longer using Cloud Dataflow, we'll be using the python3 kernel from here on out so don't forget to change the kernel if it's still python2.
End of explanation
from tensorflow.python.lib.io import file_io
# Get number of content ids from text file in Google Cloud Storage
with file_io.FileIO(tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocab_counts/content_id_vocab_count.txt*".format(BUCKET))[0], mode = 'r') as ifp:
    number_of_content_ids = int([x for x in ifp][0])
print("number_of_content_ids = {}".format(number_of_content_ids))
# Get number of categories from text file in Google Cloud Storage
with file_io.FileIO(tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocab_counts/category_vocab_count.txt*".format(BUCKET))[0], mode = 'r') as ifp:
    number_of_categories = int([x for x in ifp][0])
print("number_of_categories = {}".format(number_of_categories))
# Get number of authors from text file in Google Cloud Storage
with file_io.FileIO(tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocab_counts/author_vocab_count.txt*".format(BUCKET))[0], mode = 'r') as ifp:
    number_of_authors = int([x for x in ifp][0])
print("number_of_authors = {}".format(number_of_authors))
# Get mean months since epoch from text file in Google Cloud Storage
with file_io.FileIO(tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocab_counts/months_since_epoch_mean.txt*".format(BUCKET))[0], mode = 'r') as ifp:
    mean_months_since_epoch = float([x for x in ifp][0])
print("mean_months_since_epoch = {}".format(mean_months_since_epoch))
# Determine CSV and label columns
NON_FACTOR_COLUMNS = "next_content_id,visitor_id,content_id,category,title,author,months_since_epoch".split(',')
FACTOR_COLUMNS = ["user_factor_{}".format(i) for i in range(10)] + ["item_factor_{}".format(i) for i in range(10)]
CSV_COLUMNS = NON_FACTOR_COLUMNS + FACTOR_COLUMNS
LABEL_COLUMN = "next_content_id"
# Set default values for each CSV column
NON_FACTOR_DEFAULTS = [["Unknown"],["Unknown"],["Unknown"],["Unknown"],["Unknown"],["Unknown"],[mean_months_since_epoch]]
FACTOR_DEFAULTS = [[0.0] for i in range(10)] + [[0.0] for i in range(10)] # user and item
DEFAULTS = NON_FACTOR_DEFAULTS + FACTOR_DEFAULTS
Explanation: <h2> Create hybrid recommendation system model using TensorFlow </h2>
Now that we've created our training and evaluation input files as well as our categorical feature vocabulary files, we can create our TensorFlow hybrid recommendation system model.
Let's first get some of our aggregate information that we will use in the model from some of our preprocessed files we saved in Google Cloud Storage.
End of explanation
# Create input function for train and eval
def read_dataset(filename, mode, batch_size = 512):
    def _input_fn():
        def decode_csv(value_column):
            columns = tf.decode_csv(records = value_column, record_defaults = DEFAULTS)
            features = dict(zip(CSV_COLUMNS, columns))          
            label = features.pop(LABEL_COLUMN)         
            return features, label
        # Create list of files that match pattern
        file_list = tf.gfile.Glob(filename = filename)
        # Create dataset from file list
        dataset = tf.data.TextLineDataset(filenames = file_list).map(map_func = decode_csv)
        if mode == tf.estimator.ModeKeys.TRAIN:
            num_epochs = None # indefinitely
            dataset = dataset.shuffle(buffer_size = 10 * batch_size)
        else:
            num_epochs = 1 # end-of-input after this
        dataset = dataset.repeat(count = num_epochs).batch(batch_size = batch_size)
        return dataset.make_one_shot_iterator().get_next()
    return _input_fn
Explanation: Create input function for training and evaluation to read from our preprocessed CSV files.
End of explanation
# Create feature columns to be used in model
def create_feature_columns(args):
    # Create content_id feature column
    content_id_column = tf.feature_column.categorical_column_with_hash_bucket(
        key = "content_id",
        hash_bucket_size = number_of_content_ids)
    # Embed content id into a lower dimensional representation
    embedded_content_column = tf.feature_column.embedding_column(
        categorical_column = content_id_column,
        dimension = args["content_id_embedding_dimensions"])
    # Create category feature column
    categorical_category_column = tf.feature_column.categorical_column_with_vocabulary_file(
        key = "category",
        vocabulary_file = tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocabs/category_vocab.txt*".format(args["bucket"]))[0],
        num_oov_buckets = 1)
    # Convert categorical category column into indicator column so that it can be used in a DNN
    indicator_category_column = tf.feature_column.indicator_column(categorical_column = categorical_category_column)
    # Create title feature column using TF Hub
    embedded_title_column = hub.text_embedding_column(
        key = "title", 
        module_spec = "https://tfhub.dev/google/nnlm-de-dim50-with-normalization/1",
        trainable = False)
    # Create author feature column
    author_column = tf.feature_column.categorical_column_with_hash_bucket(
        key = "author",
        hash_bucket_size = number_of_authors + 1)
    # Embed author into a lower dimensional representation
    embedded_author_column = tf.feature_column.embedding_column(
        categorical_column = author_column,
        dimension = args["author_embedding_dimensions"])
    # Create months since epoch boundaries list for our binning
    months_since_epoch_boundaries = list(range(400, 700, 20))
    # Create months_since_epoch feature column using raw data
    months_since_epoch_column = tf.feature_column.numeric_column(
        key = "months_since_epoch")
    # Create bucketized months_since_epoch feature column using our boundaries
    months_since_epoch_bucketized = tf.feature_column.bucketized_column(
        source_column = months_since_epoch_column,
        boundaries = months_since_epoch_boundaries)
    # Cross our categorical category column and bucketized months since epoch column
    crossed_months_since_category_column = tf.feature_column.crossed_column(
        keys = [categorical_category_column, months_since_epoch_bucketized],
        hash_bucket_size = len(months_since_epoch_boundaries) * (number_of_categories + 1))
    # Convert crossed categorical category and bucketized months since epoch column into indicator column so that it can be used in a DNN
    indicator_crossed_months_since_category_column = tf.feature_column.indicator_column(
            categorical_column = crossed_months_since_category_column)
    # Create user and item factor feature columns from our trained WALS model
    user_factors = [tf.feature_column.numeric_column(key = "user_factor_" + str(i)) for i in range(10)]
    item_factors =  [tf.feature_column.numeric_column(key = "item_factor_" + str(i)) for i in range(10)]
    # Create list of feature columns
    feature_columns = [embedded_content_column,
    embedded_author_column,
    indicator_category_column,
    embedded_title_column,
    indicator_crossed_months_since_category_column] + user_factors + item_factors
    return feature_columns
Explanation: Next, we will create our feature columns using our read in features.
End of explanation
# Create custom model function for our custom estimator
def model_fn(features, labels, mode, params):
    # Create neural network input layer using our feature columns defined above
    net = tf.feature_column.input_layer(features = features, feature_columns = params["feature_columns"])
    # Create hidden layers by looping through hidden unit list
    for units in params["hidden_units"]:
        net = tf.layers.dense(inputs = net, units = units, activation = tf.nn.relu)
    # Compute logits (1 per class) using the output of our last hidden layer
    logits = tf.layers.dense(inputs = net, units = params["n_classes"], activation = None)
    # Find the predicted class indices based on the highest logit (which will result in the highest probability)
    predicted_classes = tf.argmax(input = logits, axis = 1)
  # Read in the content id vocabulary so we can tie the predicted class indices to their respective content ids
    with file_io.FileIO(tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocabs/content_id_vocab.txt*".format(BUCKET))[0], mode = "r") as ifp:
        content_id_names = tf.constant(value = [x.rstrip() for x in ifp])
    # Gather predicted class names based predicted class indices
    predicted_class_names = tf.gather(params = content_id_names, indices = predicted_classes)
    # If the mode is prediction
    if mode == tf.estimator.ModeKeys.PREDICT:
        # Create predictions dict
        predictions_dict = {
            "class_ids": tf.expand_dims(input = predicted_classes, axis = -1),
            "class_names" : tf.expand_dims(input = predicted_class_names, axis = -1),
            "probabilities": tf.nn.softmax(logits = logits),
            "logits": logits
        }
        # Create export outputs
        export_outputs = {"predict_export_outputs": tf.estimator.export.PredictOutput(outputs = predictions_dict)}
        return tf.estimator.EstimatorSpec( # return early since we"re done with what we need for prediction mode
          mode = mode,
          predictions = predictions_dict,
          loss = None,
          train_op = None,
          eval_metric_ops = None,
          export_outputs = export_outputs)
    # Continue on with training and evaluation modes
    # Create lookup table using our content id vocabulary
    table = tf.contrib.lookup.index_table_from_file(
        vocabulary_file = tf.gfile.Glob(filename = "gs://{}/hybrid_recommendation/preproc/vocabs/content_id_vocab.txt*".format(BUCKET))[0])
    # Look up labels from vocabulary table
    labels = table.lookup(keys = labels)
    # Compute loss using sparse softmax cross entropy since this is classification and our labels (content id indices) and probabilities are mutually exclusive
    loss = tf.losses.sparse_softmax_cross_entropy(labels = labels, logits = logits)
    # If the mode is evaluation
    if mode == tf.estimator.ModeKeys.EVAL:
        # Compute evaluation metrics of total accuracy and the accuracy of the top k classes
        accuracy = tf.metrics.accuracy(labels = labels, predictions = predicted_classes, name = "acc_op")
        top_k_accuracy = tf.metrics.mean(values = tf.nn.in_top_k(predictions = logits, targets = labels, k = params["top_k"]))
        map_at_k = tf.metrics.average_precision_at_k(labels = labels, predictions = predicted_classes, k = params["top_k"])
        # Put eval metrics into a dictionary
        eval_metric_ops = {
            "accuracy": accuracy,
            "top_k_accuracy": top_k_accuracy,
            "map_at_k": map_at_k}
        # Create scalar summaries to see in TensorBoard
        tf.summary.scalar(name = "accuracy", tensor = accuracy[1])
        tf.summary.scalar(name = "top_k_accuracy", tensor = top_k_accuracy[1])
        tf.summary.scalar(name = "map_at_k", tensor = map_at_k[1])
        
        return tf.estimator.EstimatorSpec( # return early since we"re done with what we need for evaluation mode
            mode = mode,
            predictions = None,
            loss = loss,
            train_op = None,
            eval_metric_ops = eval_metric_ops,
            export_outputs = None)
    # Continue on with training mode
    # If the mode is training
    assert mode == tf.estimator.ModeKeys.TRAIN
    # Create a custom optimizer
    optimizer = tf.train.AdagradOptimizer(learning_rate = params["learning_rate"])
    # Create train op
    train_op = optimizer.minimize(loss = loss, global_step = tf.train.get_global_step())
    return tf.estimator.EstimatorSpec( # final return since we"re done with what we need for training mode
        mode = mode,
        predictions = None,
        loss = loss,
        train_op = train_op,
        eval_metric_ops = None,
        export_outputs = None)
Explanation: Now we'll create our model function
End of explanation
# Create serving input function
def serving_input_fn():  
    feature_placeholders = {
        colname : tf.placeholder(dtype = tf.string, shape = [None]) \
        for colname in NON_FACTOR_COLUMNS[1:-1]
    }
    feature_placeholders["months_since_epoch"] = tf.placeholder(dtype = tf.float32, shape = [None])
    for colname in FACTOR_COLUMNS:
        feature_placeholders[colname] = tf.placeholder(dtype = tf.float32, shape = [None])
    features = {
        key: tf.expand_dims(tensor, -1) \
        for key, tensor in feature_placeholders.items()
    }
    return tf.estimator.export.ServingInputReceiver(features = features, receiver_tensors = feature_placeholders)
Explanation: Now create a serving input function
End of explanation
# Create train and evaluate loop to combine all of the pieces together.
tf.logging.set_verbosity(tf.logging.INFO)
def train_and_evaluate(args):
    estimator = tf.estimator.Estimator(
        model_fn = model_fn,
        model_dir = args["output_dir"],
        params = {
        "feature_columns": create_feature_columns(args),
        "hidden_units": args["hidden_units"],
        "n_classes": number_of_content_ids,
        "learning_rate": args["learning_rate"],
        "top_k": args["top_k"],
        "bucket": args["bucket"]
        }
    )
    train_spec = tf.estimator.TrainSpec(
        input_fn = read_dataset(filename = args["train_data_paths"], mode = tf.estimator.ModeKeys.TRAIN, batch_size = args["batch_size"]),
        max_steps = args["train_steps"])
    exporter = tf.estimator.LatestExporter(name = "exporter", serving_input_receiver_fn = serving_input_fn)
    eval_spec = tf.estimator.EvalSpec(
        input_fn = read_dataset(filename = args["eval_data_paths"], mode = tf.estimator.ModeKeys.EVAL, batch_size = args["batch_size"]),
        steps = None,
        start_delay_secs = args["start_delay_secs"],
        throttle_secs = args["throttle_secs"],
        exporters = exporter)
    tf.estimator.train_and_evaluate(estimator = estimator, train_spec = train_spec, eval_spec = eval_spec)
Explanation: Now that all of the pieces are assembled let's create and run our train and evaluate loop
End of explanation
# Call train and evaluate loop
import shutil
outdir = "hybrid_recommendation_trained"
shutil.rmtree(path = outdir, ignore_errors = True) # start fresh each time
arguments = {
    "bucket": BUCKET,
    "train_data_paths": "gs://{}/hybrid_recommendation/preproc/features/train.csv*".format(BUCKET),
    "eval_data_paths": "gs://{}/hybrid_recommendation/preproc/features/eval.csv*".format(BUCKET),
    "output_dir": outdir,
    "batch_size": 128,
    "learning_rate": 0.1,
    "hidden_units": [256, 128, 64],
    "content_id_embedding_dimensions": 10,
    "author_embedding_dimensions": 10,
    "top_k": 10,
    "train_steps": 1000,
    "start_delay_secs": 30,
    "throttle_secs": 30
}
train_and_evaluate(arguments)
Explanation: Run train_and_evaluate!
End of explanation
%%writefile requirements.txt
tensorflow_hub
%%bash
echo "bucket=${BUCKET}"
rm -rf hybrid_recommendation_trained
export PYTHONPATH=${PYTHONPATH}:${PWD}/hybrid_recommendations_module
python -m trainer.task \
    --bucket=${BUCKET} \
    --train_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/train.csv* \
    --eval_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/eval.csv* \
    --output_dir=${OUTDIR} \
    --batch_size=128 \
    --learning_rate=0.1 \
    --hidden_units="256 128 64" \
    --content_id_embedding_dimensions=10 \
    --author_embedding_dimensions=10 \
    --top_k=10 \
    --train_steps=1000 \
    --start_delay_secs=30 \
    --throttle_secs=60
Explanation: Run on module locally
Now let's place our code into a python module with model.py and task.py files so that we can train using Google Cloud's ML Engine! First, let's test our module locally.
End of explanation
%%bash
OUTDIR=gs://${BUCKET}/hybrid_recommendation/small_trained_model
JOBNAME=hybrid_recommendation_$(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=trainer.task \
    --package-path=$(pwd)/hybrid_recommendations_module/trainer \
    --job-dir=$OUTDIR \
    --staging-bucket=gs://$BUCKET \
    --scale-tier=STANDARD_1 \
    --runtime-version=$TFVERSION \
    -- \
    --bucket=${BUCKET} \
    --train_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/train.csv* \
    --eval_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/eval.csv* \
    --output_dir=${OUTDIR} \
    --batch_size=128 \
    --learning_rate=0.1 \
    --hidden_units="256 128 64" \
    --content_id_embedding_dimensions=10 \
    --author_embedding_dimensions=10 \
    --top_k=10 \
    --train_steps=1000 \
    --start_delay_secs=30 \
    --throttle_secs=30
Explanation: Run on Google Cloud AI Platform
If our module locally trained fine, let's now use of the power of AI Platform to scale it out on Google Cloud.
End of explanation
%%writefile hyperparam.yaml
trainingInput:
    hyperparameters:
        goal: MAXIMIZE
        maxTrials: 5
        maxParallelTrials: 1
        hyperparameterMetricTag: accuracy
        params:
            - parameterName: batch_size
              type: INTEGER
              minValue: 8
              maxValue: 64
              scaleType: UNIT_LINEAR_SCALE
            - parameterName: learning_rate
              type: DOUBLE
              minValue: 0.01
              maxValue: 0.1
              scaleType: UNIT_LINEAR_SCALE
            - parameterName: hidden_units
              type: CATEGORICAL
              categoricalValues: ["1024 512 256", "1024 512 128", "1024 256 128", "512 256 128", "1024 512 64", "1024 256 64", "512 256 64", "1024 128 64", "512 128 64", "256 128 64", "1024 512 32", "1024 256 32", "512 256 32", "1024 128 32", "512 128 32", "256 128 32", "1024 64 32", "512 64 32", "256 64 32", "128 64 32"]
            - parameterName: content_id_embedding_dimensions
              type: INTEGER
              minValue: 5
              maxValue: 250
              scaleType: UNIT_LOG_SCALE
            - parameterName: author_embedding_dimensions
              type: INTEGER
              minValue: 5
              maxValue: 30
              scaleType: UNIT_LINEAR_SCALE
%%bash
OUTDIR=gs://${BUCKET}/hybrid_recommendation/hypertuning
JOBNAME=hybrid_recommendation_$(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=trainer.task \
    --package-path=$(pwd)/hybrid_recommendations_module/trainer \
    --job-dir=$OUTDIR \
    --staging-bucket=gs://$BUCKET \
    --scale-tier=STANDARD_1 \
    --runtime-version=$TFVERSION \
    --config=hyperparam.yaml \
    -- \
    --bucket=${BUCKET} \
    --train_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/train.csv* \
    --eval_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/eval.csv* \
    --output_dir=${OUTDIR} \
    --batch_size=128 \
    --learning_rate=0.1 \
    --hidden_units="256 128 64" \
    --content_id_embedding_dimensions=10 \
    --author_embedding_dimensions=10 \
    --top_k=10 \
    --train_steps=1000 \
    --start_delay_secs=30 \
    --throttle_secs=30
Explanation: Let's add some hyperparameter tuning!
End of explanation
%%bash
OUTDIR=gs://${BUCKET}/hybrid_recommendation/big_trained_model
JOBNAME=hybrid_recommendation_$(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=trainer.task \
    --package-path=$(pwd)/hybrid_recommendations_module/trainer \
    --job-dir=$OUTDIR \
    --staging-bucket=gs://$BUCKET \
    --scale-tier=STANDARD_1 \
    --runtime-version=$TFVERSION \
    -- \
    --bucket=${BUCKET} \
    --train_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/train.csv* \
    --eval_data_paths=gs://${BUCKET}/hybrid_recommendation/preproc/features/eval.csv* \
    --output_dir=${OUTDIR} \
    --batch_size=128 \
    --learning_rate=0.1 \
    --hidden_units="256 128 64" \
    --content_id_embedding_dimensions=10 \
    --author_embedding_dimensions=10 \
    --top_k=10 \
    --train_steps=10000 \
    --start_delay_secs=30 \
    --throttle_secs=30
Explanation: Now that we know the best hyperparameters, run a big training job!
End of explanation
<END_TASK>