Train and Deploy a Model with SageMaker
Build an end-to-end ML pipeline on AWS SageMaker using XGBoost.
Introduction
30 Second Summary
Every time Netflix recommends a show or your email filters spam, a machine learning model is making predictions behind the scenes. These models learn patterns from data and apply them to new information they have never seen before.
In this project, you will train and deploy your own machine learning model on AWS. Starting from raw data, you'll launch a managed training job and deploy the result as a live prediction endpoint that responds in real time.
What You'll Build
An end-to-end machine learning pipeline on Amazon SageMaker that trains an XGBoost classification model and deploys it as a real-time prediction endpoint.
By the end of this project, you'll have:
- A SageMaker Notebook Instance with a Jupyter environment for running your ML code.
- A trained XGBoost classification model stored in Amazon S3.
- A live real-time inference endpoint that accepts data and returns predictions.
- Secret Mission: Run a batch transform job to generate predictions on an entire dataset at once, without needing a live endpoint.
Do I need machine learning experience?
No prior ML or Python experience is required. Basic familiarity with Python syntax is helpful but not essential.
You do need an AWS account with billing enabled. The resources in this project are covered by the AWS Free Tier for the first 2 months after you create your first SageMaker resource.
Set Up Your SageMaker Notebook Instance
To train and deploy a machine learning model, you need a coding environment connected to cloud compute resources. Amazon SageMaker AI provides managed notebook instances that come pre-loaded with ML libraries, so you can start writing code immediately without any local setup.
In this step, you'll create a SageMaker Notebook Instance in the AWS console. This gives you a ready-to-use Jupyter environment running in the cloud.
In this step, get ready to:
- Create a SageMaker Notebook Instance with an IAM execution role.
- Launch the Jupyter notebook environment.
- Create a new notebook using the conda_python3 kernel.
Sign in and create your notebook instance
SageMaker Notebook Instances are managed compute environments that run Jupyter. You'll configure one in the AWS Console and let SageMaker handle provisioning the server and libraries.
- Sign in to the AWS Management Console at https://console.aws.amazon.com/.
- In the search bar at the top, type SageMaker and select Amazon SageMaker AI from the results.
- In the left navigation pane, expand Notebook and select Notebook instances.
- Click Create notebook instance.
You'll now see the configuration page for your new notebook instance.
- For Notebook instance name, enter ml-project.
- For Notebook instance type, select ml.t3.medium.
- Leave all other fields at their default values.
Why ml.t3.medium?
The ml.t3.medium instance type is covered by the SageMaker AI Free Tier, which gives you 250 hours of notebook instance usage for the first 2 months after creating your first SageMaker AI resource. This is more than enough to complete this project.
Next, you need to set up an IAM execution role so your notebook has permission to access S3 and other AWS services.
- Scroll down to the Permissions and encryption section.
- For IAM role, select Create a new role.
- A dialog box appears asking which S3 buckets to grant access to. Leave the default settings.
- Click Create role.
- Click Create notebook instance at the bottom of the page.
What is an IAM execution role?
An IAM execution role is a set of permissions that SageMaker uses on your behalf. When your notebook needs to read data from S3 or launch a training job, it uses this role to prove it has permission.
The role SageMaker creates automatically gets the AmazonSageMakerFullAccess policy attached. This includes access to any S3 bucket with "sagemaker" in the name.
Seeing an error when creating the role?
If you get a permissions error, your AWS account may not have IAM role creation privileges. Make sure you're signed in with an account that has administrator access or permissions to create IAM roles.
Why can't I create an IAM role in the SageMaker console?
Wait for your notebook instance to start
After clicking Create notebook instance, SageMaker provisions a managed compute instance in the cloud. This takes a few minutes.
- You'll be taken back to the Notebook instances list. Your ml-project instance shows a status of Pending.
- Wait 3-5 minutes for the status to change to InService. Refresh the page to check.
- Once the status is InService, click Open Jupyter in the Actions column next to your instance.
A new browser tab opens with the Jupyter notebook environment.
What just happened?
SageMaker launched a cloud server (ml.t3.medium), pre-installed common ML libraries, attached a 5 GB storage volume, and configured your IAM role. You now have a fully managed ML development environment without installing anything locally.
Instance stuck on Pending?
If your instance stays in Pending for more than 10 minutes, check that your AWS region supports the ml.t3.medium instance type. Try refreshing the page or switching to a different region (like us-east-1).
My SageMaker notebook instance is stuck on Pending.
Create a new notebook with the conda_python3 kernel
The Jupyter environment includes multiple pre-configured kernels. The conda_python3 kernel comes with the SageMaker Python SDK, pandas, NumPy, scikit-learn, and boto3 already installed.
- In the Jupyter file browser, click New in the top-right corner.
- Select conda_python3 from the dropdown list.
A new notebook opens in a separate tab, ready for you to write code.
What is a kernel?
A kernel is the engine that runs your notebook code. The conda_python3 kernel uses a Conda environment with Python 3 and popular data science libraries pre-installed. You can start importing pandas, scikit-learn, and the SageMaker SDK immediately without running any pip install commands.
Rename your notebook
Click the title "Untitled" at the top of the notebook and rename it to something descriptive like sagemaker_ml_pipeline. This makes it easier to find later.
Your cloud ML environment is ready. Next up, you'll load a dataset and upload it to S3 for training.
Prepare Your Data and Upload to S3
Your notebook instance is running and Jupyter is ready. Now you need data to train your machine learning model.
In this step, you'll load a classic dataset, reformat it to match what SageMaker's built-in algorithms expect, and upload it to Amazon S3 so SageMaker can access it during training.
In this step, get ready to:
- Import libraries and connect to your SageMaker session.
- Load and reformat the Iris dataset for training.
- Split, save, and upload your data to S3.
Set up your SageMaker session
Before loading any data, you need to establish a connection to your AWS environment. This cell imports the libraries you'll use throughout the project and identifies the IAM role and default S3 bucket that SageMaker will use for storage.
- Initialize your SageMaker session by pasting this code into the first cell of your notebook and pressing Shift+Enter to run it:
# Cell 1: Import libraries and set up SageMaker session
import sagemaker
import boto3
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
region = sagemaker.Session().boto_region_name
print("AWS Region: {}".format(region))
role = sagemaker.get_execution_role()
print("RoleArn: {}".format(role))
session = sagemaker.Session()
bucket = session.default_bucket()
prefix = "sagemaker-iris-xgboost"
print("Default S3 bucket: {}".format(bucket))
What does this code do?
- Imports the SageMaker SDK, pandas, NumPy, and scikit-learn utilities you'll use for data prep.
- `sagemaker.get_execution_role()` retrieves the IAM role attached to your notebook instance. This role gives SageMaker permission to access S3 and launch training jobs on your behalf.
- `session.default_bucket()` identifies a pre-created S3 bucket that SageMaker uses for storing data and model artifacts.
- After the cell finishes running, you should see three printed values: your AWS region, the IAM role ARN, and the default S3 bucket name (something like sagemaker-us-east-1-123456789012).
Seeing an error?
- If you see ModuleNotFoundError, make sure you selected the conda_python3 kernel when creating your notebook. This kernel has all required libraries pre-installed.
- If you see a permissions error, your notebook instance may not have an IAM role with S3 access attached. Return to the SageMaker console and verify the execution role.
Help me troubleshoot my SageMaker session setup. I'm getting an error when running the first cell of my notebook.
Load and prepare the Iris dataset
The Iris dataset is a classic machine learning dataset containing 150 flower measurements across 3 species. SageMaker's built-in algorithms have a specific requirement: the target column (what you're predicting) must be the first column, with no header row.
- Load the Iris dataset and reformat it for SageMaker by pasting this code into the next cell and pressing Shift+Enter:
# Cell 2: Load and prepare the Iris dataset
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df["target"] = iris.target
# SageMaker built-in algorithms expect: target column first, no header
# Reorder columns so target is first
cols = ["target"] + [col for col in iris_df.columns if col != "target"]
iris_df = iris_df[cols]
print("Dataset shape: {}".format(iris_df.shape))
print("Class distribution:")
print(iris_df["target"].value_counts())
iris_df.head()
What does this code do?
- `load_iris()` loads the dataset directly from scikit-learn. No file downloads needed.
- The code converts the raw data into a DataFrame (a table structure from pandas), then moves the target column to the first position.
- The three classes (0, 1, 2) represent three Iris flower species: setosa, versicolor, and virginica. Each has 50 samples.
- You should see the dataset shape printed as (150, 5) and a class distribution showing 50 samples per class. A preview table also appears with target as the first column.
Not seeing the table preview?
- Make sure iris_df.head() is the last line in the cell. Jupyter displays the result of the last expression automatically.
- If the output shows numbers but no table formatting, your kernel may need a restart. Click Kernel in the top menu and select Restart & Run All.
Help me understand why my Iris dataset isn't displaying correctly in my Jupyter notebook.
Split your data and upload to S3
Machine learning models need separate datasets for training and validation. The training set teaches the model, while the validation set checks how well it learned. You'll split your data 80/20 and upload both files to S3.
- Split your data, save it as CSV files, and upload to S3 by pasting this code into the next cell and pressing Shift+Enter:
# Cell 3: Split data and upload to S3
train_df, val_df = train_test_split(iris_df, test_size=0.2, random_state=42, stratify=iris_df["target"])
print("Training set size: {}".format(len(train_df)))
print("Validation set size: {}".format(len(val_df)))
# Save as CSV without index or header (SageMaker requirement)
train_df.to_csv("train.csv", index=False, header=False)
val_df.to_csv("validation.csv", index=False, header=False)
# Upload to S3
train_s3_path = session.upload_data("train.csv", bucket=bucket, key_prefix=prefix + "/data")
val_s3_path = session.upload_data("validation.csv", bucket=bucket, key_prefix=prefix + "/data")
print("Training data uploaded to: {}".format(train_s3_path))
print("Validation data uploaded to: {}".format(val_s3_path))
What does this code do?
- `train_test_split` divides the 150 samples into 120 for training and 30 for validation. The stratify parameter ensures each split has equal representation of all three classes.
- `to_csv(..., index=False, header=False)` saves the files without row numbers or column names. SageMaker's built-in algorithms require this exact format.
- `session.upload_data()` pushes the local CSV files up to your default S3 bucket under the sagemaker-iris-xgboost/data/ prefix.
- You should see the training and validation set sizes printed (120 and 30), followed by two S3 paths starting with s3:// confirming your data was uploaded successfully.
Upload taking too long or failing?
- If you see a permissions error mentioning S3 access, the IAM role attached to your notebook instance may not have the right policies. Return to the SageMaker console and verify your execution role includes S3 permissions.
- If the cell hangs for more than a minute, check your internet connection. The Iris dataset is tiny (a few KB), so uploads should complete in seconds.
Help me troubleshoot my S3 upload in SageMaker. The upload_data call is failing or hanging.
Why does SageMaker need the target column first?
SageMaker's built-in algorithms like XGBoost use a convention where the first column is always the label (what the model predicts). The remaining columns are features (the inputs). This avoids needing a separate label file or column mapping configuration.
✔️ Awesome, I've got everything!
Great. Make sure your notebook is saved by pressing Ctrl+S (Windows) or Cmd+S (macOS).
ⓧ I'd like to double check the full code
Here is the complete code for all three cells so far:
# Cell 1: Import libraries and set up SageMaker session
import sagemaker
import boto3
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
region = sagemaker.Session().boto_region_name
print("AWS Region: {}".format(region))
role = sagemaker.get_execution_role()
print("RoleArn: {}".format(role))
session = sagemaker.Session()
bucket = session.default_bucket()
prefix = "sagemaker-iris-xgboost"
print("Default S3 bucket: {}".format(bucket))
# Cell 2: Load and prepare the Iris dataset
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df["target"] = iris.target
# SageMaker built-in algorithms expect: target column first, no header
# Reorder columns so target is first
cols = ["target"] + [col for col in iris_df.columns if col != "target"]
iris_df = iris_df[cols]
print("Dataset shape: {}".format(iris_df.shape))
print("Class distribution:")
print(iris_df["target"].value_counts())
iris_df.head()
# Cell 3: Split data and upload to S3
train_df, val_df = train_test_split(iris_df, test_size=0.2, random_state=42, stratify=iris_df["target"])
print("Training set size: {}".format(len(train_df)))
print("Validation set size: {}".format(len(val_df)))
# Save as CSV without index or header (SageMaker requirement)
train_df.to_csv("train.csv", index=False, header=False)
val_df.to_csv("validation.csv", index=False, header=False)
# Upload to S3
train_s3_path = session.upload_data("train.csv", bucket=bucket, key_prefix=prefix + "/data")
val_s3_path = session.upload_data("validation.csv", bucket=bucket, key_prefix=prefix + "/data")
print("Training data uploaded to: {}".format(train_s3_path))
print("Validation data uploaded to: {}".format(val_s3_path))
Your data is prepared and stored in S3. Next up, you'll train an XGBoost model on this data using SageMaker's managed training infrastructure.
Train Your XGBoost Model
Your data is formatted and sitting in S3. Now comes the core of any ML workflow: training a model on that data.
SageMaker handles all the infrastructure for you. It spins up a dedicated training instance, runs the algorithm against your data, and saves the trained model back to S3. You just need to tell it what algorithm to use and how to tune it.
In this step, get ready to:
- Configure an XGBoost Estimator with SageMaker's built-in algorithm.
- Launch a managed training job on AWS infrastructure.
- Verify the trained model artifact is saved to S3.
Configure the XGBoost Estimator
Before SageMaker can train a model, it needs to know which algorithm to use, what compute resources to provision, and how to tune the algorithm. You configure all of this in an Estimator object.
- In your Jupyter notebook, create a new cell below Cell 3 and paste the following code:
# Cell 4: Configure and run training job
from sagemaker.session import TrainingInput
container = sagemaker.image_uris.retrieve("xgboost", region, "1.2-1")
print("XGBoost container image: {}".format(container))
s3_output_location = "s3://{}/{}/output".format(bucket, prefix)
xgb_model = sagemaker.estimator.Estimator(
image_uri=container,
role=role,
instance_count=1,
instance_type="ml.m4.xlarge",
volume_size=5,
output_path=s3_output_location,
sagemaker_session=session,
)
xgb_model.set_hyperparameters(
max_depth=5,
eta=0.2,
gamma=4,
min_child_weight=6,
subsample=0.7,
objective="multi:softmax",
num_class=3,
num_round=100,
)
What does this code do?
This cell configures everything SageMaker needs to run a training job.
- sagemaker.image_uris.retrieve("xgboost", region, "1.2-1") fetches the URI of a pre-built Docker container that has XGBoost ready to run on SageMaker.
- The Estimator defines the training infrastructure: one ml.m4.xlarge instance (covered by the free tier for 50 hours), your IAM role for permissions, and where to save the output model.
- set_hyperparameters() tunes the algorithm. objective="multi:softmax" tells XGBoost this is a multi-class classification problem, and num_class=3 tells it there are three possible classes (the three iris species).
- Run the cell by pressing Shift+Enter.
- You should see the XGBoost container image URI printed in the output, starting with a long AWS account number and ending in xgboost:1.2-1.
Not seeing the container URI?
- Make sure you ran Cells 1-3 first. The region variable must be defined before this cell can retrieve the image URI.
- Check that the kernel says conda_python3 in the top right of your notebook. Other kernels may not have the SageMaker SDK installed.
Why can't SageMaker find my XGBoost image?
Why XGBoost?
XGBoost is one of the most popular algorithms for structured/tabular data. It builds an ensemble of decision trees that learn from each other's mistakes. SageMaker provides it as a built-in algorithm, meaning you don't need to write any training code yourself.
The alternative would be writing a custom training script. Built-in algorithms let you skip that entirely and focus on configuration.
Launch the training job
With the Estimator configured, you need to point it at your training and validation data in S3, then kick off the job. SageMaker provisions a dedicated instance, downloads your data, runs XGBoost, and saves the model.
- Create a new cell below Cell 4 and paste the following code:
# Cell 5: Start training
train_input = TrainingInput(
"s3://{}/{}/data/train.csv".format(bucket, prefix), content_type="csv"
)
validation_input = TrainingInput(
"s3://{}/{}/data/validation.csv".format(bucket, prefix), content_type="csv"
)
xgb_model.fit({"train": train_input, "validation": validation_input}, wait=True)
print("\nModel artifact saved to: {}".format(xgb_model.model_data))
What does this code do?
- TrainingInput objects tell SageMaker where your data lives in S3 and what format it's in (csv).
- .fit() starts the actual training job on AWS. The dictionary keys "train" and "validation" are channel names that SageMaker uses to route data to the algorithm.
- wait=True keeps the cell running until training finishes, streaming the training logs directly into your notebook output.
- Run the cell by pressing Shift+Enter.
- This cell will take 2-4 minutes to complete. You'll see training logs streaming in the output as SageMaker provisions the instance and runs the algorithm.
What should I see while training runs?
The output streams status messages as SageMaker sets up the training job. You'll see it download the data, run XGBoost training iterations, and report metrics. The cell stays busy (shown by a [*] next to it) until training completes.
Once finished, the final line prints the S3 path where your trained model artifact (model.tar.gz) is saved.
Training job failed or timed out?
- Check the error message in the output. A common cause is an IAM permissions issue. Make sure the execution role has S3 access (it should if you selected the default when creating the notebook instance).
- If you see a resource limit error, your AWS account may not have the ml.m4.xlarge quota for training. New accounts sometimes need to request a service limit increase from the AWS console.
- Verify that Cells 1-3 ran successfully by checking that train_s3_path and val_s3_path print valid S3 paths when you run them in a new cell.
Why is my SageMaker training job failing?
Verify the trained model artifact
Once the cell finishes running, your trained model is stored in S3 as a compressed artifact. This is the file SageMaker will use in the next step to deploy a live prediction endpoint.
- Look at the last line of your Cell 5 output. It prints the full S3 path to your model artifact.
- The path follows this pattern: s3://{bucket}/sagemaker-iris-xgboost/output/{training-job-name}/output/model.tar.gz.
What is model.tar.gz?
SageMaker packages your trained model into a compressed archive (model.tar.gz) and uploads it to S3. This archive contains the serialized model weights that XGBoost learned from your training data. When you deploy this model, SageMaker downloads the archive and loads it into a serving container.
✔️ Awesome, I've got everything!
Great. Double check you see the model artifact S3 path printed at the end of Cell 5.
ⓧ I'd like to double check the full code
Here is the complete notebook code through Cell 5:
# Cell 1: Import libraries and set up SageMaker session
import sagemaker
import boto3
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
region = sagemaker.Session().boto_region_name
print("AWS Region: {}".format(region))
role = sagemaker.get_execution_role()
print("RoleArn: {}".format(role))
session = sagemaker.Session()
bucket = session.default_bucket()
prefix = "sagemaker-iris-xgboost"
print("Default S3 bucket: {}".format(bucket))
# Cell 2: Load and prepare the Iris dataset
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df["target"] = iris.target
# SageMaker built-in algorithms expect: target column first, no header
# Reorder columns so target is first
cols = ["target"] + [col for col in iris_df.columns if col != "target"]
iris_df = iris_df[cols]
print("Dataset shape: {}".format(iris_df.shape))
print("Class distribution:")
print(iris_df["target"].value_counts())
iris_df.head()
# Cell 3: Split data and upload to S3
train_df, val_df = train_test_split(iris_df, test_size=0.2, random_state=42, stratify=iris_df["target"])
print("Training set size: {}".format(len(train_df)))
print("Validation set size: {}".format(len(val_df)))
# Save as CSV without index or header (SageMaker requirement)
train_df.to_csv("train.csv", index=False, header=False)
val_df.to_csv("validation.csv", index=False, header=False)
# Upload to S3
train_s3_path = session.upload_data("train.csv", bucket=bucket, key_prefix=prefix + "/data")
val_s3_path = session.upload_data("validation.csv", bucket=bucket, key_prefix=prefix + "/data")
print("Training data uploaded to: {}".format(train_s3_path))
print("Validation data uploaded to: {}".format(val_s3_path))
# Cell 4: Configure and run training job
from sagemaker.session import TrainingInput
container = sagemaker.image_uris.retrieve("xgboost", region, "1.2-1")
print("XGBoost container image: {}".format(container))
s3_output_location = "s3://{}/{}/output".format(bucket, prefix)
xgb_model = sagemaker.estimator.Estimator(
image_uri=container,
role=role,
instance_count=1,
instance_type="ml.m4.xlarge",
volume_size=5,
output_path=s3_output_location,
sagemaker_session=session,
)
xgb_model.set_hyperparameters(
max_depth=5,
eta=0.2,
gamma=4,
min_child_weight=6,
subsample=0.7,
objective="multi:softmax",
num_class=3,
num_round=100,
)
# Cell 5: Start training
train_input = TrainingInput(
"s3://{}/{}/data/train.csv".format(bucket, prefix), content_type="csv"
)
validation_input = TrainingInput(
"s3://{}/{}/data/validation.csv".format(bucket, prefix), content_type="csv"
)
xgb_model.fit({"train": train_input, "validation": validation_input}, wait=True)
print("\nModel artifact saved to: {}".format(xgb_model.model_data))
Your model is trained and stored in S3. Next up, you'll deploy it as a live prediction endpoint and send it real data to classify.
Deploy Your Model and Get Predictions
Your model is trained and the artifact is sitting in S3. But a model file on its own doesn't do anything useful.
To actually use your model, you need to deploy it as a live prediction service. SageMaker handles the infrastructure for this. It spins up a compute instance, loads your trained model, and exposes an endpoint that accepts data and returns predictions in real time.
In this step, get ready to:
- Deploy your trained model as a real-time inference endpoint.
- Send test data to the endpoint and verify prediction accuracy.
Deploy the trained model to a real-time endpoint
Deploying a model creates a hosted HTTPS endpoint on AWS. SageMaker provisions a dedicated compute instance, loads your model artifact from S3, and keeps the endpoint running until you explicitly shut it down.
What is a real-time inference endpoint?
A real-time endpoint is a live web service that accepts incoming data and returns predictions immediately. It stays running 24/7 until you delete it, which is why cleanup is critical.
The SageMaker free tier covers 125 hours of ml.m4.xlarge inference instances for the first 2 months. That is plenty for this project.
- Create a new cell in your notebook and deploy the model by pasting this code:
# Cell 6: Deploy model to real-time endpoint
from sagemaker.serializers import CSVSerializer
xgb_predictor = xgb_model.deploy(
initial_instance_count=1,
instance_type="ml.m4.xlarge",
serializer=CSVSerializer(),
)
print("Endpoint name: {}".format(xgb_predictor.endpoint_name))
print("Endpoint is live and ready for predictions!")
What does this code do?
- from sagemaker.serializers import CSVSerializer imports the serializer that converts your input data to CSV format before sending it to the endpoint.
- xgb_model.deploy() takes your trained model and launches it on a dedicated ml.m4.xlarge instance with one replica.
- The serializer=CSVSerializer() tells the predictor to format your input as CSV when sending requests to the endpoint.
- Run the cell by pressing Shift+Enter.
- Wait for deployment to complete. This takes 3-5 minutes. You will see a series of dashes (---) appearing as SageMaker provisions the instance.
- Once complete, you should see your endpoint name printed along with the message Endpoint is live and ready for predictions!.
Deployment taking longer than 5 minutes?
- Deployment can occasionally take up to 10 minutes depending on instance availability in your region. Let it continue running.
- If you see an error about instance limits, your account may have hit a quota. Check your AWS Service Quotas for SageMaker and request an increase for ml.m4.xlarge endpoint instances.
- help me troubleshoot my SageMaker endpoint deployment error
Endpoints charge continuously
Your endpoint is now running on a dedicated instance. It charges per hour while active, even if you are not sending predictions. You will delete it in the next step to stop charges.
Send test predictions and verify accuracy
Your endpoint is live. Now you will send real data to it and check whether the predictions match the actual labels from your validation set.
- Create a new cell below and paste this code to send test samples and print the results:
# Cell 7: Send test predictions
# Use validation data to test (features only, no label)
test_samples = val_df.iloc[:, 1:].values # All columns except target
actual_labels = val_df.iloc[:, 0].values # Target column
# Send predictions in small batches
predictions = []
for i in range(len(test_samples)):
row = ",".join([str(val) for val in test_samples[i]])
result = xgb_predictor.predict(row)
predictions.append(float(result))
predictions = np.array(predictions)
accuracy = np.mean(predictions == actual_labels)
print("Predictions vs Actual (first 10 samples):")
print("-" * 40)
for i in range(min(10, len(predictions))):
status = "correct" if predictions[i] == actual_labels[i] else "WRONG"
print(" Predicted: {:.0f} | Actual: {:.0f} | {}".format(predictions[i], actual_labels[i], status))
print("-" * 40)
print("Overall accuracy: {:.1f}% ({}/{} correct)".format(
accuracy * 100, int(np.sum(predictions == actual_labels)), len(predictions)
))
What does this code do?
- val_df.iloc[:, 1:].values grabs the feature columns (everything except the target) from your validation set as a NumPy array.
- val_df.iloc[:, 0].values grabs the actual target labels so you can compare them against the predictions.
- The loop sends each row to the endpoint one at a time as a CSV-formatted string, then collects the predicted class label.
- The final print statements compare predicted vs actual labels for the first 10 samples and calculate overall accuracy across all 30 validation samples.
- Run the cell by pressing Shift+Enter.
- You should see a table showing predicted vs actual class labels for 10 samples, followed by an overall accuracy percentage.
What should I see?
You will see a table of 10 predictions with their actual labels. Most (or all) should show correct. The overall accuracy should be high, typically 90% or above. The XGBoost algorithm is well suited for this type of structured classification problem.
Seeing an error when sending predictions?
- If you see a ModelError or ValidationError, make sure you ran Cell 6 successfully and the endpoint is fully deployed before running Cell 7.
- If you see a timeout error, the endpoint may still be warming up. Wait 30 seconds and re-run the cell.
- help me debug my SageMaker prediction error
✔️ Awesome, I've got everything!
Great. Double check you have saved your notebook.
ⓧ I'd like to double check the full code
Here is the complete notebook code through Cell 7. Compare against your notebook to make sure everything matches.
# Cell 1: Import libraries and set up SageMaker session
import sagemaker
import boto3
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
region = sagemaker.Session().boto_region_name
print("AWS Region: {}".format(region))
role = sagemaker.get_execution_role()
print("RoleArn: {}".format(role))
session = sagemaker.Session()
bucket = session.default_bucket()
prefix = "sagemaker-iris-xgboost"
print("Default S3 bucket: {}".format(bucket))
# Cell 2: Load and prepare the Iris dataset
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df["target"] = iris.target
# SageMaker built-in algorithms expect: target column first, no header
# Reorder columns so target is first
cols = ["target"] + [col for col in iris_df.columns if col != "target"]
iris_df = iris_df[cols]
print("Dataset shape: {}".format(iris_df.shape))
print("Class distribution:")
print(iris_df["target"].value_counts())
iris_df.head()
# Cell 3: Split data and upload to S3
train_df, val_df = train_test_split(iris_df, test_size=0.2, random_state=42, stratify=iris_df["target"])
print("Training set size: {}".format(len(train_df)))
print("Validation set size: {}".format(len(val_df)))
# Save as CSV without index or header (SageMaker requirement)
train_df.to_csv("train.csv", index=False, header=False)
val_df.to_csv("validation.csv", index=False, header=False)
# Upload to S3
train_s3_path = session.upload_data("train.csv", bucket=bucket, key_prefix=prefix + "/data")
val_s3_path = session.upload_data("validation.csv", bucket=bucket, key_prefix=prefix + "/data")
print("Training data uploaded to: {}".format(train_s3_path))
print("Validation data uploaded to: {}".format(val_s3_path))
# Cell 4: Configure and run training job
from sagemaker.session import TrainingInput
container = sagemaker.image_uris.retrieve("xgboost", region, "1.2-1")
print("XGBoost container image: {}".format(container))
s3_output_location = "s3://{}/{}/output".format(bucket, prefix)
xgb_model = sagemaker.estimator.Estimator(
image_uri=container,
role=role,
instance_count=1,
instance_type="ml.m4.xlarge",
volume_size=5,
output_path=s3_output_location,
sagemaker_session=session,
)
xgb_model.set_hyperparameters(
max_depth=5,
eta=0.2,
gamma=4,
min_child_weight=6,
subsample=0.7,
objective="multi:softmax",
num_class=3,
num_round=100,
)
# Cell 5: Start training
train_input = TrainingInput(
"s3://{}/{}/data/train.csv".format(bucket, prefix), content_type="csv"
)
validation_input = TrainingInput(
"s3://{}/{}/data/validation.csv".format(bucket, prefix), content_type="csv"
)
xgb_model.fit({"train": train_input, "validation": validation_input}, wait=True)
print("\nModel artifact saved to: {}".format(xgb_model.model_data))
# Cell 6: Deploy model to real-time endpoint
from sagemaker.serializers import CSVSerializer
xgb_predictor = xgb_model.deploy(
initial_instance_count=1,
instance_type="ml.m4.xlarge",
serializer=CSVSerializer(),
)
print("Endpoint name: {}".format(xgb_predictor.endpoint_name))
print("Endpoint is live and ready for predictions!")
# Cell 7: Send test predictions
# Use validation data to test (features only, no label)
test_samples = val_df.iloc[:, 1:].values # All columns except target
actual_labels = val_df.iloc[:, 0].values # Target column
# Send predictions in small batches
predictions = []
for i in range(len(test_samples)):
row = ",".join([str(val) for val in test_samples[i]])
result = xgb_predictor.predict(row)
predictions.append(float(result))
predictions = np.array(predictions)
accuracy = np.mean(predictions == actual_labels)
print("Predictions vs Actual (first 10 samples):")
print("-" * 40)
for i in range(min(10, len(predictions))):
status = "correct" if predictions[i] == actual_labels[i] else "WRONG"
print(" Predicted: {:.0f} | Actual: {:.0f} | {}".format(predictions[i], actual_labels[i], status))
print("-" * 40)
print("Overall accuracy: {:.1f}% ({}/{} correct)".format(
accuracy * 100, int(np.sum(predictions == actual_labels)), len(predictions)
))
Your model is live and making accurate predictions. Next up, you will clean up all your resources to stop any ongoing charges.
Secret mission
Run a Batch Transform Job
Your real-time endpoint handles one prediction at a time. But what if you had thousands of records to score at once? In production, batch transform is the go-to pattern for bulk predictions without keeping a live endpoint running.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses AWS resources that charge per hour while running, so cleaning up promptly avoids unexpected costs.
Cost warning
Your real-time inference endpoint charges continuously while active, even if you are not sending predictions. The SageMaker free tier covers 125 hours of ml.m4.xlarge inference and 250 hours of ml.t3.medium notebook time for the first 2 months only.
If you are not actively testing, delete the endpoint immediately. A forgotten endpoint can consume your entire free tier allowance in about 5 days.
Resources you used:
- SageMaker Real-Time Inference Endpoint (ml.m4.xlarge) charges continuously while active.
- SageMaker Notebook Instance ml-project (ml.t3.medium) charges per hour when running.
- S3 bucket contents (training data, model artifacts, batch transform data) incur minimal storage charges.
Keep everything running
No action needed beyond deleting the endpoint. Choose this if you plan to return within a few hours to continue experimenting.
- Delete the inference endpoint first. Return to your Jupyter notebook and run Cell 8 (xgb_predictor.delete_endpoint()). Endpoints charge continuously, even if you keep the notebook running.
- Leave the notebook instance running if you want to come back soon. It will continue using your free tier hours.
- S3 storage costs are negligible for this dataset size.
Pause - I'll come back to this later
Shut down running compute to preserve your free tier hours. Your notebook files and S3 data stay intact for when you return.
- Delete the inference endpoint by running Cell 8 in your notebook (xgb_predictor.delete_endpoint()).
- Stop the notebook instance. In the SageMaker console, under Notebook, choose Notebook instances.
- Select ml-project, choose Actions, then choose Stop. Wait for the status to change to Stopped.
- Your notebooks and files are preserved on the stopped instance. When you are ready to resume, choose Actions and then Start.
Delete - I don't want to use this again
Remove all project resources to stop all charges completely. This cannot be undone.
- Delete the inference endpoint. In your Jupyter notebook, run Cell 8:
- xgb_predictor.delete_endpoint() removes the endpoint and its underlying ML compute instances.
- Delete the notebook instance. In the SageMaker console, under Notebook, choose Notebook instances.
- Select ml-project, choose Actions, then choose Stop. Wait for the status to change to Stopped.
- Once stopped, choose Actions again and choose Delete. This permanently removes the compute instance and its storage volume.
- Empty the S3 bucket. Open the Amazon S3 console at https://console.aws.amazon.com/s3/.
- In the left navigation pane, choose General purpose buckets.
- Find your default SageMaker bucket (it starts with sagemaker- followed by your region and account ID).
- Select the bucket and choose Empty. Confirm by entering the bucket name, then choose Empty.
- Optionally, select the bucket again and choose Delete to remove the bucket itself.
Nice Work!
Nice Work!
You just trained and deployed a machine learning model on Amazon SageMaker.
You've learned how to:
- Built a complete ML pipeline from raw data to live predictions using a managed Jupyter notebook in the cloud.
- Trained an XGBoost classification model using SageMaker's managed training infrastructure.
- Deployed a real-time inference endpoint and sent live prediction requests to classify iris flower species.
- Ran a batch transform job for bulk predictions without needing a live endpoint.
Ready to quiz yourself?