Skip to content

Commit 1cc65f6

Browse files
authored
Merge pull request #2 from vyshnaav/main
Changes for prod compatibility
2 parents ce1ec14 + 38ed480 commit 1cc65f6

9 files changed

+270
-105
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ __pycache__/
22
.ipynb_checkpoints/
33
.DS_Store/
44
code/query.py
5+
.idea/

0_model_training_pipeline.ipynb

+71-9
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,41 @@
153153
"### Load the Config.yml file that contains information that is used across this pipeline"
154154
]
155155
},
156+
{
157+
"cell_type": "code",
158+
"execution_count": null,
159+
"metadata": {
160+
"tags": []
161+
},
162+
"outputs": [],
163+
"source": []
164+
},
165+
{
166+
"cell_type": "code",
167+
"execution_count": null,
168+
"metadata": {
169+
"tags": []
170+
},
171+
"outputs": [],
172+
"source": [
173+
"from glob import glob\n",
174+
"from utils import load_config\n",
175+
"\n",
176+
"s3 = boto3.client('s3')\n",
177+
"\n",
178+
"config = load_config('config.yml')\n",
179+
"\n",
180+
"source_dir = config['scripts']['source_dir']\n",
181+
"bucket = config['aws']['s3_bucket']\n",
182+
"prefix = config['aws']['s3_prefix']\n",
183+
"\n",
184+
"files = glob(os.path.join(source_dir, \"*.py\")) + glob(os.path.join(source_dir, \"*.txt\"))\n",
185+
"\n",
186+
"for file in files:\n",
187+
" s3.upload_file(file, bucket, f\"{prefix}/{file}\")\n",
188+
" print(file, bucket, f\"{prefix}/{file}\")"
189+
]
190+
},
156191
{
157192
"cell_type": "code",
158193
"execution_count": null,
@@ -176,7 +211,7 @@
176211
"## initialize the sagemaker session, region, role bucket and pipeline session\n",
177212
"session = sagemaker.session.Session()\n",
178213
"region = session.boto_region_name\n",
179-
"pipeline_session = PipelineSession()\n",
214+
"pipeline_session = PipelineSession(default_bucket=config['aws']['s3_bucket'])\n",
180215
"ci = boto3.client('sts').get_caller_identity()\n",
181216
"\n",
182217
"role_name = config['aws']['sagemaker_execution_role_name']\n",
@@ -229,7 +264,15 @@
229264
"# query for the training job, write it to query_training.py\n",
230265
"fpath: str = os.path.join(config['scripts']['source_dir'], config['scripts']['query'])\n",
231266
"logger.info(f\"writing training query to {fpath}\")\n",
232-
"Path(fpath).write_text(f\"TRAINING_DATA_QUERY=\\\"\\\"\\\"{config['training_step']['query']}\\\"\\\"\\\"\")\n",
267+
"\n",
268+
"q = f\"\"\"\n",
269+
"TRAINING_TRUE_QUERY=\\\"\\\"\\\"{config['training_step']['query_true']}\\\"\\\"\\\"\n",
270+
"\\n\n",
271+
"TRAINING_NON_TRUE_QUERY=\\\"\\\"\\\"{config['training_step']['query_non_true']}\\\"\\\"\\\"\n",
272+
"\"\"\"\n",
273+
"\n",
274+
"Path(fpath).write_text(q)\n",
275+
"\n",
233276
"\n",
234277
"# approval status for trained model\n",
235278
"model_approval_status = ParameterString(\n",
@@ -312,6 +355,14 @@
312355
"# A managed processor comes with a preconfigured container, so only specifying version is required.\n",
313356
"est_cls = sagemaker.sklearn.estimator.SKLearn\n",
314357
"\n",
358+
"nw_cfg = config['aws']['network_config']\n",
359+
"\n",
360+
"network_config = sagemaker.network.NetworkConfig(\n",
361+
" enable_network_isolation=nw_cfg['enable_network_isolation'],\n",
362+
" security_group_ids=nw_cfg['security_group_ids'], \n",
363+
" subnets=nw_cfg['subnets']\n",
364+
")\n",
365+
"\n",
315366
"sklearn_processor = FrameworkProcessor(\n",
316367
" estimator_cls=est_cls,\n",
317368
" framework_version=config['training_step']['sklearn_framework_version'],\n",
@@ -320,7 +371,9 @@
320371
" instance_count=config['data_processing_step']['instance_count'],\n",
321372
" tags=config['data_processing_step']['tags'], \n",
322373
" sagemaker_session=pipeline_session,\n",
323-
" base_job_name=config['pipeline']['base_job_name'], )\n",
374+
" base_job_name=config['pipeline']['base_job_name'], \n",
375+
" network_config=network_config\n",
376+
")\n",
324377
"\n",
325378
"outputs_preprocessor = [\n",
326379
" ProcessingOutput(\n",
@@ -435,7 +488,8 @@
435488
" \"features\": config['training_step']['training_features'],\n",
436489
" \"target\": config['training_step']['training_target'],\n",
437490
" },\n",
438-
" tags=config['training_step']['tags']\n",
491+
" tags=config['training_step']['tags'],\n",
492+
" output_path=f\"s3://{bucket}/{prefix}\",\n",
439493
")\n",
440494
"\n",
441495
"# Create Hyperparameter tuner object. Ranges from https://docs.aws.amazon.com/sagemaker/latest/dg/xgboost-tuning.html\n",
@@ -538,7 +592,7 @@
538592
" )\n",
539593
" )\n",
540594
" ],\n",
541-
" code = config['scripts']['evaluation'],\n",
595+
" code = f\"s3://{bucket}/{prefix}/{config['scripts']['evaluation']}\",\n",
542596
" property_files=[evaluation_report],\n",
543597
" job_arguments=[\n",
544598
" \"--target\", target_parameter,\n",
@@ -559,6 +613,13 @@
559613
"The model is registered with the model Registry with approval status set to PendingManualApproval, this means the model cannot be deployed on a SageMaker Endpoint unless its status in the registry is changed to Approved manually via the SageMaker console, programmatically or through a Lambda function."
560614
]
561615
},
616+
{
617+
"cell_type": "code",
618+
"execution_count": null,
619+
"metadata": {},
620+
"outputs": [],
621+
"source": []
622+
},
562623
{
563624
"cell_type": "code",
564625
"execution_count": null,
@@ -704,7 +765,8 @@
704765
" step_preprocess_data, \n",
705766
" step_tuning, \n",
706767
" step_evaluate_model, \n",
707-
" step_cond],\n",
768+
" step_cond\n",
769+
" ],\n",
708770
")"
709771
]
710772
},
@@ -1408,9 +1470,9 @@
14081470
],
14091471
"instance_type": "ml.t3.medium",
14101472
"kernelspec": {
1411-
"display_name": "Python 3",
1473+
"display_name": "Python 3 (Data Science 3.0)",
14121474
"language": "python",
1413-
"name": "python3"
1475+
"name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1"
14141476
},
14151477
"language_info": {
14161478
"codemirror_mode": {
@@ -1422,7 +1484,7 @@
14221484
"name": "python",
14231485
"nbconvert_exporter": "python",
14241486
"pygments_lexer": "ipython3",
1425-
"version": "3.11.5"
1487+
"version": "3.10.6"
14261488
}
14271489
},
14281490
"nbformat": 4,

1_batch_transform_pipeline.ipynb

+28-7
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
"## initialize the sagemaker session, region, role bucket and pipeline session\n",
113113
"session = sagemaker.session.Session()\n",
114114
"region = session.boto_region_name\n",
115-
"pipeline_session = PipelineSession()\n",
115+
"pipeline_session = PipelineSession(default_bucket=config['aws']['s3_bucket'])\n",
116116
"\n",
117117
"ci = boto3.client('sts').get_caller_identity()\n",
118118
"\n",
@@ -189,6 +189,13 @@
189189
" name=\"ProcessingInstanceType\", default_value=config['data_processing_step']['processing_instance_type']\n",
190190
")\n",
191191
"\n",
192+
"nw_cfg = config['aws']['network_config']\n",
193+
"\n",
194+
"network_config = sagemaker.network.NetworkConfig(\n",
195+
" enable_network_isolation=nw_cfg['enable_network_isolation'],\n",
196+
" security_group_ids=nw_cfg['security_group_ids'], \n",
197+
" subnets=nw_cfg['subnets']\n",
198+
")\n",
192199
"\n",
193200
"# Create SKlearn processor object,\n",
194201
"# The object contains information about what instance type to use, the IAM role to use etc.\n",
@@ -204,7 +211,9 @@
204211
" instance_count=config['data_processing_step']['instance_count'],\n",
205212
" tags=config['data_processing_step']['tags'], \n",
206213
" sagemaker_session=pipeline_session,\n",
207-
" base_job_name=config['pipeline']['base_job_name'], )"
214+
" base_job_name=config['pipeline']['base_job_name'], \n",
215+
" network_config=network_config\n",
216+
")"
208217
]
209218
},
210219
{
@@ -306,6 +315,15 @@
306315
"### first step is to get the latest batch data from presto and use that for batch transform step"
307316
]
308317
},
318+
{
319+
"cell_type": "code",
320+
"execution_count": null,
321+
"metadata": {},
322+
"outputs": [],
323+
"source": [
324+
"start_time, end_time = \"2024-02-27 08:00:00\", \"2024-02-27 08:10:00\" # TODO: FIX"
325+
]
326+
},
309327
{
310328
"cell_type": "code",
311329
"execution_count": null,
@@ -347,6 +365,8 @@
347365
" \"--region\", region_parameter,\n",
348366
" \"--presto_catalog\", presto_catalog_parameter,\n",
349367
" \"--presto_schema\", presto_schema_parameter,\n",
368+
" \"--start_time\", start_time,\n",
369+
" \"--end_time\", end_time,\n",
350370
" ],\n",
351371
")\n",
352372
"\n",
@@ -610,7 +630,9 @@
610630
{
611631
"cell_type": "code",
612632
"execution_count": null,
613-
"metadata": {},
633+
"metadata": {
634+
"tags": []
635+
},
614636
"outputs": [],
615637
"source": [
616638
"logger.info(json.dumps(resp, indent=2, default=str))"
@@ -1223,11 +1245,10 @@
12231245
"vcpuNum": 128
12241246
}
12251247
],
1226-
"instance_type": "ml.t3.medium",
12271248
"kernelspec": {
1228-
"display_name": "Python 3",
1249+
"display_name": "Python 3 (Data Science 3.0)",
12291250
"language": "python",
1230-
"name": "python3"
1251+
"name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/sagemaker-data-science-310-v1"
12311252
},
12321253
"language_info": {
12331254
"codemirror_mode": {
@@ -1239,7 +1260,7 @@
12391260
"name": "python",
12401261
"nbconvert_exporter": "python",
12411262
"pygments_lexer": "ipython3",
1242-
"version": "3.11.5"
1263+
"version": "3.10.6"
12431264
}
12441265
},
12451266
"nbformat": 4,

2_realtime_inference.ipynb

+61-5
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
"import sagemaker.session\n",
5353
"from datetime import datetime\n",
5454
"from typing import Dict, List\n",
55-
"from sagemaker.workflow.pipeline_context import PipelineSession"
55+
"from sagemaker.workflow.pipeline_context import PipelineSession\n",
56+
"\n",
57+
"from utils import load_config"
5658
]
5759
},
5860
{
@@ -96,9 +98,9 @@
9698
"outputs": [],
9799
"source": [
98100
"## initialize the sagemaker session, region, role bucket and pipeline session\n",
99-
"session = sagemaker.session.Session()\n",
101+
"session = sagemaker.session.Session(default_bucket=config['aws']['s3_bucket'])\n",
100102
"region = session.boto_region_name\n",
101-
"pipeline_session = PipelineSession()\n",
103+
"pipeline_session = PipelineSession(default_bucket=config['aws']['s3_bucket'])\n",
102104
"\n",
103105
"## initialize the sagemaker client\n",
104106
"sm = boto3.client(\"sagemaker\")\n",
@@ -379,7 +381,7 @@
379381
"## Run this cell to test the model inference with the newly deployed real time endpoint\n",
380382
"\n",
381383
"## create this from the config param.\n",
382-
"body_str = \"total_extended_price,avg_discount,total_quantity\\n1,2,3\\n66.77,12,2\"\n",
384+
"body_str = \"feature_1,feature_2,feature_3\\n1000,250,0.2\\n100,50,0.5\"\n",
383385
"\n",
384386
"response = smr.invoke_endpoint(\n",
385387
" EndpointName=endpoint_name,\n",
@@ -388,7 +390,61 @@
388390
")\n",
389391
"\n",
390392
"response_str = response[\"Body\"].read().decode()\n",
391-
"response_str"
393+
"eval(response_str)"
394+
]
395+
},
396+
{
397+
"cell_type": "code",
398+
"execution_count": null,
399+
"metadata": {},
400+
"outputs": [],
401+
"source": []
402+
},
403+
{
404+
"cell_type": "code",
405+
"execution_count": null,
406+
"metadata": {
407+
"tags": []
408+
},
409+
"outputs": [],
410+
"source": [
411+
"sagemaker_client.describe_endpoint_config(EndpointConfigName=endpoint_config_name)"
412+
]
413+
},
414+
{
415+
"cell_type": "code",
416+
"execution_count": null,
417+
"metadata": {},
418+
"outputs": [],
419+
"source": []
420+
},
421+
{
422+
"cell_type": "markdown",
423+
"source": [
424+
"# Delete the endpoint and endpoint configuration"
425+
],
426+
"metadata": {
427+
"collapsed": false
428+
}
429+
},
430+
{
431+
"cell_type": "code",
432+
"execution_count": null,
433+
"metadata": {
434+
"tags": []
435+
},
436+
"outputs": [],
437+
"source": [
438+
"# Create a low-level SageMaker service client.\n",
439+
"sagemaker_client = boto3.client('sagemaker', region_name=region)\n",
440+
"\n",
441+
"response = sagemaker_client.describe_endpoint_config(EndpointConfigName=endpoint_config_name)\n",
442+
"\n",
443+
"# Delete endpoint amd endpoint configuration\n",
444+
"sagemaker_client.delete_endpoint(EndpointName=endpoint_name)\n",
445+
"sagemaker_client.delete_endpoint_config(EndpointConfigName=endpoint_config_name)\n",
446+
"\n",
447+
"print(response)"
392448
]
393449
},
394450
{

code/inference.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def predict_fn(input_data, model):
5050
logger.info(f"Prediction start time: {start_time}")
5151

5252
# Ensure we use the features as specified in the model's config
53-
features_df = input_data[model.features]
53+
features_df = input_data#[model.features] # TODO: FIX when adding record identifier
5454
predictions = model.predict(features_df)
5555
features_df['prediction'] = predictions.tolist()
5656

0 commit comments

Comments
 (0)