(Optional) The Same Jobs from the Terminal
Last updated on 2026-11-04 | Edit this page
Overview
Questions
- What does the AWS command-line interface (CLI) let me do that the lesson’s notebooks did, and what should I not do with it?
- How do I see, and stop, everything that is costing money from a terminal?
- What request does the SageMaker SDK send when I call
estimator.fit()?
Objectives
- Authenticate the CLI with short-lived Identity Center credentials, never with access keys.
- Match each SDK call and helper the episodes used to the CLI command that does the same thing.
- List and inspect training jobs, processing jobs, tuning jobs and
notebook instances from the terminal, stop your own by name, and read a
job’s bill the way
job_cost_report()did. - Copy data to and from S3 in bulk with
aws s3 sync. - Relaunch the training episode’s XGBoost job from its JSON description, with the same script, hyperparameters, cap and tags.
- State which resources the lesson never creates from the CLI, and why the account refuses them.
Optional, self-study episode
Everything in this lesson went through the SageMaker Python SDK in a
notebook on a SageMaker notebook instance. That instance is a cost and a
chore. It bills while it is on, five cents an hour for the
ml.t3.medium, a dollar a day, and someone has to remember
to stop it. It is also a second place to work, a Jupyter session in a
browser tab, when your code, your editor and your files are on your
laptop.
None of that is required. The notebook instance was a convenience for teaching and for governance in a shared account. SageMaker is an API, and the AWS CLI calls the same API from a terminal. A job launched from your laptop needs no instance at all. The request goes from your terminal to SageMaker, the job runs on a machine rented for it and ends, and the model lands in S3. For a project that launches a job a day and otherwise works locally, that removes the notebook instance’s whole cost and the habit of stopping it. The terminal is also the tool for checking on a job from another machine, stopping something when no notebook is open, and copying results out of S3 in bulk.
This episode does five things from a laptop terminal. It signs in to the account with Identity Center, lists what is running and reads what a job cost, stops your own jobs and your own notebook instance by name, copies data to and from S3, and relaunches the training episode’s XGBoost job from a JSON file.
Two things differ from the notebook. The first is identity. On the instance, its role signed every call. On a laptop you sign in yourself, which is section 1. The second is checking. The lesson’s notebooks printed a cost estimate and ran a launch check before every job. A JSON request does neither on its own, so section 5 runs the lesson’s checker on the file before the create call. It applies the account’s rules and prints the most the request can bill.
On a shared workshop account, such as the ML Marathon’s, keep launching from the notebook instance. It is required there, because every learner’s launches and the code behind them then sit on an instance the administrators can see, which is how they help when something goes wrong. Launching from the terminal is for your own account, and for practicing it in this episode. Checking on jobs and stopping them from the terminal is fine on any account.
What the notebooks did, and the command that does the same
The CLI, the SageMaker SDK, boto3 and the console all
talk to the same AWS API. The SDK’s estimators built requests for it,
the boto3 calls in the cleanup and RAG episodes sent
requests to it directly, and the console shows its results. So every
call the episodes made has a CLI command with the same name and the same
fields, and a boto3 method name such as
describe_training_job is the CLI command
describe-training-job with the underscores swapped for
hyphens. This table is the map. The sections below work through the rows
that matter most.
| Episode | In the notebook | From the terminal |
|---|---|---|
| Controllers, Training |
sagemaker.Session(),
get_execution_role()
|
aws sts get-caller-identity, and the role ARN is the
RoleArn field of any job you launched |
| Training | helpers.get_notebook_instance_info(name, region) |
aws sagemaker describe-notebook-instance --notebook-instance-name <name> |
| Accessing S3 |
s3.upload_file, s3.download_file,
helpers.show_bucket(bucket)
|
aws s3 cp, aws s3 sync,
aws s3 ls --recursive
|
| Training, PyTorch | xgboost_estimator.fit({'train': train_input}) |
aws sagemaker create-training-job --cli-input-json file://train-xgboost.json
(section 5) |
| Training |
fit(wait=True), the default |
aws sagemaker wait training-job-completed-or-stopped --training-job-name <name> |
| Training | job_cost_report(job_name, price) |
aws sagemaker describe-training-job --training-job-name <name>
(section 2) |
| Hyperparameter tuning | tuner.fit(...) |
aws sagemaker create-hyper-parameter-tuning-job --cli-input-json file://... |
| Hyperparameter tuning |
tuning_cost_report(tuner, price),
tuner.best_training_job()
|
aws sagemaker list-training-jobs-for-hyper-parameter-tuning-job,
describe-hyper-parameter-tuning-job --query BestTrainingJob.TrainingJobName
|
| PyTorch, Hyperparameter tuning, Fine-tuning |
helpers.estimate_training_cost(...),
helpers.estimate_tuning_cost(...),
helpers.estimate_finetune_cost(...)
|
the same functions from a laptop (section 5) |
| Fine-tuning |
helpers.check_launch(...),
helpers.check_finetune_launch(...)
|
python scripts/check_request.py <request>.json --max-cost <dollars>
(section 5) |
| RAG with Processing jobs |
rag_processor.run(...),
describe_processing_job(...)
|
aws sagemaker create-processing-job --cli-input-json file://...,
aws sagemaker describe-processing-job --processing-job-name <name>
|
| RAG with Bedrock |
bedrock.list_inference_profiles(typeEquals="APPLICATION"),
bedrock_runtime.converse(...)
|
aws bedrock list-inference-profiles --type-equals APPLICATION,
aws bedrock-runtime converse --model-id <profile ARN> ...
|
| Cleanup |
sm.list_notebook_instances(),
bedrock.delete_inference_profile(...)
|
aws sagemaker list-notebook-instances,
aws bedrock delete-inference-profile --inference-profile-identifier <ARN>
(section 3) |
The SDK’s job classes (XGBoost, PyTorch,
HuggingFace, HuggingFaceProcessor,
HyperparameterTuner) are builders for the JSON these
commands take. describe-* on any job you launched from a
notebook prints that JSON back, which is how section 5 gets its
file.
What to replace in the commands
Anything in angle brackets, <like this>, is a
value of yours. Replace it, brackets included. This table lists every
placeholder in the episode and how to find its value.
| Placeholder | What it is | Where to find it |
|---|---|---|
<notebook-instance-name>, then
$NB
|
The name you gave your notebook instance in the controllers episode | The first column of
aws sagemaker list-notebook-instances in section 2, where
it is set once as $NB
|
<your-bucket>, then $BUCKET
|
The bucket you created in the S3 episode |
aws s3 ls prints every bucket you can see; set once as
$BUCKET in section 2 |
<a training job name> |
Any training job you ran | The list command in section 2, or the name the training notebook
printed when fit() ran |
<your xgboost job name> |
The XGBoost job from the training episode, named
<notebook-instance-name>-xgboost-<timestamp>
|
aws sagemaker list-training-jobs --name-contains xgboost --query 'TrainingJobSummaries[].TrainingJobName' |
<name> in section 3 |
A job or notebook instance to stop | The lists in section 2 |
<image>, <role>,
<code>
|
The container, the role and the uploaded code of the XGBoost job | Printed by the describe-training-job command at the
start of section 5 |
<LastnameFirstname>,
<ChallengeName>
|
Your Name and Project tag values |
The same values you put on your bucket and your notebook instance |
<ARN> |
A Bedrock inference profile’s ARN | The second column of
aws bedrock list-inference-profiles in section 3 |
Read this before the first command
Nothing here is more powerful than a notebook cell. The difference is that a terminal shows nothing unless you ask. A notebook instance left running is visible in the console the next day, and an endpoint created from a terminal on a Friday is not noticed until the bill arrives. A past participant of this workshop spent a large share of a year’s credits that way. Three rules apply on the shared account and are worth keeping on your own.
-
Authenticate with
aws sso loginonly. Neveraws configurewith an access key ID and secret. Those are long-lived, and they end up in shell histories and committed files. -
Launch only jobs (training, processing, tuning),
with the same three tags and the same
MaxRuntimeInSecondsthe notebooks always set. Jobs end automatically. Endpoints, EC2 instances and GPU notebook instances do not, and the lesson never creates them from the CLI, or at all. -
A refused
createcommand is the account’s rules, not a fault. The workshop account carries a guard-rail policy that denies endpoint and EC2 creation, instance types outside the lesson’s list, caps over 48 hours, and any job whose three tags are missing, blank or off theProjectandPurposelists. The administrator attaches that policy, to the notebook role and to the permission set your laptop signs in with. You attach nothing. If acreatecommand is refused, that policy is why, and AWS says onlyAccessDenied. The checker in section 5 applies the same rules to a request before it is sent, so you see the reason instead. (Instructors: the policy and where it is attached are on the Account preparation checklist page.)
1. Sign in with Identity Center
This episode runs from your own laptop, in a terminal, so it works when no notebook is open. CloudShell and the SageMaker notebook instance already have the AWS CLI installed, and on the instance it uses the instance’s role, so there is no sign-in. On a laptop you install the CLI and sign in yourself.
- Install AWS CLI v2 from the installer for your operating system. Then open a terminal, Terminal on macOS, Git Bash or PowerShell on Windows, and check that it is on your path:
-
Register the account’s Identity Center, once. Run
the command below in the same terminal and answer its prompts in this
order. A profile is a named set of these answers, saved in
~/.aws/configon your laptop, so that the CLI knows which account, role and region a command is for. One laptop can hold several, one per account you use.
| Prompt | Answer |
|---|---|
| SSO session name | workshop |
| SSO start URL | Your sign-in link from the instructor’s email, up to and including
/start, with nothing after it (for UW-Madison it begins
with https://uw-madison and ends in
awsapps.com/start) |
| SSO region | The region Identity Center runs in, from the same email
(us-east-2 for UW-Madison). It is not always the account’s
working region |
| SSO registration scopes | Enter, for the default |
| A browser tab opens | Sign in with your university login if asked. On the page headed Allow botocore-client-workshop to access your data?, choose Allow access |
| Account | The workshop account, whose ID is in the sign-in email. If your login has only one, the CLI picks it for you |
| Role | The permission set your login carries (for UW-Madison, the one with
sagemaker in its name). If there is only one, the CLI picks
it |
| Default client region |
us-east-2 for the workshop account |
| Default output format | Enter, which is json
|
| Profile name |
workshop, in place of the long default it offers, since
the rest of the episode uses that name |
The wizard ends by printing
aws sts get-caller-identity --profile workshop. That is the
identity check from the next block.
The role here is the permission set, not the notebook role. The
permission set is the identity you sign in with, the same one the
console uses. The notebook role, ml-sagemaker-use, is what
a job runs as, and it stays in the job’s RoleArn in section
5.
The commands in this episode are the same in Bash (macOS, Linux, Git Bash on Windows) and in PowerShell. Where the shell’s own syntax differs, variables, line continuation, writing a file, the two are shown as tabs.
From then on, every session starts with three commands. The login
fetches credentials for the profile, which takes you through the browser
once more. Setting AWS_PROFILE makes every later command in
that terminal use the profile without a --profile flag on
each one. The identity check confirms that you are who you think you
are, in the account you think you are in:
The login ends with
Successfully logged into Start URL: .... The identity check
prints the account ID and an Arn that names an
AWSReservedSSO_... role, the permission set, and ends with
your email. Check the region too, since SageMaker resources are regional
and a job in another region does not appear in any list:
BASH
aws configure get region # us-east-2 for the workshop account; if it is wrong, run aws configure sso again
The credentials expire after a few hours. Run
aws sso login again when a command returns
ExpiredToken. Nothing that would still work next month is
written anywhere.
If you are in the notebook instance’s own terminal instead (JupyterLab, File → New → Terminal), skip the install and the sign-in. The instance’s role is already the identity, and every command below works there as written.
The sections below are the AWS commands, so that you see what the SDK
was doing. Most of the lesson’s helpers wrapped one of these calls and
are not needed here. The ones that do arithmetic, the cost estimators
and the launch check, come back in section 5, from the lesson’s
scripts/helpers.py, plain Python that runs on a laptop as
it did on the notebook instance. Clone the lesson once and install
boto3, which the module imports:
2. What is running, and what a job cost
First the lists. Each should be short, or empty. --query
is a JMESPath filter that keeps the
output to what you asked about, and the cleanup episode’s first cell ran
the same four list_* calls through boto3.
BASH
aws sagemaker list-training-jobs --status-equals InProgress --query 'TrainingJobSummaries[].TrainingJobName'
aws sagemaker list-processing-jobs --status-equals InProgress --query 'ProcessingJobSummaries[].ProcessingJobName'
aws sagemaker list-hyper-parameter-tuning-jobs --status-equals InProgress --query 'HyperParameterTuningJobSummaries[].HyperParameterTuningJobName'
aws sagemaker list-notebook-instances --query 'NotebookInstances[].[NotebookInstanceName,NotebookInstanceStatus,InstanceType]' --output table
aws sagemaker list-endpoints # must print an empty list on the workshop account
Your notebook instance is in the fourth list, and
aws s3 ls prints your bucket. Those two names come up in
most commands below, so set them as shell variables once per terminal
session, after the login, and the commands use $NB and
$BUCKET from here on:
Then one job’s bill. job_cost_report() in the training
episodes called describe_training_job and read four fields
from it, the status, the instance count,
BillableTimeInSeconds, and the model’s S3 path, and
computed the wall-clock from CreationTime and
TrainingEndTime. This is the same call with the same
fields. Pick a job from the list below, newest first with its status,
and put its full name in place of
<a training job name>. On the shared account the list
is everyone’s jobs, so do not take the newest. Take the one named after
your notebook instance:
BASH
aws sagemaker list-training-jobs --sort-by CreationTime --sort-order Descending --query 'TrainingJobSummaries[].[TrainingJobName,TrainingJobStatus]' --output table
# only your own, since the lesson names every job after its notebook instance: filter on that name
# aws sagemaker list-training-jobs --name-contains $NB --sort-by CreationTime --sort-order Descending --query 'TrainingJobSummaries[].[TrainingJobName,TrainingJobStatus]' --output table
# the same list in name order, which groups each learner's jobs together
# aws sagemaker list-training-jobs --sort-by Name --sort-order Ascending --query 'TrainingJobSummaries[].[TrainingJobName,TrainingJobStatus]' --output table
Cost is billable_s × count ÷ 3600 × the
hourly rate from the Instances
for ML page, the arithmetic job_cost_report() did. The
helper printed it. Here you do the multiplication.
billable_s can be missing for a job that failed. Read the
status and FailureReason before reading anything into its
cost.
The other job kinds have the same shape. The Processing Jobs
episode’s job_cost() read CreationTime,
ProcessingStartTime and ProcessingEndTime from
describe_processing_job, and the tuning episode’s
tuning_cost_report() looped
describe_training_job over the tuner’s child jobs:
BASH
aws sagemaker describe-processing-job --processing-job-name <name> --query '{status:ProcessingJobStatus, created:CreationTime, started:ProcessingStartTime, ended:ProcessingEndTime, instance:ProcessingResources.ClusterConfig.InstanceType}'
aws sagemaker list-training-jobs-for-hyper-parameter-tuning-job --hyper-parameter-tuning-job-name <name> --query 'TrainingJobSummaries[].[TrainingJobName,TrainingJobStatus,FinalHyperParameterTuningJobObjectiveMetric.Value]' --output table
aws sagemaker describe-hyper-parameter-tuning-job --hyper-parameter-tuning-job-name <name> --query 'BestTrainingJob.TrainingJobName' # tuner.best_training_job()
Tags are returned by a separate call. The Name tag is
how you confirm a job is yours before you stop it in the next section,
and a job with no tags is the one that shows on the bill under “No tag
key”:
3. Stopping jobs and notebook instances
Each of these stops a charge. They are the calls behind the
Stop buttons the cleanup episode walks through in the
console. Every one takes a name, and on a shared account the name must
be yours. The lists in section 2 show everyone’s jobs and instances.
Before any stop command, confirm the Name tag with the
list-tags call from section 2, and stop only what you
started. Someone else’s job is a question for them, or for the
instructor.
BASH
aws sagemaker stop-training-job --training-job-name <name>
aws sagemaker stop-processing-job --processing-job-name <name>
aws sagemaker stop-hyper-parameter-tuning-job --hyper-parameter-tuning-job-name <name> # stops every child job
aws sagemaker stop-notebook-instance --notebook-instance-name <name>
A stopped job keeps its logs and whatever it had already written to
S3. A stopped notebook instance keeps
/home/ec2-user/SageMaker/ and keeps billing for that
volume. Deleting the instance is the step that stops the storage charge,
and the cleanup episode’s last two items, the bucket and the Bedrock
inference profiles, have their CLI forms too:
BASH
aws sagemaker delete-notebook-instance --notebook-instance-name <name> # only after it reports Stopped
aws s3 rb s3://$BUCKET --force # empties the bucket, then deletes it; the cleanup episode's delete_objects loop plus delete_bucket
aws bedrock list-inference-profiles --type-equals APPLICATION --query 'inferenceProfileSummaries[].[inferenceProfileName,inferenceProfileArn]' --output table
aws bedrock delete-inference-profile --inference-profile-identifier <ARN> # one per profile, as the cleanup episode's loop did
4. Copying to and from S3
The Accessing S3 episode moved single files with
s3.upload_file and s3.download_file and listed
the bucket with helpers.show_bucket. For many files, or for
pulling a job’s outputs down to a laptop, the CLI is the better tool,
and these are the same keys those episodes used:
BASH
aws s3 ls s3://$BUCKET/ --recursive --human-readable --summarize # helpers.show_bucket, for the whole bucket
aws s3 cp titanic_train.csv s3://$BUCKET/titanic_train.csv # s3.upload_file(train_filename, bucket_name, train_filename)
aws s3 cp s3://$BUCKET/xgboost/<job-name>/output/model.tar.gz model.tar.gz # the download in the training episode's evaluate step
aws s3 sync s3://$BUCKET/xgboost/ ./xgboost-outputs/ # every job's outputs under the prefix; only new or changed files move
aws s3 rm s3://$BUCKET/scratch/ --recursive # delete a prefix; this one asks no questions
The last line, sync --delete and the
rb --force in section 3 remove data for good and ask
nothing first. Check the bucket name twice before any of them, and on
the shared account run them only on your own bucket.
Downloads to a laptop are a transfer out of AWS ($0.09
per GB). For anything larger than a few hundred megabytes, keep the data
in the region and let a job read it, which is the lesson’s pattern.
5. Launching the training episode’s job from a JSON file
xgboost_estimator.fit({'train': train_input}) in the
training episode assembled a JSON request and sent it to
CreateTrainingJob. SageMaker kept that request, and
describe-training-job on the job you ran prints it back.
Three fields come from there, because they are specific to your account
and region, and the rest of the file below is the estimator’s arguments
under their API names.
First find the job’s name. The training episode named it after your
notebook instance, so it is the one with xgboost in it:
BASH
aws sagemaker list-training-jobs --name-contains "$NB-xgboost" --query 'TrainingJobSummaries[].TrainingJobName'
Put that name in place of <your xgboost job name>
below.
The describe output is a description, not a request. It carries fields AWS fills in after the fact, so it cannot be saved and sent back as it is, which is why the file below is written out from the estimator’s arguments and takes only three values from the description.
image is the XGBoost 1.7-1 container that
framework_version="1.7-1" picked. role is the
role the notebook printed. code is where
fit() uploaded source_dir, the
sourcedir.tar.gz in the SDK’s default bucket that the
training episode pointed out under What landed in S3. Reusing
it means this job runs the same train_xgboost.py the
notebook’s job ran. Save the file below as
train-xgboost.json, in the folder your terminal is in, with
any text editor. The file is the same whichever shell you use, and a
file cannot read shell variables, so the two names are written out in
it. Put the three values in place of <image>,
<role> and <code>, your bucket in
place of <your-bucket>, your notebook instance’s name
in TrainingJobName, and your tag values in place of
<LastnameFirstname> and
<ChallengeName>. The code value prints
with quotation marks inside it; put only the s3://... path
in place of <code>, since the file supplies the
quotes. The -cli-1 suffix makes the job name unique; use
-cli-2 for a second run, since SageMaker refuses a name it
has seen.
JSON
{
"TrainingJobName": "<notebook-instance-name>-xgboost-cli-1",
"AlgorithmSpecification": {
"TrainingImage": "<image>",
"TrainingInputMode": "File"
},
"RoleArn": "<role>",
"HyperParameters": {
"train": "\"titanic_train.csv\"",
"max_depth": "3",
"eta": "0.1",
"subsample": "0.8",
"colsample_bytree": "0.8",
"num_round": "100",
"sagemaker_program": "\"train_xgboost.py\"",
"sagemaker_submit_directory": "\"<code>\"",
"sagemaker_region": "\"us-east-2\"",
"sagemaker_container_log_level": "20"
},
"InputDataConfig": [
{
"ChannelName": "train",
"ContentType": "csv",
"DataSource": { "S3DataSource": {
"S3DataType": "S3Prefix",
"S3Uri": "s3://<your-bucket>/titanic_train.csv",
"S3DataDistributionType": "FullyReplicated" } }
}
],
"OutputDataConfig": { "S3OutputPath": "s3://<your-bucket>/xgboost/" },
"ResourceConfig": { "InstanceType": "ml.m5.large", "InstanceCount": 1, "VolumeSizeInGB": 30 },
"StoppingCondition": { "MaxRuntimeInSeconds": 1200 },
"Tags": [
{ "Key": "Name", "Value": "<LastnameFirstname>" },
{ "Key": "Project", "Value": "<ChallengeName>" },
{ "Key": "Purpose", "Value": "Training" }
]
}
Read it against the estimator cell in the training episode. Every field is one of its arguments:
| In the estimator | In the JSON |
|---|---|
base_job_name=f"{notebook_instance_name}-xgboost" plus
the SDK’s timestamp |
TrainingJobName, which you write out in full |
framework_version="1.7-1" |
AlgorithmSpecification.TrainingImage |
role=role |
RoleArn |
hyperparameters={'train': train_file, 'max_depth': max_depth, ...} |
HyperParameters, the same six keys and values, as
strings |
entry_point='train_xgboost.py',
source_dir=.../scripts
|
sagemaker_program and
sagemaker_submit_directory, which the SDK adds to the
hyperparameters so the container knows what to run |
TrainingInput(train_s3_path, content_type='csv') and
fit({'train': ...})
|
InputDataConfig, one channel named
train
|
output_path=f's3://{bucket_name}/xgboost/' |
OutputDataConfig.S3OutputPath |
instance_type="ml.m5.large",
instance_count=1
|
ResourceConfig, with the SDK’s default 30 GB
volume |
max_run=20*60 |
StoppingCondition.MaxRuntimeInSeconds, 1200 |
tags=job_tags |
Tags, the same three keys |
The string values with escaped quotes,
"\"titanic_train.csv\"", are how the SDK encodes a text
hyperparameter, and the container decodes them before they reach
argparse in the script, so
--train titanic_train.csv arrives as it did from the
notebook. Numbers are plain strings.
Before sending it, estimate it, as the notebooks did before every
launch. Nothing in a JSON file prints a price, so the hand method is the
instance’s hourly rate from the Instances
for ML page times the minutes you expect, and
MaxRuntimeInSeconds at about twice that. This XGBoost job
is startup and little else, two to three minutes on
ml.m5.large, under a cent. For a job with real compute the
lesson’s estimators do the arithmetic, with the same arguments the
notebooks gave them. They are called from python -c, with
the lesson’s scripts folder put on the path first. These are the PyTorch
episode’s estimate, the tuning episode’s and the fine-tuning episode’s,
and each prints the time, the cost and the max_run to put
in the request:
BASH
python -c "import sys; sys.path.insert(0, 'ML_with_AWS_SageMaker/scripts'); import helpers; helpers.estimate_training_cost(params_billions=0.125, examples=1_000_000, tokens_per_example=256, epochs=3, instance_type='ml.g6.xlarge')"
python -c "import sys; sys.path.insert(0, 'ML_with_AWS_SageMaker/scripts'); import helpers; helpers.estimate_tuning_cost(train_minutes_per_job=1, price_per_hour=0.115, max_jobs=8)"
python -c "import sys; sys.path.insert(0, 'ML_with_AWS_SageMaker/scripts'); import helpers; helpers.estimate_finetune_cost(params_billions=3.75, examples=251, tokens_per_example=1600, epochs=2, instance_type='ml.g5.xlarge')"
Then check the request. scripts/check_request.py reads
the JSON and does two things. It applies the account’s rules from
scripts/guardrails.json, as
helpers.check_launch did before every launch in the
notebooks, so a Project or Purpose off the
lists, an instance type off the list or a cap over 48 hours is named
here, where AWS would refuse it silently. Then it prints the most the
request can bill: every instance it asks for, running to its cap, at the
instance’s hourly price, and for a tuning job every child job it allows.
--max-cost is a dollar amount you choose, the most you are
willing to spend on this job. When the worst case is above it, the
checker exits with an error, and the launch command below is written so
that an error stops it. Here it is 1, one dollar, because
the job’s worst case is four cents:
BASH
python ML_with_AWS_SageMaker/scripts/check_request.py train-xgboost.json --max-cost 1 # refuse if this job could bill more than $1
OUTPUT
train-xgboost.json: tags, instance type and cap pass the account's rules
worst case if every job runs to its cap: 1 x 0.33 h x $0.115/h = $0.04
The same command takes a Processing job’s or a tuning job’s request,
and the tuning job’s worst case multiplies by its
MaxNumberOfTrainingJobs, which is where a tuning request
surprises people.
The check catches configuration and cost mistakes before a request reaches AWS. It does not grant permission to launch the job or guarantee that AWS accepts it. The account’s own policy decides that, and on the shared workshop account the rule is the one above, launch from the notebook instance.
Then send it. This one line is estimator.fit(), and the
&& in front of it means the create call runs only
when the check passed:
BASH
python ML_with_AWS_SageMaker/scripts/check_request.py train-xgboost.json --max-cost 1 && aws sagemaker create-training-job --cli-input-json file://train-xgboost.json
The CLI returns the moment the request is accepted. Nothing waits,
which is fit(wait=False). To follow the job the way the
default wait=True did, then read its bill as in section
2:
BASH
aws sagemaker wait training-job-completed-or-stopped --training-job-name "$NB-xgboost-cli-1" # blocks until it ends
aws sagemaker describe-training-job --training-job-name "$NB-xgboost-cli-1" --query '{status:TrainingJobStatus, billable_s:BillableTimeInSeconds, failure:FailureReason, model:ModelArtifacts.S3ModelArtifacts}'
Expect the same two to three billable minutes on
ml.m5.large as the notebook’s job, under a cent, and the
same xgboost-model.json inside the
model.tar.gz it names.
The PyTorch job, a Processing job and a tuning job follow the same
route. describe-training-job,
describe-processing-job and
describe-hyper-parameter-tuning-job on the ones you ran
print the request, and create-training-job,
create-processing-job and
create-hyper-parameter-tuning-job take it back with
--cli-input-json. A PyTorch job’s
HyperParameters carries epochs and
learning_rate and two input channels. A Processing job’s
AppSpecification.ContainerArguments is the
arguments= list. A tuning job’s file has the estimator’s
request nested under TrainingJobDefinition and the ranges
under HyperParameterTuningJobConfig.ParameterRanges.
What the lesson never does from the CLI
-
aws sagemaker create-endpoint/create-endpoint-config: an endpoint is a server that runs until you delete it, with no runtime cap. The lesson serves models with processing jobs and Bedrock so that nothing of this kind exists in the account. -
aws sagemaker create-notebook-instancewith a GPU type: a GPU notebook is$60a day while you are asleep. The optional GPU-notebook episode creates one through the console, where it stays visible, and deletes it the same session. -
aws ec2 run-instances: bare virtual machines have no tags required, no runtime cap and no SageMaker job list to appear in.
On the workshop account all three are denied by the guard-rail policy the administrator attached, as is any instance type outside the lesson’s list, any cap over 48 hours and any job whose tags are missing or off the lists. On your own account, the policy is on the instructor page Account preparation checklist. Attaching it to your own user or role takes an afternoon and is worth it.
Challenge: what is still running on Friday evening
You are leaving for the weekend and have a terminal, not a browser. Write the commands you would run, in order, to make sure nothing of yours is costing money until Monday, and the one command to run if a check finds something. Then run them.
BASH
aws sagemaker list-training-jobs --status-equals InProgress --query 'TrainingJobSummaries[].TrainingJobName'
aws sagemaker list-processing-jobs --status-equals InProgress --query 'ProcessingJobSummaries[].ProcessingJobName'
aws sagemaker list-hyper-parameter-tuning-jobs --status-equals InProgress --query 'HyperParameterTuningJobSummaries[].HyperParameterTuningJobName'
aws sagemaker list-notebook-instances --query 'NotebookInstances[?NotebookInstanceStatus==`InService`].NotebookInstanceName'
aws sagemaker list-endpoints --query 'Endpoints[].EndpointName'
For anything of yours the first four print, confirm it with
list-tags and run the matching stop-...
command from section 3. A job you expect to finish within its
MaxRuntimeInSeconds can be left. A job that is not yours is
its owner’s, and the tags say who that is. For an endpoint,
aws sagemaker delete-endpoint --endpoint-name <name>,
then find out how it was created, because on the workshop account the
guard-rail policy refuses it. Buckets cost almost nothing over a weekend
and need no action.
- The CLI, the SDK and the console are one API. Every call the
notebooks made has a CLI command with the same name and fields, and
describe-*on a job you ran prints the request the SDK built. - The CLI shows you nothing you do not ask for, so its first use is to look and to stop, not to launch.
- Authenticate with
aws sso loginand short-lived credentials. Never store an access key. -
describe-training-jobisjob_cost_report(). Cost is billable seconds × instance count × the hourly rate, and you do the multiplication. - A
create-training-jobJSON is whatestimator.fit()sent, the same script, hyperparameters, channel, cap and tags, with no price printed next to it. - Endpoints, EC2 instances and GPU notebooks are not jobs and do not end. The workshop account’s notebook role denies creating them, and your own account should too.