|
36 | 36 | "\n",
|
37 | 37 | "## Setup\n",
|
38 | 38 | "\n",
|
39 |
| - "_This notebook was created and tested on an ml.m4.xlarge notebook instance._\n", |
| 39 | + "_This notebook was created and tested on an ml.m4.xlarge notebook instance. It assumes that the 'sagemaker' package is already installed in the environment._ \n", |
| 40 | + "\n", |
| 41 | + "_It has been tested on the following versions of important python packages:_\n", |
| 42 | + "\n", |
| 43 | + "_sagemaker>=2.14_,\n", |
| 44 | + "_pandas==1.1.2_" |
| 45 | + ] |
| 46 | + }, |
| 47 | + { |
| 48 | + "cell_type": "code", |
| 49 | + "execution_count": null, |
| 50 | + "metadata": {}, |
| 51 | + "outputs": [], |
| 52 | + "source": [ |
| 53 | + "import sys\n", |
| 54 | + "import sagemaker\n", |
| 55 | + "import importlib\n", |
| 56 | + "orig_sm_version = sagemaker.__version__\n", |
| 57 | + "\n", |
| 58 | + "with open('orig_sm_version.txt', \"w\") as f:\n", |
| 59 | + " f.write(orig_sm_version)\n", |
| 60 | + "\n", |
| 61 | + "%pip install --no-cache-dir -qU \"sagemaker>=2.14.0\"" |
| 62 | + ] |
| 63 | + }, |
| 64 | + { |
| 65 | + "cell_type": "markdown", |
| 66 | + "metadata": {}, |
| 67 | + "source": [ |
| 68 | + "### Please restart the kernel to use the updated sagemaker package and continue below" |
| 69 | + ] |
| 70 | + }, |
| 71 | + { |
| 72 | + "cell_type": "markdown", |
| 73 | + "metadata": {}, |
| 74 | + "source": [ |
40 | 75 | "\n",
|
41 | 76 | "Let's start by specifying:\n",
|
42 | 77 | "\n",
|
|
86 | 121 | "import json\n",
|
87 | 122 | "from IPython.display import display\n",
|
88 | 123 | "from time import strftime, gmtime\n",
|
89 |
| - "import sagemaker\n", |
90 |
| - "from sagemaker.predictor import csv_serializer" |
| 124 | + "from sagemaker.serializers import CSVSerializer" |
91 | 125 | ]
|
92 | 126 | },
|
93 | 127 | {
|
|
325 | 359 | "metadata": {},
|
326 | 360 | "outputs": [],
|
327 | 361 | "source": [
|
328 |
| - "from sagemaker.amazon.amazon_estimator import get_image_uri\n", |
329 |
| - "container = get_image_uri(boto3.Session().region_name, 'xgboost')" |
| 362 | + "from sagemaker import image_uris\n", |
| 363 | + "container = image_uris.retrieve(framework='xgboost', region=boto3.Session().region_name, version='1')" |
330 | 364 | ]
|
331 | 365 | },
|
332 | 366 | {
|
|
342 | 376 | "metadata": {},
|
343 | 377 | "outputs": [],
|
344 | 378 | "source": [
|
345 |
| - "s3_input_train = sagemaker.s3_input(s3_data='s3://{}/{}/train'.format(bucket, prefix), content_type='csv')\n", |
346 |
| - "s3_input_validation = sagemaker.s3_input(s3_data='s3://{}/{}/validation/'.format(bucket, prefix), content_type='csv')" |
| 379 | + "s3_input_train = sagemaker.inputs.TrainingInput(s3_data='s3://{}/{}/train'.format(bucket, prefix), content_type='csv')\n", |
| 380 | + "s3_input_validation = sagemaker.inputs.TrainingInput(s3_data='s3://{}/{}/validation/'.format(bucket, prefix), content_type='csv')" |
347 | 381 | ]
|
348 | 382 | },
|
349 | 383 | {
|
|
370 | 404 | "\n",
|
371 | 405 | "xgb = sagemaker.estimator.Estimator(container,\n",
|
372 | 406 | " role, \n",
|
373 |
| - " train_instance_count=1, \n", |
374 |
| - " train_instance_type='ml.m4.xlarge',\n", |
| 407 | + " instance_count=1, \n", |
| 408 | + " instance_type='ml.m4.xlarge',\n", |
375 | 409 | " output_path='s3://{}/{}/output'.format(bucket, prefix),\n",
|
376 | 410 | " sagemaker_session=sess)\n",
|
377 | 411 | "xgb.set_hyperparameters(max_depth=5,\n",
|
|
393 | 427 | "---\n",
|
394 | 428 | "## Host\n",
|
395 | 429 | "\n",
|
396 |
| - "Now that we've trained the algorithm, let's create a model and deploy it to a hosted endpoint." |
| 430 | + "Now that we've trained the algorithm, let's create a model and deploy it to a hosted endpoint. We'll also need to setup serializers and deserializers for passing our `test_data` NumPy arrays to the model behind the endpoint." |
397 | 431 | ]
|
398 | 432 | },
|
399 | 433 | {
|
|
403 | 437 | "outputs": [],
|
404 | 438 | "source": [
|
405 | 439 | "xgb_predictor = xgb.deploy(initial_instance_count=1,\n",
|
406 |
| - " instance_type='ml.m4.xlarge')" |
| 440 | + " instance_type='ml.m4.xlarge', serializer=CSVSerializer())" |
407 | 441 | ]
|
408 | 442 | },
|
409 | 443 | {
|
|
412 | 446 | "source": [
|
413 | 447 | "### Evaluate\n",
|
414 | 448 | "\n",
|
415 |
| - "Now that we have a hosted endpoint running, we can make real-time predictions from our model very easily, simply by making an http POST request. But first, we'll need to setup serializers and deserializers for passing our `test_data` NumPy arrays to the model behind the endpoint." |
416 |
| - ] |
417 |
| - }, |
418 |
| - { |
419 |
| - "cell_type": "code", |
420 |
| - "execution_count": null, |
421 |
| - "metadata": {}, |
422 |
| - "outputs": [], |
423 |
| - "source": [ |
424 |
| - "xgb_predictor.content_type = 'text/csv'\n", |
425 |
| - "xgb_predictor.serializer = csv_serializer\n", |
426 |
| - "xgb_predictor.deserializer = None" |
| 449 | + "Now that we have a hosted endpoint running, we can make real-time predictions from our model very easily, simply by making an http POST request." |
427 | 450 | ]
|
428 | 451 | },
|
429 | 452 | {
|
430 | 453 | "cell_type": "markdown",
|
431 | 454 | "metadata": {},
|
432 | 455 | "source": [
|
433 |
| - "Now, we'll use a simple function to:\n", |
| 456 | + "We'll use a simple function to:\n", |
434 | 457 | "1. Loop over our test dataset\n",
|
435 | 458 | "1. Split it into mini-batches of rows \n",
|
436 | 459 | "1. Convert those mini-batchs to CSV string payloads\n",
|
|
449 | 472 | " predictions = ''\n",
|
450 | 473 | " for array in split_array:\n",
|
451 | 474 | " predictions = ','.join([predictions, xgb_predictor.predict(array).decode('utf-8')])\n",
|
452 |
| - "\n", |
| 475 | + " \n", |
453 | 476 | " return np.fromstring(predictions[1:], sep=',')\n",
|
454 | 477 | "\n",
|
455 |
| - "predictions = predict(test_data.as_matrix()[:, 1:])" |
| 478 | + "predictions = predict(test_data.values[:, 1:])" |
456 | 479 | ]
|
457 | 480 | },
|
458 | 481 | {
|
|
604 | 627 | "**Important. If the following command result in a permission error, scroll up and locate the value of execution role returned by `get_execution_role()`. The role must have access to the S3 bucket specified in ``output_path``.**"
|
605 | 628 | ]
|
606 | 629 | },
|
| 630 | + { |
| 631 | + "cell_type": "code", |
| 632 | + "execution_count": null, |
| 633 | + "metadata": {}, |
| 634 | + "outputs": [], |
| 635 | + "source": [ |
| 636 | + "'/'.join(xgb.output_path.split('/')[:-1])" |
| 637 | + ] |
| 638 | + }, |
607 | 639 | {
|
608 | 640 | "cell_type": "code",
|
609 | 641 | "execution_count": null,
|
|
615 | 647 | " input_shape={'data':[1, 69]},\n",
|
616 | 648 | " role=role,\n",
|
617 | 649 | " framework='xgboost',\n",
|
618 |
| - " framework_version='0.7',\n", |
| 650 | + " framework_version='0.9',\n", |
619 | 651 | " output_path=output_path)"
|
620 | 652 | ]
|
621 | 653 | },
|
|
627 | 659 | "\n",
|
628 | 660 | "We can deploy this compiled model, note that we need to use the same instance that the target we used for compilation. This creates a SageMaker endpoint that we can use to perform inference. \n",
|
629 | 661 | "\n",
|
630 |
| - "The arguments to the ``deploy`` function allow us to set the number and type of instances that will be used for the Endpoint. Make sure to choose an instance for which you have compiled your model, so in our case `ml_c5`. Neo API uses a special runtime (DLR runtime), in which our optimzed model will run." |
| 662 | + "The arguments to the ``deploy`` function allow us to set the number and type of instances that will be used for the Endpoint. Make sure to choose an instance for which you have compiled your model, so in our case `ml_c5`. Neo API uses a special runtime (DLR runtime), in which our optimzed model will run.\n", |
| 663 | + "\n", |
| 664 | + "The compiled model accepts CSV content type:" |
631 | 665 | ]
|
632 | 666 | },
|
633 | 667 | {
|
|
638 | 672 | "source": [
|
639 | 673 | "# known issue: need to manually specify endpoint name\n",
|
640 | 674 | "compiled_model.name = 'deployed-xgboost-customer-churn'\n",
|
641 |
| - "# There is a known issue where SageMaker SDK locates the incorrect docker image URI for XGBoost\n", |
642 |
| - "# For now, we manually set Image URI\n", |
643 |
| - "compiled_model.image = get_image_uri(sess.boto_region_name, 'xgboost-neo', repo_version='latest')\n", |
644 |
| - "compiled_predictor = compiled_model.deploy(initial_instance_count = 1, instance_type = 'ml.c5.4xlarge')" |
| 675 | + "\n", |
| 676 | + "compiled_predictor = compiled_model.deploy(initial_instance_count = 1, instance_type = 'ml.c5.4xlarge', serializer=CSVSerializer())" |
645 | 677 | ]
|
646 | 678 | },
|
647 | 679 | {
|
648 | 680 | "cell_type": "markdown",
|
649 | 681 | "metadata": {},
|
650 | 682 | "source": [
|
651 |
| - "### Making an inference request\n", |
652 |
| - "The compiled model accepts CSV content type:" |
| 683 | + "### Making an inference request\n" |
653 | 684 | ]
|
654 | 685 | },
|
655 | 686 | {
|
|
658 | 689 | "metadata": {},
|
659 | 690 | "outputs": [],
|
660 | 691 | "source": [
|
661 |
| - "compiled_predictor.content_type = 'text/csv'\n", |
662 |
| - "compiled_predictor.serializer = csv_serializer\n", |
663 |
| - "compiled_predictor.deserializer = None" |
| 692 | + "def optimized_predict(data, rows=500):\n", |
| 693 | + " split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))\n", |
| 694 | + " predictions = ''\n", |
| 695 | + " for array in split_array:\n", |
| 696 | + " predictions = ','.join([predictions, compiled_predictor.predict(array).decode('utf-8')])\n", |
| 697 | + "\n", |
| 698 | + " return np.fromstring(predictions[1:], sep=',')\n", |
| 699 | + "\n", |
| 700 | + "predictions = optimized_predict(test_data.values[:, 1:])" |
| 701 | + ] |
| 702 | + }, |
| 703 | + { |
| 704 | + "cell_type": "markdown", |
| 705 | + "metadata": {}, |
| 706 | + "source": [ |
| 707 | + "### Clean up sagemaker version" |
664 | 708 | ]
|
665 | 709 | },
|
666 | 710 | {
|
|
669 | 713 | "metadata": {},
|
670 | 714 | "outputs": [],
|
671 | 715 | "source": [
|
672 |
| - "def optimized_predict(data, rows=500):\n", |
673 |
| - " split_array = np.array_split(data, int(data.shape[0] / float(rows) + 1))\n", |
674 |
| - " predictions = ''\n", |
675 |
| - " for array in split_array:\n", |
676 |
| - " predictions = ','.join([predictions, compiled_predictor.predict(array).decode('utf-8')])\n", |
677 |
| - "\n", |
678 |
| - " return np.fromstring(predictions[1:], sep=',')\n", |
| 716 | + "# rollback the SageMaker Python SDK to the kernel's original version\n", |
| 717 | + "with open('orig_sm_version.txt', \"r\") as f:\n", |
| 718 | + " orig_sm_version = f.read()\n", |
679 | 719 | "\n",
|
680 |
| - "predictions = optimized_predict(test_data.as_matrix()[:, 1:])" |
| 720 | + "print(\"Original version: {}\".format(orig_sm_version))\n", |
| 721 | + "print(\"Current version: {}\".format(sagemaker.__version__))\n", |
| 722 | + "s = 'sagemaker=={}'.format(orig_sm_version)\n", |
| 723 | + "print(\"Rolling back to... {}\".format(s))\n", |
| 724 | + "%pip install --no-cache-dir -qU {s}\n", |
| 725 | + "%rm orig_sm_version.txt" |
681 | 726 | ]
|
682 | 727 | },
|
683 | 728 | {
|
|
695 | 740 | "metadata": {},
|
696 | 741 | "outputs": [],
|
697 | 742 | "source": [
|
698 |
| - "sagemaker.Session().delete_endpoint(xgb_predictor.endpoint)\n", |
699 |
| - "sagemaker.Session().delete_endpoint(compiled_predictor.endpoint)" |
| 743 | + "xgb_predictor.delete_endpoint()\n", |
| 744 | + "compiled_predictor.delete_endpoint()" |
700 | 745 | ]
|
701 | 746 | }
|
702 | 747 | ],
|
|
0 commit comments