|
398 | 398 | "if not IS_GOOGLE_CLOUD_NOTEBOOK:\n", |
399 | 399 | " if \"google.colab\" in sys.modules:\n", |
400 | 400 | " from google.colab import auth as google_auth\n", |
| 401 | + "\n", |
401 | 402 | " google_auth.authenticate_user()\n", |
402 | 403 | "\n", |
403 | 404 | " # If you are running this notebook locally, replace the string below with the\n", |
|
472 | 473 | }, |
473 | 474 | "outputs": [], |
474 | 475 | "source": [ |
475 | | - "! gsutil mb -l $REGION $BUCKET_NAME" |
| 476 | + "! gcloud storage buckets create --location $REGION $BUCKET_NAME" |
476 | 477 | ] |
477 | 478 | }, |
478 | 479 | { |
|
492 | 493 | }, |
493 | 494 | "outputs": [], |
494 | 495 | "source": [ |
495 | | - "! gsutil ls -al $BUCKET_NAME" |
| 496 | + "! gcloud storage ls --all-versions --long $BUCKET_NAME" |
496 | 497 | ] |
497 | 498 | }, |
498 | 499 | { |
|
565 | 566 | "outputs": [], |
566 | 567 | "source": [ |
567 | 568 | "# Copy the sample data into your DATA_PATH\n", |
568 | | - "! gsutil cp \"gs://cloud-samples-data/vertex-ai/community-content/tf_agents_bandits_movie_recommendation_with_kfp_and_vertex_sdk/u.data\" $DATA_PATH" |
| 569 | + "! gcloud storage cp \"gs://cloud-samples-data/vertex-ai/community-content/tf_agents_bandits_movie_recommendation_with_kfp_and_vertex_sdk/u.data\" $DATA_PATH" |
569 | 570 | ] |
570 | 571 | }, |
571 | 572 | { |
|
579 | 580 | "# Set hyperparameters.\n", |
580 | 581 | "BATCH_SIZE = 8 # @param {type:\"integer\"} Training and prediction batch size.\n", |
581 | 582 | "TRAINING_LOOPS = 5 # @param {type:\"integer\"} Number of training iterations.\n", |
582 | | - "STEPS_PER_LOOP = 2 # @param {type:\"integer\"} Number of driver steps per training iteration.\n", |
| 583 | + "STEPS_PER_LOOP = (\n", |
| 584 | + " 2 # @param {type:\"integer\"} Number of driver steps per training iteration.\n", |
| 585 | + ")\n", |
583 | 586 | "\n", |
584 | 587 | "# Set MovieLens simulation environment parameters.\n", |
585 | 588 | "RANK_K = 20 # @param {type:\"integer\"} Rank for matrix factorization in the MovieLens environment; also the observation dimension.\n", |
586 | | - "NUM_ACTIONS = 20 # @param {type:\"integer\"} Number of actions (movie items) to choose from.\n", |
| 589 | + "NUM_ACTIONS = (\n", |
| 590 | + " 20 # @param {type:\"integer\"} Number of actions (movie items) to choose from.\n", |
| 591 | + ")\n", |
587 | 592 | "PER_ARM = False # Use the non-per-arm version of the MovieLens environment.\n", |
588 | 593 | "\n", |
589 | 594 | "# Set agent parameters.\n", |
|
621 | 626 | "source": [ |
622 | 627 | "# Define RL environment.\n", |
623 | 628 | "env = movielens_py_environment.MovieLensPyEnvironment(\n", |
624 | | - " DATA_PATH, RANK_K, BATCH_SIZE, num_movies=NUM_ACTIONS, csv_delimiter=\"\\t\")\n", |
| 629 | + " DATA_PATH, RANK_K, BATCH_SIZE, num_movies=NUM_ACTIONS, csv_delimiter=\"\\t\"\n", |
| 630 | + ")\n", |
625 | 631 | "environment = tf_py_environment.TFPyEnvironment(env)\n", |
626 | 632 | "\n", |
627 | 633 | "# Define RL agent/algorithm.\n", |
|
631 | 637 | " tikhonov_weight=TIKHONOV_WEIGHT,\n", |
632 | 638 | " alpha=AGENT_ALPHA,\n", |
633 | 639 | " dtype=tf.float32,\n", |
634 | | - " accepts_per_arm_features=PER_ARM)\n", |
| 640 | + " accepts_per_arm_features=PER_ARM,\n", |
| 641 | + ")\n", |
635 | 642 | "print(\"TimeStep Spec (for each batch):\\n\", agent.time_step_spec, \"\\n\")\n", |
636 | 643 | "print(\"Action Spec (for each batch):\\n\", agent.action_spec, \"\\n\")\n", |
637 | 644 | "print(\"Reward Spec (for each batch):\\n\", environment.reward_spec(), \"\\n\")\n", |
638 | 645 | "\n", |
639 | 646 | "# Define RL metric.\n", |
640 | 647 | "optimal_reward_fn = functools.partial(\n", |
641 | 648 | " environment_utilities.compute_optimal_reward_with_movielens_environment,\n", |
642 | | - " environment=environment)\n", |
| 649 | + " environment=environment,\n", |
| 650 | + ")\n", |
643 | 651 | "regret_metric = tf_bandit_metrics.RegretMetric(optimal_reward_fn)\n", |
644 | 652 | "metrics = [regret_metric]" |
645 | 653 | ] |
|
704 | 712 | " if training_data_spec_transformation_fn is None:\n", |
705 | 713 | " data_spec = agent.policy.trajectory_spec\n", |
706 | 714 | " else:\n", |
707 | | - " data_spec = training_data_spec_transformation_fn(\n", |
708 | | - " agent.policy.trajectory_spec)\n", |
709 | | - " replay_buffer = trainer.get_replay_buffer(data_spec, environment.batch_size,\n", |
710 | | - " steps_per_loop)\n", |
| 715 | + " data_spec = training_data_spec_transformation_fn(agent.policy.trajectory_spec)\n", |
| 716 | + " replay_buffer = trainer.get_replay_buffer(\n", |
| 717 | + " data_spec, environment.batch_size, steps_per_loop\n", |
| 718 | + " )\n", |
711 | 719 | "\n", |
712 | 720 | " # `step_metric` records the number of individual rounds of bandit interaction;\n", |
713 | 721 | " # that is, (number of trajectories) * batch_size.\n", |
714 | 722 | " step_metric = tf_metrics.EnvironmentSteps()\n", |
715 | 723 | " metrics = [\n", |
716 | 724 | " tf_metrics.NumberOfEpisodes(),\n", |
717 | | - " tf_metrics.AverageEpisodeLengthMetric(batch_size=environment.batch_size)\n", |
| 725 | + " tf_metrics.AverageEpisodeLengthMetric(batch_size=environment.batch_size),\n", |
718 | 726 | " ]\n", |
719 | 727 | " if additional_metrics:\n", |
720 | 728 | " metrics += additional_metrics\n", |
721 | 729 | "\n", |
722 | 730 | " if isinstance(environment.reward_spec(), dict):\n", |
723 | | - " metrics += [tf_metrics.AverageReturnMultiMetric(\n", |
724 | | - " reward_spec=environment.reward_spec(),\n", |
725 | | - " batch_size=environment.batch_size)]\n", |
726 | | - " else:\n", |
727 | 731 | " metrics += [\n", |
728 | | - " tf_metrics.AverageReturnMetric(batch_size=environment.batch_size)]\n", |
| 732 | + " tf_metrics.AverageReturnMultiMetric(\n", |
| 733 | + " reward_spec=environment.reward_spec(), batch_size=environment.batch_size\n", |
| 734 | + " )\n", |
| 735 | + " ]\n", |
| 736 | + " else:\n", |
| 737 | + " metrics += [tf_metrics.AverageReturnMetric(batch_size=environment.batch_size)]\n", |
729 | 738 | "\n", |
730 | 739 | " # Store intermediate metric results, indexed by metric names.\n", |
731 | 740 | " metric_results = defaultdict(list)\n", |
732 | 741 | "\n", |
733 | 742 | " if training_data_spec_transformation_fn is not None:\n", |
734 | | - " def add_batch_fn(data): return replay_buffer.add_batch(training_data_spec_transformation_fn(data)) \n", |
735 | | - " \n", |
| 743 | + "\n", |
| 744 | + " def add_batch_fn(data):\n", |
| 745 | + " return replay_buffer.add_batch(training_data_spec_transformation_fn(data))\n", |
| 746 | + "\n", |
736 | 747 | " else:\n", |
737 | 748 | " add_batch_fn = replay_buffer.add_batch\n", |
738 | 749 | "\n", |
|
742 | 753 | " env=environment,\n", |
743 | 754 | " policy=agent.collect_policy,\n", |
744 | 755 | " num_steps=steps_per_loop * environment.batch_size,\n", |
745 | | - " observers=observers)\n", |
| 756 | + " observers=observers,\n", |
| 757 | + " )\n", |
746 | 758 | "\n", |
747 | 759 | " training_loop = trainer.get_training_loop_fn(\n", |
748 | | - " driver, replay_buffer, agent, steps_per_loop)\n", |
| 760 | + " driver, replay_buffer, agent, steps_per_loop\n", |
| 761 | + " )\n", |
749 | 762 | " saver = policy_saver.PolicySaver(agent.policy)\n", |
750 | 763 | "\n", |
751 | 764 | " for _ in range(training_loops):\n", |
|
783 | 796 | " environment=environment,\n", |
784 | 797 | " training_loops=TRAINING_LOOPS,\n", |
785 | 798 | " steps_per_loop=STEPS_PER_LOOP,\n", |
786 | | - " additional_metrics=metrics)\n", |
| 799 | + " additional_metrics=metrics,\n", |
| 800 | + ")\n", |
787 | 801 | "\n", |
788 | 802 | "tf.profiler.experimental.stop()" |
789 | 803 | ] |
|
1092 | 1106 | }, |
1093 | 1107 | "outputs": [], |
1094 | 1108 | "source": [ |
1095 | | - "RUN_HYPERPARAMETER_TUNING = True # Execute hyperparameter tuning instead of regular training.\n", |
| 1109 | + "RUN_HYPERPARAMETER_TUNING = (\n", |
| 1110 | + " True # Execute hyperparameter tuning instead of regular training.\n", |
| 1111 | + ")\n", |
1096 | 1112 | "TRAIN_WITH_BEST_HYPERPARAMETERS = False # Do not train.\n", |
1097 | 1113 | "\n", |
1098 | 1114 | "HPTUNING_RESULT_DIR = \"hptuning/\" # @param {type: \"string\"} Directory to store the best hyperparameter(s) in `BUCKET_NAME` and locally (temporarily).\n", |
1099 | | - "HPTUNING_RESULT_PATH = os.path.join(HPTUNING_RESULT_DIR, \"result.json\") # @param {type: \"string\"} Path to the file containing the best hyperparameter(s)." |
| 1115 | + "HPTUNING_RESULT_PATH = os.path.join(\n", |
| 1116 | + " HPTUNING_RESULT_DIR, \"result.json\"\n", |
| 1117 | + ") # @param {type: \"string\"} Path to the file containing the best hyperparameter(s)." |
1100 | 1118 | ] |
1101 | 1119 | }, |
1102 | 1120 | { |
|
1124 | 1142 | " image_uri: str,\n", |
1125 | 1143 | " args: List[str],\n", |
1126 | 1144 | " location: str = \"us-central1\",\n", |
1127 | | - " api_endpoint: str = \"us-central1-aiplatform.googleapis.com\"\n", |
| 1145 | + " api_endpoint: str = \"us-central1-aiplatform.googleapis.com\",\n", |
1128 | 1146 | ") -> None:\n", |
1129 | 1147 | " \"\"\"Creates a hyperparameter tuning job using a custom container.\n", |
1130 | 1148 | "\n", |
|
1197 | 1215 | "\n", |
1198 | 1216 | " # Create job\n", |
1199 | 1217 | " response = client.create_hyperparameter_tuning_job(\n", |
1200 | | - " parent=parent,\n", |
1201 | | - " hyperparameter_tuning_job=hyperparameter_tuning_job)\n", |
| 1218 | + " parent=parent, hyperparameter_tuning_job=hyperparameter_tuning_job\n", |
| 1219 | + " )\n", |
1202 | 1220 | " job_id = response.name.split(\"/\")[-1]\n", |
1203 | 1221 | " print(\"Job ID:\", job_id)\n", |
1204 | 1222 | " print(\"Job config:\", response)\n", |
|
1242 | 1260 | " image_uri=f\"gcr.io/{PROJECT_ID}/{HPTUNING_TRAINING_CONTAINER}:latest\",\n", |
1243 | 1261 | " args=args,\n", |
1244 | 1262 | " location=REGION,\n", |
1245 | | - " api_endpoint=f\"{REGION}-aiplatform.googleapis.com\")" |
| 1263 | + " api_endpoint=f\"{REGION}-aiplatform.googleapis.com\",\n", |
| 1264 | + ")" |
1246 | 1265 | ] |
1247 | 1266 | }, |
1248 | 1267 | { |
|
1292 | 1311 | " name = client.hyperparameter_tuning_job_path(\n", |
1293 | 1312 | " project=project,\n", |
1294 | 1313 | " location=location,\n", |
1295 | | - " hyperparameter_tuning_job=hyperparameter_tuning_job_id)\n", |
| 1314 | + " hyperparameter_tuning_job=hyperparameter_tuning_job_id,\n", |
| 1315 | + " )\n", |
1296 | 1316 | " response = client.get_hyperparameter_tuning_job(name=name)\n", |
1297 | 1317 | " return response" |
1298 | 1318 | ] |
|
1313 | 1333 | " location=REGION,\n", |
1314 | 1334 | " api_endpoint=f\"{REGION}-aiplatform.googleapis.com\")\n", |
1315 | 1335 | " if response.state.name == 'JOB_STATE_SUCCEEDED':\n", |
1316 | | - " print(\"Job succeeded.\\nJob Time:\", response.update_time - response.create_time)\n", |
| 1336 | + " print(\"Job succeeded.\n", |
| 1337 | + "Job Time:\", response.update_time - response.create_time)\n", |
1317 | 1338 | " trials = response.trials\n", |
1318 | 1339 | " print(\"Trials:\", trials)\n", |
1319 | 1340 | " break\n", |
|
1348 | 1369 | "if trials:\n", |
1349 | 1370 | " # Dict mapping from metric names to the best metric values seen so far\n", |
1350 | 1371 | " best_objective_values = dict.fromkeys(\n", |
1351 | | - " [metric.metric_id for metric in trials[0].final_measurement.metrics],\n", |
1352 | | - " -np.inf)\n", |
| 1372 | + " [metric.metric_id for metric in trials[0].final_measurement.metrics], -np.inf\n", |
| 1373 | + " )\n", |
1353 | 1374 | " # Dict mapping from metric names to a list of the best combination(s) of\n", |
1354 | 1375 | " # hyperparameter(s). Each combination is a dict mapping from hyperparameter\n", |
1355 | 1376 | " # names to their values.\n", |
|
1358 | 1379 | " # `final_measurement` and `parameters` are `RepeatedComposite` objects.\n", |
1359 | 1380 | " # Reference the structure above to extract the value of your interest.\n", |
1360 | 1381 | " for metric in trial.final_measurement.metrics:\n", |
1361 | | - " params = {\n", |
1362 | | - " param.parameter_id: param.value for param in trial.parameters}\n", |
| 1382 | + " params = {param.parameter_id: param.value for param in trial.parameters}\n", |
1363 | 1383 | " if metric.value > best_objective_values[metric.metric_id]:\n", |
1364 | 1384 | " best_params[metric.metric_id] = [params]\n", |
1365 | 1385 | " elif metric.value == best_objective_values[metric.metric_id]:\n", |
1366 | | - " best_params[param.parameter_id].append(params) # Handle cases where multiple hyperparameter values lead to the same performance.\n", |
| 1386 | + " best_params[param.parameter_id].append(\n", |
| 1387 | + " params\n", |
| 1388 | + " ) # Handle cases where multiple hyperparameter values lead to the same performance.\n", |
1367 | 1389 | " print(\"Best hyperparameter value(s):\")\n", |
1368 | 1390 | " for metric, params in best_params.items():\n", |
1369 | 1391 | " print(f\"Metric={metric}: {sorted(params)}\")\n", |
|
1443 | 1465 | }, |
1444 | 1466 | "outputs": [], |
1445 | 1467 | "source": [ |
1446 | | - "PREDICTION_CONTAINER = \"prediction-custom-container\" # @param {type:\"string\"} Name of the container image." |
| 1468 | + "PREDICTION_CONTAINER = (\n", |
| 1469 | + " \"prediction-custom-container\" # @param {type:\"string\"} Name of the container image.\n", |
| 1470 | + ")" |
1447 | 1471 | ] |
1448 | 1472 | }, |
1449 | 1473 | { |
|
1475 | 1499 | " machineType: 'E2_HIGHCPU_8'\"\"\".format(\n", |
1476 | 1500 | " PROJECT_ID=PROJECT_ID,\n", |
1477 | 1501 | " PREDICTION_CONTAINER=PREDICTION_CONTAINER,\n", |
1478 | | - " ARTIFACTS_DIR=ARTIFACTS_DIR\n", |
| 1502 | + " ARTIFACTS_DIR=ARTIFACTS_DIR,\n", |
1479 | 1503 | ")\n", |
1480 | 1504 | "\n", |
1481 | 1505 | "with open(\"cloudbuild.yaml\", \"w\") as fp:\n", |
|
1592 | 1616 | }, |
1593 | 1617 | "outputs": [], |
1594 | 1618 | "source": [ |
1595 | | - "RUN_HYPERPARAMETER_TUNING = False # Execute regular training instead of hyperparameter tuning.\n", |
1596 | | - "TRAIN_WITH_BEST_HYPERPARAMETERS = True # @param {type:\"bool\"} Whether to use learned hyperparameters in training." |
| 1619 | + "RUN_HYPERPARAMETER_TUNING = (\n", |
| 1620 | + " False # Execute regular training instead of hyperparameter tuning.\n", |
| 1621 | + ")\n", |
| 1622 | + "TRAIN_WITH_BEST_HYPERPARAMETERS = (\n", |
| 1623 | + " True # @param {type:\"bool\"} Whether to use learned hyperparameters in training.\n", |
| 1624 | + ")" |
1597 | 1625 | ] |
1598 | 1626 | }, |
1599 | 1627 | { |
|
1633 | 1661 | "job = aiplatform.CustomContainerTrainingJob(\n", |
1634 | 1662 | " display_name=\"train-movielens\",\n", |
1635 | 1663 | " container_uri=f\"gcr.io/{PROJECT_ID}/{HPTUNING_TRAINING_CONTAINER}:latest\",\n", |
1636 | | - " command=[\"python3\", \"-m\", \"src.training.task\"] + args, # Pass in training arguments, including hyperparameters.\n", |
| 1664 | + " command=[\"python3\", \"-m\", \"src.training.task\"]\n", |
| 1665 | + " + args, # Pass in training arguments, including hyperparameters.\n", |
1637 | 1666 | " model_serving_container_image_uri=f\"gcr.io/{PROJECT_ID}/{PREDICTION_CONTAINER}:latest\",\n", |
1638 | 1667 | " model_serving_container_predict_route=\"/predict\",\n", |
1639 | | - " model_serving_container_health_route=\"/health\")\n", |
| 1668 | + " model_serving_container_health_route=\"/health\",\n", |
| 1669 | + ")\n", |
1640 | 1670 | "\n", |
1641 | 1671 | "print(\"Training Spec:\", job._managed_model)\n", |
1642 | 1672 | "\n", |
|
1645 | 1675 | " replica_count=1,\n", |
1646 | 1676 | " machine_type=\"n1-standard-4\",\n", |
1647 | 1677 | " accelerator_type=\"ACCELERATOR_TYPE_UNSPECIFIED\",\n", |
1648 | | - " accelerator_count=0)" |
| 1678 | + " accelerator_count=0,\n", |
| 1679 | + ")" |
1649 | 1680 | ] |
1650 | 1681 | }, |
1651 | 1682 | { |
|
1784 | 1815 | "! gcloud ai models delete $model.name --quiet\n", |
1785 | 1816 | "\n", |
1786 | 1817 | "# Delete Cloud Storage objects that were created\n", |
1787 | | - "! gsutil -m rm -r $ARTIFACTS_DIR" |
| 1818 | + "! gcloud storage rm --recursive $ARTIFACTS_DIR" |
1788 | 1819 | ] |
1789 | 1820 | } |
1790 | 1821 | ], |
|
0 commit comments