def test_deploy_tags(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel(model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) tags = [{"ModelName": "TestModel"}] model.deploy(instance_type=INSTANCE_TYPE, initial_instance_count=1, tags=tags) sagemaker_session.endpoint_from_production_variants.assert_called_with( name="mi-1-2017-10-10-14-14-15", production_variants=[{ "InitialVariantWeight": 1, "ModelName": "mi-1-2017-10-10-14-14-15", "InstanceType": INSTANCE_TYPE, "InitialInstanceCount": 1, "VariantName": "AllTraffic", }], tags=tags, wait=True, kms_key=None, data_capture_config_dict=None, )
def test_inference_pipeline_batch_transform(sagemaker_session): sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(SPARKML_DATA_PATH, 'mleap_model.tar.gz'), key_prefix='integ-test-data/sparkml/model') xgb_model_data = sagemaker_session.upload_data( path=os.path.join(XGBOOST_DATA_PATH, 'xgb_model.tar.gz'), key_prefix='integ-test-data/xgboost/model') batch_job_name = 'test-inference-pipeline-batch-{}'.format( sagemaker_timestamp()) sparkml_model = SparkMLModel(model_data=sparkml_model_data, env={'SAGEMAKER_SPARKML_SCHEMA': SCHEMA}, sagemaker_session=sagemaker_session) xgb_image = get_image_uri(sagemaker_session.boto_region_name, 'xgboost') xgb_model = Model(model_data=xgb_model_data, image=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel(models=[sparkml_model, xgb_model], role='SageMakerRole', sagemaker_session=sagemaker_session, name=batch_job_name) transformer = model.transformer(1, 'ml.m4.xlarge') transform_input_key_prefix = 'integ-test-data/sparkml_xgboost/transform' transform_input = transformer.sagemaker_session.upload_data( path=VALID_DATA_PATH, key_prefix=transform_input_key_prefix) with timeout_and_delete_model_with_transformer( transformer, sagemaker_session, minutes=TRANSFORM_DEFAULT_TIMEOUT_MINUTES): transformer.transform(transform_input, content_type=CONTENT_TYPE_CSV, job_name=batch_job_name) transformer.wait()
def test_prepare_container_def(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel( model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session, env={"SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT": "text/csv"}, ) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) assert model.pipeline_container_def(INSTANCE_TYPE) == [ { "Environment": { "SAGEMAKER_PROGRAM": "blah.py", "SAGEMAKER_SUBMIT_DIRECTORY": "s3://mybucket/mi-1-2017-10-10-14-14-15/sourcedir.tar.gz", "SAGEMAKER_CONTAINER_LOG_LEVEL": "20", "SAGEMAKER_REGION": "us-west-2", "SAGEMAKER_ENABLE_CLOUDWATCH_METRICS": "false", }, "Image": "mi-1", "ModelDataUrl": "s3://bucket/model_1.tar.gz", }, { "Environment": { "SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT": "text/csv" }, "Image": "246618743249.dkr.ecr.us-west-2.amazonaws.com" + "/sagemaker-sparkml-serving:2.2", "ModelDataUrl": "s3://bucket/model_2.tar.gz", }, ]
def lambda_handler(event, context): schema_json = get_schema_json() bucket = os.environ['bucket'] # Get the execution ID sess = sagemaker.Session() obj = s3.Object(bucket, 'execution.txt') exec_id = obj.get()['Body'].read().decode("utf-8") role = os.environ['role'] print(exec_id) # Build variables training_job = f'{exec_id}-job' mleap_model_prefix = f'sagemaker/spark-preprocess-demo/{exec_id}/mleap-model' # Create models for Pipeline xgb_model = sagemaker.estimator.Estimator.attach( training_job).create_model() sparkml_data = 's3://{}/{}/{}'.format(os.environ['bucket'], mleap_model_prefix, 'model.tar.gz') sparkml_model = SparkMLModel(model_data=sparkml_data, env={'SAGEMAKER_SPARKML_SCHEMA': schema_json}) # Create Pipeline Model model_name = 'inference-pipeline-' + exec_id sm_model = PipelineModel(name=model_name, role=role, models=[sparkml_model, xgb_model]) sm_model.transformer(1, 'ml.m4.xlarge') event['model_name'] = model_name event['timestamp_prefix'] = exec_id return event
def test_deploy_update_endpoint(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) endpoint_name = "endpoint-name" sparkml_model = SparkMLModel(model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) model.deploy( instance_type=INSTANCE_TYPE, initial_instance_count=1, endpoint_name=endpoint_name, update_endpoint=True, ) sagemaker_session.create_endpoint_config.assert_called_with( name=model.name, model_name=model.name, initial_instance_count=INSTANCE_COUNT, instance_type=INSTANCE_TYPE, tags=None, ) config_name = sagemaker_session.create_endpoint_config( name=model.name, model_name=model.name, initial_instance_count=INSTANCE_COUNT, instance_type=INSTANCE_TYPE, ) sagemaker_session.update_endpoint.assert_called_with( endpoint_name, config_name) sagemaker_session.create_endpoint.assert_not_called()
def test_prepare_container_def(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel( model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session, env={'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT': 'text/csv'}) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) assert model.pipeline_container_def(INSTANCE_TYPE) == [{ 'Environment': { 'SAGEMAKER_PROGRAM': 'blah.py', 'SAGEMAKER_SUBMIT_DIRECTORY': 's3://mybucket/mi-1-2017-10-10-14-14-15/sourcedir.tar.gz', 'SAGEMAKER_CONTAINER_LOG_LEVEL': '20', 'SAGEMAKER_REGION': 'us-west-2', 'SAGEMAKER_ENABLE_CLOUDWATCH_METRICS': 'false' }, 'Image': 'mi-1', 'ModelDataUrl': 's3://bucket/model_1.tar.gz' }, { 'Environment': { 'SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT': 'text/csv' }, 'Image': '246618743249.dkr.ecr.us-west-2.amazonaws.com' + '/sagemaker-sparkml-serving:2.2', 'ModelDataUrl': 's3://bucket/model_2.tar.gz' }]
def test_inference_pipeline_model_deploy_and_update_endpoint( sagemaker_session, cpu_instance_type, alternative_cpu_instance_type): sparkml_data_path = os.path.join(DATA_DIR, "sparkml_model") xgboost_data_path = os.path.join(DATA_DIR, "xgboost_model") endpoint_name = "test-inference-pipeline-deploy-{}".format( sagemaker_timestamp()) sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(sparkml_data_path, "mleap_model.tar.gz"), key_prefix="integ-test-data/sparkml/model", ) xgb_model_data = sagemaker_session.upload_data( path=os.path.join(xgboost_data_path, "xgb_model.tar.gz"), key_prefix="integ-test-data/xgboost/model", ) with timeout_and_delete_endpoint_by_name(endpoint_name, sagemaker_session): sparkml_model = SparkMLModel( model_data=sparkml_model_data, env={"SAGEMAKER_SPARKML_SCHEMA": SCHEMA}, sagemaker_session=sagemaker_session, ) xgb_image = image_uris.retrieve("xgboost", sagemaker_session.boto_region_name, version="1", image_scope="inference") xgb_model = Model(model_data=xgb_model_data, image_uri=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel( models=[sparkml_model, xgb_model], role="SageMakerRole", predictor_cls=Predictor, sagemaker_session=sagemaker_session, ) predictor = model.deploy(1, alternative_cpu_instance_type, endpoint_name=endpoint_name) endpoint_desc = sagemaker_session.sagemaker_client.describe_endpoint( EndpointName=endpoint_name) old_config_name = endpoint_desc["EndpointConfigName"] predictor.update_endpoint(initial_instance_count=1, instance_type=cpu_instance_type) endpoint_desc = sagemaker_session.sagemaker_client.describe_endpoint( EndpointName=endpoint_name) new_config_name = endpoint_desc["EndpointConfigName"] new_config = sagemaker_session.sagemaker_client.describe_endpoint_config( EndpointConfigName=new_config_name) assert old_config_name != new_config_name assert new_config["ProductionVariants"][0][ "InstanceType"] == cpu_instance_type assert new_config["ProductionVariants"][0]["InitialInstanceCount"] == 1 model.delete_model() with pytest.raises(Exception) as exception: sagemaker_session.sagemaker_client.describe_model(ModelName=model.name) assert "Could not find model" in str(exception.value)
def test_delete_model_without_deploy(sagemaker_session): pipeline_model = PipelineModel([], role=ROLE, sagemaker_session=sagemaker_session) expected_error_message = 'The SageMaker model must be created before attempting to delete.' with pytest.raises(ValueError, match=expected_error_message): pipeline_model.delete_model()
def test_transformer(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel(model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session) model_name = "ModelName" model = PipelineModel( models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session, name=model_name, ) instance_count = 55 strategy = "MultiRecord" assemble_with = "Line" output_path = "s3://output/path" output_kms_key = "output:kms:key" accept = "application/jsonlines" env = {"my_key": "my_value"} max_concurrent_transforms = 20 max_payload = 5 tags = [{"my_tag": "my_value"}] volume_kms_key = "volume:kms:key" transformer = model.transformer( instance_type=INSTANCE_TYPE, instance_count=instance_count, strategy=strategy, assemble_with=assemble_with, output_path=output_path, output_kms_key=output_kms_key, accept=accept, env=env, max_concurrent_transforms=max_concurrent_transforms, max_payload=max_payload, tags=tags, volume_kms_key=volume_kms_key, ) assert transformer.instance_type == INSTANCE_TYPE assert transformer.instance_count == instance_count assert transformer.strategy == strategy assert transformer.assemble_with == assemble_with assert transformer.output_path == output_path assert transformer.output_kms_key == output_kms_key assert transformer.accept == accept assert transformer.env == env assert transformer.max_concurrent_transforms == max_concurrent_transforms assert transformer.max_payload == max_payload assert transformer.tags == tags assert transformer.volume_kms_key == volume_kms_key assert transformer.model_name == model_name
def test_inference_pipeline_model_deploy_with_update_endpoint( sagemaker_session, cpu_instance_type, alternative_cpu_instance_type ): sparkml_data_path = os.path.join(DATA_DIR, "sparkml_model") xgboost_data_path = os.path.join(DATA_DIR, "xgboost_model") endpoint_name = "test-inference-pipeline-deploy-{}".format(sagemaker_timestamp()) sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(sparkml_data_path, "mleap_model.tar.gz"), key_prefix="integ-test-data/sparkml/model", ) xgb_model_data = sagemaker_session.upload_data( path=os.path.join(xgboost_data_path, "xgb_model.tar.gz"), key_prefix="integ-test-data/xgboost/model", ) with timeout_and_delete_endpoint_by_name(endpoint_name, sagemaker_session): sparkml_model = SparkMLModel( model_data=sparkml_model_data, env={"SAGEMAKER_SPARKML_SCHEMA": SCHEMA}, sagemaker_session=sagemaker_session, ) xgb_image = get_image_uri(sagemaker_session.boto_region_name, "xgboost") xgb_model = Model( model_data=xgb_model_data, image=xgb_image, sagemaker_session=sagemaker_session ) model = PipelineModel( models=[sparkml_model, xgb_model], role="SageMakerRole", sagemaker_session=sagemaker_session, ) model.deploy(1, alternative_cpu_instance_type, endpoint_name=endpoint_name) old_endpoint = sagemaker_session.sagemaker_client.describe_endpoint( EndpointName=endpoint_name ) old_config_name = old_endpoint["EndpointConfigName"] model.deploy(1, cpu_instance_type, update_endpoint=True, endpoint_name=endpoint_name) # Wait for endpoint to finish updating # Endpoint update takes ~7min. 40 retries * 30s sleeps = 20min timeout for _ in retries(40, "Waiting for 'InService' endpoint status", seconds_to_sleep=30): new_endpoint = sagemaker_session.sagemaker_client.describe_endpoint( EndpointName=endpoint_name ) if new_endpoint["EndpointStatus"] == "InService": break new_config_name = new_endpoint["EndpointConfigName"] new_config = sagemaker_session.sagemaker_client.describe_endpoint_config( EndpointConfigName=new_config_name ) assert old_config_name != new_config_name assert new_config["ProductionVariants"][0]["InstanceType"] == cpu_instance_type assert new_config["ProductionVariants"][0]["InitialInstanceCount"] == 1 model.delete_model() with pytest.raises(Exception) as exception: sagemaker_session.sagemaker_client.describe_model(ModelName=model.name) assert "Could not find model" in str(exception.value)
def inference_pipeline_ep(role, sess, spark_model_uri, region, bucket, pipeline_model_name, endpoint_name, **context): timestamp_prefix = Variable.get("timestamp") # sm = boto3.client('sagemaker', region_name=region) s3client = boto3.client('s3', region_name=region) s3_sparkml_data_uri = spark_model_uri # Using S3 calls for listing model artifcats s3_xgb_objects = s3client.list_objects_v2( Bucket=bucket, StartAfter='sagemaker/spark-preprocess/model/xgboost/') obj_list = s3_xgb_objects['Contents'] obj_list.sort(key=lambda x: x['LastModified'], reverse=False) xgboost_model_latest = obj_list[-1]['Key'] s3_xgboost_model_uri = 's3://' + bucket + '/' + xgboost_model_latest # AirFlow XCOM feature # s3_xgboost_model_uri = context['task_instance'].xcom_pull( # task_ids='xgboost_model_training')['Training']['ModelArtifacts']['S3ModelArtifacts'] xgb_container = get_image_uri(sess.region_name, 'xgboost', repo_version='0.90-1') schema_json = schema_utils.abalone_schema() sparkml_model = SparkMLModel( model_data=s3_sparkml_data_uri, role=role, sagemaker_session=sagemaker.session.Session(sess), env={'SAGEMAKER_SPARKML_SCHEMA': schema_json}) xgb_model = Model(model_data=s3_xgboost_model_uri, role=role, sagemaker_session=sagemaker.session.Session(sess), image=xgb_container) pipeline_model_name = pipeline_model_name sm_model = PipelineModel(name=pipeline_model_name, role=role, sagemaker_session=sagemaker.session.Session(sess), models=[sparkml_model, xgb_model]) endpoint_name = endpoint_name sm_model.deploy(initial_instance_count=1, instance_type='ml.c4.xlarge', endpoint_name=endpoint_name)
def test_create_model_step_with_model_pipeline(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel( model_data="s3://bucket/model_2.tar.gz", role=ROLE, sagemaker_session=sagemaker_session, env={"SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT": "text/csv"}, ) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) inputs = CreateModelInput( instance_type="c4.4xlarge", accelerator_type="ml.eia1.medium", ) step = CreateModelStep( name="MyCreateModelStep", depends_on=["TestStep"], display_name="MyCreateModelStep", description="TestDescription", model=model, inputs=inputs, ) step.add_depends_on(["SecondTestStep"]) assert step.to_request() == { "Name": "MyCreateModelStep", "Type": "Model", "Description": "TestDescription", "DisplayName": "MyCreateModelStep", "DependsOn": ["TestStep", "SecondTestStep"], "Arguments": { "Containers": [ { "Environment": { "SAGEMAKER_PROGRAM": "dummy_script.py", "SAGEMAKER_SUBMIT_DIRECTORY": "s3://my-bucket/mi-1-2017-10-10-14-14-15/sourcedir.tar.gz", "SAGEMAKER_CONTAINER_LOG_LEVEL": "20", "SAGEMAKER_REGION": "us-west-2", }, "Image": "mi-1", "ModelDataUrl": "s3://bucket/model_1.tar.gz", }, { "Environment": { "SAGEMAKER_DEFAULT_INVOCATIONS_ACCEPT": "text/csv" }, "Image": "246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-sparkml-serving:2.4", "ModelDataUrl": "s3://bucket/model_2.tar.gz", }, ], "ExecutionRoleArn": "DummyRole", }, } assert step.properties.ModelName.expr == { "Get": "Steps.MyCreateModelStep.ModelName" }
def test_deploy(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel(model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session) model = PipelineModel(models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session) model.deploy(instance_type=INSTANCE_TYPE, initial_instance_count=1) sagemaker_session.endpoint_from_production_variants.assert_called_with( 'mi-1-2017-10-10-14-14-15', [{ 'InitialVariantWeight': 1, 'ModelName': 'mi-1-2017-10-10-14-14-15', 'InstanceType': INSTANCE_TYPE, 'InitialInstanceCount': 1, 'VariantName': 'AllTraffic' }], None)
def test_inference_pipeline_batch_transform(sagemaker_session, cpu_instance_type): sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(SPARKML_DATA_PATH, "mleap_model.tar.gz"), key_prefix="integ-test-data/sparkml/model", ) xgb_model_data = sagemaker_session.upload_data( path=os.path.join(XGBOOST_DATA_PATH, "xgb_model.tar.gz"), key_prefix="integ-test-data/xgboost/model", ) batch_job_name = "test-inference-pipeline-batch-{}".format( sagemaker_timestamp()) sparkml_model = SparkMLModel( model_data=sparkml_model_data, env={"SAGEMAKER_SPARKML_SCHEMA": SCHEMA}, sagemaker_session=sagemaker_session, ) xgb_image = image_uris.retrieve("xgboost", sagemaker_session.boto_region_name, version="1", image_scope="inference") xgb_model = Model(model_data=xgb_model_data, image_uri=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel( models=[sparkml_model, xgb_model], role="SageMakerRole", sagemaker_session=sagemaker_session, name=batch_job_name, ) transformer = model.transformer(1, cpu_instance_type) transform_input_key_prefix = "integ-test-data/sparkml_xgboost/transform" transform_input = transformer.sagemaker_session.upload_data( path=VALID_DATA_PATH, key_prefix=transform_input_key_prefix) with timeout_and_delete_model_with_transformer( transformer, sagemaker_session, minutes=TRANSFORM_DEFAULT_TIMEOUT_MINUTES): transformer.transform(transform_input, content_type="text/csv", job_name=batch_job_name) transformer.wait()
def test_network_isolation(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) sparkml_model = SparkMLModel(model_data=MODEL_DATA_2, role=ROLE, sagemaker_session=sagemaker_session) model = PipelineModel( models=[framework_model, sparkml_model], role=ROLE, sagemaker_session=sagemaker_session, enable_network_isolation=True, ) model.deploy(instance_type=INSTANCE_TYPE, initial_instance_count=1) sagemaker_session.create_model.assert_called_with( model.name, ROLE, [ { "Image": "mi-1", "Environment": { "SAGEMAKER_PROGRAM": "blah.py", "SAGEMAKER_SUBMIT_DIRECTORY": "s3://mybucket/mi-1-2017-10-10-14-14-15/sourcedir.tar.gz", "SAGEMAKER_CONTAINER_LOG_LEVEL": "20", "SAGEMAKER_REGION": "us-west-2", }, "ModelDataUrl": "s3://bucket/model_1.tar.gz", }, { "Image": "246618743249.dkr.ecr.us-west-2.amazonaws.com/sagemaker-sparkml-serving:2.2", "Environment": {}, "ModelDataUrl": "s3://bucket/model_2.tar.gz", }, ], vpc_config=None, enable_network_isolation=True, )
def test_delete_model(tfo, time, sagemaker_session): framework_model = DummyFrameworkModel(sagemaker_session) pipeline_model = PipelineModel( [framework_model], role=ROLE, sagemaker_session=sagemaker_session ) pipeline_model.deploy(instance_type=INSTANCE_TYPE, initial_instance_count=1) pipeline_model.delete_model() sagemaker_session.delete_model.assert_called_with(pipeline_model.name)
def test_inference_pipeline_model_deploy(sagemaker_session, cpu_instance_type): sparkml_data_path = os.path.join(DATA_DIR, "sparkml_model") xgboost_data_path = os.path.join(DATA_DIR, "xgboost_model") endpoint_name = "test-inference-pipeline-deploy-{}".format( sagemaker_timestamp()) sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(sparkml_data_path, "mleap_model.tar.gz"), key_prefix="integ-test-data/sparkml/model", ) xgb_model_data = sagemaker_session.upload_data( path=os.path.join(xgboost_data_path, "xgb_model.tar.gz"), key_prefix="integ-test-data/xgboost/model", ) with timeout_and_delete_endpoint_by_name(endpoint_name, sagemaker_session): sparkml_model = SparkMLModel( model_data=sparkml_model_data, env={"SAGEMAKER_SPARKML_SCHEMA": SCHEMA}, sagemaker_session=sagemaker_session, ) xgb_image = image_uris.retrieve("xgboost", sagemaker_session.boto_region_name, version="1", image_scope="inference") xgb_model = Model(model_data=xgb_model_data, image_uri=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel( models=[sparkml_model, xgb_model], role="SageMakerRole", sagemaker_session=sagemaker_session, name=endpoint_name, ) model.deploy(1, cpu_instance_type, endpoint_name=endpoint_name) predictor = Predictor( endpoint_name=endpoint_name, sagemaker_session=sagemaker_session, serializer=JSONSerializer, content_type="text/csv", accept="text/csv", ) with open(VALID_DATA_PATH, "r") as f: valid_data = f.read() assert predictor.predict(valid_data) == "0.714013934135" with open(INVALID_DATA_PATH, "r") as f: invalid_data = f.read() assert predictor.predict(invalid_data) is None model.delete_model() with pytest.raises(Exception) as exception: sagemaker_session.sagemaker_client.describe_model(ModelName=model.name) assert "Could not find model" in str(exception.value)
def test_inference_pipeline_model_deploy(sagemaker_session): sparkml_data_path = os.path.join(DATA_DIR, 'sparkml_model') xgboost_data_path = os.path.join(DATA_DIR, 'xgboost_model') endpoint_name = 'test-inference-pipeline-deploy-{}'.format( sagemaker_timestamp()) sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(sparkml_data_path, 'mleap_model.tar.gz'), key_prefix='integ-test-data/sparkml/model') xgb_model_data = sagemaker_session.upload_data( path=os.path.join(xgboost_data_path, 'xgb_model.tar.gz'), key_prefix='integ-test-data/xgboost/model') with timeout_and_delete_endpoint_by_name(endpoint_name, sagemaker_session): sparkml_model = SparkMLModel(model_data=sparkml_model_data, env={'SAGEMAKER_SPARKML_SCHEMA': SCHEMA}, sagemaker_session=sagemaker_session) xgb_image = get_image_uri(sagemaker_session.boto_region_name, 'xgboost') xgb_model = Model(model_data=xgb_model_data, image=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel(models=[sparkml_model, xgb_model], role='SageMakerRole', sagemaker_session=sagemaker_session, name=endpoint_name) model.deploy(1, 'ml.m4.xlarge', endpoint_name=endpoint_name) predictor = RealTimePredictor(endpoint=endpoint_name, sagemaker_session=sagemaker_session, serializer=json_serializer, content_type=CONTENT_TYPE_CSV, accept=CONTENT_TYPE_CSV) with open(VALID_DATA_PATH, 'r') as f: valid_data = f.read() assert predictor.predict(valid_data) == '0.714013934135' with open(INVALID_DATA_PATH, 'r') as f: invalid_data = f.read() assert (predictor.predict(invalid_data) is None) model.delete_model() with pytest.raises(Exception) as exception: sagemaker_session.sagemaker_client.describe_model(ModelName=model.name) assert 'Could not find model' in str(exception.value)
def test_inference_pipeline_model_deploy(sagemaker_session): sparkml_data_path = os.path.join(DATA_DIR, 'sparkml_model') xgboost_data_path = os.path.join(DATA_DIR, 'xgboost_model') endpoint_name = 'test-inference-pipeline-deploy-{}'.format(sagemaker_timestamp()) sparkml_model_data = sagemaker_session.upload_data( path=os.path.join(sparkml_data_path, 'mleap_model.tar.gz'), key_prefix='integ-test-data/sparkml/model') xgb_model_data = sagemaker_session.upload_data( path=os.path.join(xgboost_data_path, 'xgb_model.tar.gz'), key_prefix='integ-test-data/xgboost/model') schema = json.dumps({ "input": [ { "name": "Pclass", "type": "float" }, { "name": "Embarked", "type": "string" }, { "name": "Age", "type": "float" }, { "name": "Fare", "type": "float" }, { "name": "SibSp", "type": "float" }, { "name": "Sex", "type": "string" } ], "output": { "name": "features", "struct": "vector", "type": "double" } }) with timeout_and_delete_endpoint_by_name(endpoint_name, sagemaker_session): sparkml_model = SparkMLModel(model_data=sparkml_model_data, env={'SAGEMAKER_SPARKML_SCHEMA': schema}, sagemaker_session=sagemaker_session) xgb_image = get_image_uri(sagemaker_session.boto_region_name, 'xgboost') xgb_model = Model(model_data=xgb_model_data, image=xgb_image, sagemaker_session=sagemaker_session) model = PipelineModel(models=[sparkml_model, xgb_model], role='SageMakerRole', sagemaker_session=sagemaker_session, name=endpoint_name) model.deploy(1, 'ml.m4.xlarge', endpoint_name=endpoint_name) predictor = RealTimePredictor(endpoint=endpoint_name, sagemaker_session=sagemaker_session, serializer=json_serializer, content_type=CONTENT_TYPE_CSV, accept=CONTENT_TYPE_CSV) valid_data = '1.0,C,38.0,71.5,1.0,female' assert predictor.predict(valid_data) == "0.714013934135" invalid_data = "1.0,28.0,C,38.0,71.5,1.0" assert (predictor.predict(invalid_data) is None) model.delete_model() with pytest.raises(Exception) as exception: sagemaker_session.sagemaker_client.describe_model(ModelName=model.name) assert 'Could not find model' in str(exception.value)
def get_pipeline( region, sagemaker_project_arn=None, role=None, default_bucket='', pipeline_name='end-to-end-ml-sagemaker-pipeline', model_package_group_name='end-to-end-ml-sm-model-package-group', base_job_prefix='endtoendmlsm') -> Pipeline: """ Gets the SM Pipeline. :param role: The execution role. :param bucket_name: The bucket where pipeline artifacts are stored. :param prefix: The prefix where pipeline artifacts are stored. :return: A Pipeline instance. """ bucket_name = default_bucket prefix = 'endtoendmlsm' sagemaker_session = get_session(region, bucket_name) # --------------------- # Processing parameters # --------------------- # The path to the raw data. raw_data_path = 's3://gianpo-public/endtoendml/data/raw/predmain_raw_data_header.csv'.format( bucket_name, prefix) raw_data_path_param = ParameterString(name="raw_data_path", default_value=raw_data_path) # The output path to the training data. train_data_path = 's3://{0}/{1}/data/preprocessed/train/'.format( bucket_name, prefix) train_data_path_param = ParameterString(name="train_data_path", default_value=train_data_path) # The output path to the validation data. val_data_path = 's3://{0}/{1}/data/preprocessed/val/'.format( bucket_name, prefix) val_data_path_param = ParameterString(name="val_data_path", default_value=val_data_path) # The output path to the featurizer model. model_path = 's3://{0}/{1}/output/sklearn/'.format(bucket_name, prefix) model_path_param = ParameterString(name="model_path", default_value=model_path) # The instance type for the processing job. processing_instance_type_param = ParameterString( name="processing_instance_type", default_value='ml.m5.large') # The instance count for the processing job. processing_instance_count_param = ParameterInteger( name="processing_instance_count", default_value=1) # The train/test split ration parameter. train_test_split_ratio_param = ParameterString( name="train_test_split_ratio", default_value='0.2') # ------------------- # Training parameters # ------------------- # XGB hyperparameters. max_depth_param = ParameterString(name="max_depth", default_value='3') eta_param = ParameterString(name="eta", default_value='0.1') gamma_param = ParameterString(name="gamma", default_value='0') min_child_weight_param = ParameterString(name="min_child_weight", default_value='1') objective_param = ParameterString(name="objective", default_value='binary:logistic') num_round_param = ParameterString(name="num_round", default_value='10') eval_metric_param = ParameterString(name="eval_metric", default_value='auc') # The instance type for the training job. training_instance_type_param = ParameterString( name="training_instance_type", default_value='ml.m5.xlarge') # The instance count for the training job. training_instance_count_param = ParameterInteger( name="training_instance_count", default_value=1) # The training output path for the model. output_path = 's3://{0}/{1}/output/'.format(bucket_name, prefix) output_path_param = ParameterString(name="output_path", default_value=output_path) # -------------------------- # Register model parameters # -------------------------- # The default instance type for deployment. deploy_instance_type_param = ParameterString(name="deploy_instance_type", default_value='ml.m5.2xlarge') # The approval status for models added to the registry. model_approval_status_param = ParameterString( name="model_approval_status", default_value='PendingManualApproval') # -------------------------- # Processing Step # -------------------------- sklearn_processor = SKLearnProcessor( role=role, instance_type=processing_instance_type_param, instance_count=processing_instance_count_param, framework_version='0.20.0') inputs = [ ProcessingInput(input_name='raw_data', source=raw_data_path_param, destination='/opt/ml/processing/input') ] outputs = [ ProcessingOutput(output_name='train_data', source='/opt/ml/processing/train', destination=train_data_path_param), ProcessingOutput(output_name='val_data', source='/opt/ml/processing/val', destination=val_data_path_param), ProcessingOutput(output_name='model', source='/opt/ml/processing/model', destination=model_path_param) ] code_path = os.path.join(BASE_DIR, 'dataprep/preprocess.py') processing_step = ProcessingStep(name='Processing', code=code_path, processor=sklearn_processor, inputs=inputs, outputs=outputs, job_arguments=[ '--train-test-split-ratio', train_test_split_ratio_param ]) # -------------------------- # Training Step # -------------------------- hyperparameters = { "max_depth": max_depth_param, "eta": eta_param, "gamma": gamma_param, "min_child_weight": min_child_weight_param, "silent": 0, "objective": objective_param, "num_round": num_round_param, "eval_metric": eval_metric_param } entry_point = 'train.py' source_dir = os.path.join(BASE_DIR, 'train/') code_location = 's3://{0}/{1}/code'.format(bucket_name, prefix) estimator = XGBoost(entry_point=entry_point, source_dir=source_dir, output_path=output_path_param, code_location=code_location, hyperparameters=hyperparameters, instance_type=training_instance_type_param, instance_count=training_instance_count_param, framework_version="0.90-2", py_version="py3", role=role) training_step = TrainingStep( name='Training', estimator=estimator, inputs={ 'train': TrainingInput( s3_data=processing_step.properties.ProcessingOutputConfig. Outputs['train_data'].S3Output.S3Uri, content_type='text/csv'), 'validation': TrainingInput( s3_data=processing_step.properties.ProcessingOutputConfig. Outputs['val_data'].S3Output.S3Uri, content_type='text/csv') }) # -------------------------- # Register Model Step # -------------------------- code_location = 's3://{0}/{1}/code'.format(bucket_name, prefix) sklearn_model = SKLearnModel( name='end-to-end-ml-sm-skl-model-{0}'.format(str(int(time.time()))), model_data=processing_step.properties.ProcessingOutputConfig. Outputs['model'].S3Output.S3Uri, entry_point='inference.py', source_dir=os.path.join(BASE_DIR, 'deploy/sklearn/'), code_location=code_location, role=role, sagemaker_session=sagemaker_session, framework_version='0.20.0', py_version='py3') code_location = 's3://{0}/{1}/code'.format(bucket_name, prefix) xgboost_model = XGBoostModel( name='end-to-end-ml-sm-xgb-model-{0}'.format(str(int(time.time()))), model_data=training_step.properties.ModelArtifacts.S3ModelArtifacts, entry_point='inference.py', source_dir=os.path.join(BASE_DIR, 'deploy/xgboost/'), code_location=code_location, framework_version='0.90-2', py_version='py3', role=role, sagemaker_session=sagemaker_session) pipeline_model_name = 'end-to-end-ml-sm-xgb-skl-pipeline-{0}'.format( str(int(time.time()))) pipeline_model = PipelineModel(name=pipeline_model_name, role=role, models=[sklearn_model, xgboost_model], sagemaker_session=sagemaker_session) register_model_step = RegisterModel( name='RegisterModel', content_types=['text/csv'], response_types=['application/json', 'text/csv'], inference_instances=[deploy_instance_type_param, 'ml.m5.large'], transform_instances=['ml.c5.4xlarge'], model_package_group_name=model_package_group_name, approval_status=model_approval_status_param, model=pipeline_model) # -------------------------- # Pipeline # -------------------------- pipeline = Pipeline( name=pipeline_name, parameters=[ raw_data_path_param, train_data_path_param, val_data_path_param, model_path_param, processing_instance_type_param, processing_instance_count_param, train_test_split_ratio_param, max_depth_param, eta_param, gamma_param, min_child_weight_param, objective_param, num_round_param, eval_metric_param, training_instance_type_param, training_instance_count_param, output_path_param, deploy_instance_type_param, model_approval_status_param ], steps=[processing_step, training_step, register_model_step], sagemaker_session=sagemaker_session, ) response = pipeline.upsert(role_arn=role) print(response["PipelineArn"]) return pipeline
def build_workflow_definition(self): """ Build the workflow definition for the inference pipeline with all the states involved. Returns: :class:`~stepfunctions.steps.states.Chain`: Workflow definition as a chain of states involved in the the inference pipeline. """ default_name = self.pipeline_name train_instance_type = self.preprocessor.train_instance_type train_instance_count = self.preprocessor.train_instance_count # Preprocessor for feature transformation preprocessor_train_step = TrainingStep( StepId.TrainPreprocessor.value, estimator=self.preprocessor, job_name=default_name + '/preprocessor-source', data=self.inputs, ) preprocessor_model = self.preprocessor.create_model() preprocessor_model_step = ModelStep( StepId.CreatePreprocessorModel.value, instance_type=train_instance_type, model=preprocessor_model, model_name=default_name) preprocessor_transform_step = TransformStep( StepId.TransformInput.value, transformer=self.preprocessor.transformer( instance_count=train_instance_count, instance_type=train_instance_type, max_payload=20), job_name=default_name, model_name=default_name, data=self.inputs['train'], compression_type=self.compression_type, content_type=self.content_type) # Training train_instance_type = self.estimator.train_instance_type train_instance_count = self.estimator.train_instance_count training_step = TrainingStep( StepId.Train.value, estimator=self.estimator, job_name=default_name + '/estimator-source', data=self.inputs, ) pipeline_model = PipelineModel(name='PipelineModel', role=self.estimator.role, models=[ self.preprocessor.create_model(), self.estimator.create_model() ]) pipeline_model_step = ModelStep(StepId.CreatePipelineModel.value, instance_type=train_instance_type, model=preprocessor_model, model_name=default_name) pipeline_model_step.parameters = self.pipeline_model_config( train_instance_type, pipeline_model) deployable_model = Model(model_data='', image='') # Deployment endpoint_config_step = EndpointConfigStep( StepId.ConfigureEndpoint.value, endpoint_config_name=default_name, model_name=default_name, initial_instance_count=train_instance_count, instance_type=train_instance_type) deploy_step = EndpointStep( StepId.Deploy.value, endpoint_name=default_name, endpoint_config_name=default_name, ) return Chain([ preprocessor_train_step, preprocessor_model_step, preprocessor_transform_step, training_step, pipeline_model_step, endpoint_config_step, deploy_step ])
preproc_model_url = args.preproc_model sm_role = get_sm_execution_role(False, region) preproc_model = SKLearnModel(model_data=preproc_model_url, source_dir=os.path.abspath( os.path.dirname(__file__)), role=sm_role, entry_point='infer_preproc.py', sagemaker_session=sess) ll_image = get_image_uri(region, 'linear-learner') ll_model = Model(model_data=model_url, image=ll_image, role=sm_role, sagemaker_session=sess) timestamp_prefix = strftime("%Y-%m-%d-%H-%M-%S", gmtime()) model_name = 'inference-pipeline-' + timestamp_prefix endpoint_name = 'inference-pipeline-ep-' + timestamp_prefix sm_model = PipelineModel(name=model_name, role=sm_role, models=[preproc_model, ll_model], sagemaker_session=sess) print('Deploying SM EndPoint') sm_model.deploy(initial_instance_count=1, instance_type='ml.c4.xlarge', endpoint_name=endpoint_name) print(f'SageMaker deployed to endpoint - {endpoint_name}')