Key Points
Overview: ML on AWS
- The cloud offers the current GPU generation on demand, billed per second while a job runs. Campus and national research computing is often cheaper for sustained work, and free to many researchers.
- Cost and energy efficiency depend on the hardware generation, how busy it is kept, and the data center’s overhead.
- S3 stores the datasets and results. A small SageMaker notebook instance is the workspace.
- SageMaker runs training, tuning, processing and inference jobs on instances that exist only for the job.
- Bedrock gives API access to hosted models, with no GPU instance to manage.
Data Storage: Setting up S3
Use S3 for scalable, cost-effective, and flexible storage.
EC2 storage is fairly uncommon, but may be suitable for small, temporary datasets; only
/home/ec2-user/SageMakersurvives a Stop, and nothing survives a Delete.Create the bucket in the same region as your SageMaker notebook, and tag it with the same three keys (
Name,Project,Purpose) you will put on every other resource.Track your S3 storage costs, data transfer, and requests to manage expenses.
Regularly delete unused data or buckets to avoid ongoing costs.
Notebooks as Controllers
- Use a minimal SageMaker notebook instance as a controller to manage larger, resource-intensive tasks.
- The notebook does not do the heavy computation; later episodes use it to launch training, tuning and processing jobs on separate instances.
- Every resource gets the same three tags; they never propagate, so each new resource needs its own.
- Stop the notebook instance at the end of class, and delete it when the workshop is over.
Accessing and Managing Data in S3 with SageMaker Notebooks
- Read S3 objects into memory with
get_object; copy one to the instance’s disk withdownload_fileonly when a program needs it as a file. - Periodically check storage usage and costs to manage S3 budgets.
- Write outputs back to your bucket under a prefix, and read the bucket’s size from the notebook to see what accumulates.
- The lesson repository lives at
/home/ec2-user/SageMaker/ML_with_AWS_SageMaker/; every later episode adds itsscripts/folder tosys.pathand importshelpers.
(Optional) Pushing Your Notebooks to GitHub from SageMaker
- Your own work belongs in your own repository: create one on GitHub,
git inita folder under/home/ec2-user/SageMaker/, and connect the two withgit remote add. - Authenticate over HTTPS with a scoped, expiring Personal Access
Token entered through
getpass; nothing is saved on the instance, and the token is revoked when you are done. - Version
.pycopies of notebooks (Jupytext converts both ways) and ignore*.ipynb, caches and data archives in.gitignore. - Pull before you push; the first pull into a freshly initialized
folder needs
--allow-unrelated-histories.
Training Models in SageMaker: Intro
- Setup: a SageMaker session, the execution role and the bucket name are what every job needs from the notebook.
- Local vs. managed training: Always test your code locally (on a smaller scale) before scaling things up. This avoids wasting resources on buggy code that doesn’t produce reliable results.
-
Estimators:
XGBoost(entry_point=...)is AWS’s container running your script, the pattern every later episode uses withPyTorchandHuggingFace. -
Training data channels:
TrainingInputnames the S3 data a job copies onto its instance before the script runs. - Estimate the cost before launching (rate × minutes, startup
included), then read back
BillableTimeInSecondswithjob_cost_report()after every job and compare. -
Long runs: launch with
wait=Falseand carry on, or stop the notebook instance; the job runs and finishes without it, andjob_cost_report(job_name, ...)reads its bill later. Setmax_runa little above the estimate, and checkpoint to S3 on anything longer than half an hour.
Training Models in SageMaker: PyTorch Example
- Startup dominates small jobs: Every SageMaker training job waits a minute or so for an instance (not billed), then spends one to three minutes on container pull and data download (billed) before the script runs; for a job whose script finishes in seconds, that overhead is the whole bill.
-
Estimate before you launch: for small models, time
a short run and scale it by epochs and rows, plus about three minutes of
startup; for large ones, 6 FLOPs per parameter per token, divided by a
quarter of the GPU’s peak.
helpers.estimate_training_costdoes the second; write the number down and compare it to the bill. -
GPU or CPU is a measurement: the same script on an
ml.g4dn.xlargewas slower and dearer than on anml.m5.largefor this network, because the step is too small to keep a GPU busy; the GPU pays when the model and batch are large. -
More than one machine is the last move: a faster
single device first, then more GPUs in one box, then more instances.
instance_count=2on its own runs the whole job twice and bills twice; data parallelism needsdistribution=on the estimator and, for your own script, three additions: join the process group, shard the rows, wrap the model in DDP. -
Parallelism pays when the step’s computation is large next
to the gradient exchange: big model, big batch, fast link.
helpers.estimate_parallel_speedupgives the speedup and the cost ratio before you rent the devices; on 569 rows of tabular data the measured result was 0.85x the speed at 2.4x the cost.
Hyperparameter Tuning in SageMaker: Neural Network Example
-
Tuner = estimator + ranges + objective: A
HyperparameterTunerwraps an ordinary estimator; the script only has to print the objective metric in a format themetric_definitionsregex can capture. -
Start with one job:
max_jobs=1, max_parallel_jobs=1first, to catch script and configuration errors before paying for a search. -
Parallelism buys time, not quality: Cost is per
child training job;
max_parallel_jobschanges wall-clock time and, with the Bayesian strategy, how much each job can learn from the ones before it. 2-4 parallel jobs is a good default. - Tags propagate from the tuner: tags on the tuner are copied to every child training job.
-
Estimate the whole search before launching it:
helpers.estimate_tuning_costtakes the tuner’s own limits and one child job’s billable minutes; startup is paid once per parallel slot, which is why two at a time is cheaper than ten at once. -
Read the bill from the child jobs: SageMaker bills
per second of
BillableTimeInSecondsx instance count on each training job; container pull and data download are inside that number and dominate short jobs. -
Transform the test set with the training scaler:
Load the saved scaler and pass it to
preprocess_data(test_df, scaler=scaler); never refit on test data.
Fine-tuning a Vision-Language Model with Training Jobs
- Fine-tuning cost is GPU-hours × hourly rate, and GPU-hours scale with model size × tokens × epochs × attempts. The same recipe runs from under a dollar (3B, LoRA, a few hundred pages) to tens of thousands (70B, full fine-tune, days on multi-GPU nodes). Starting from a model that already knows most of the task is the biggest saving available.
- Training jobs, not GPU notebooks, are the safe way to run it: they
end,
max_runguarantees it, a uniquejob_nameprevents a second copy launching by accident, and checkpoints synced to S3 mean a killed job costs an epoch, not the run. Interrupting a notebook cell does not stop a job. - Estimate before launching (startup overhead + pages × epochs ×
seconds per page, at the instance’s rate), then compare to
BillableTimeInSeconds. - Image resolution (
max_pixels) and epochs change cost by multiples; the instance size changes it by 5–45x, which is right when the model does not fit on one GPU and waste when it does. - Score the holdout at the end of every epoch: the curve, not a rule of thumb, says how many passes were worth paying for. Measure the gain on the same held-out pages before and after, with the task’s own metric, and a page-level holdout is optimistic when the real test is split by document.
Overview of RAG Workflows on AWS
- RAG is inference only. Nothing is trained or fine-tuned, so running one does not need a GPU of your own.
- Bedrock is the default for inference: you pay per token, nothing runs between calls, and there is nothing to forget to shut down.
- Self-managed GPU compute (Processing jobs, notebook GPUs, inference endpoints) is for a model Bedrock does not offer, or for batch volumes so large that per-token pricing loses; it is not a starting point.
- Of the GPU options, Processing jobs are the safest, because the instance ends itself; notebook GPUs and endpoints bill by the hour until you stop them.
- A forgotten GPU instance costs tens of dollars overnight and hundreds to thousands over a month; a full WattBot run on Bedrock costs under a dollar.
- Tags never propagate. Tag every job at launch and route Bedrock calls through a tagged application inference profile, or the spend cannot be traced.
- The hands-on episodes start with Bedrock, then the same pipeline on Processing jobs; the notebook-GPU version is optional self-study.
RAG with Bedrock
- A complete RAG pipeline on AWS needs no GPU. A CPU notebook plus Bedrock-hosted embedding and generation models is enough.
- Corpus preparation (unpacking the staged PDFs, page extraction,
chunking) is cheap CPU work; cache
chunks.jsonlon S3 so later episodes and runs can reuse it. - Bedrock calls carry no tags; route them through a tagged application inference profile or the spend is anonymous on the bill.
-
converseis the provider-neutral way to call a chat model on Bedrock; itsusageblock is what you are billed on. DeepSeek V3 is the generator here, and any catalog model is a one-line swap. - Bedrock bills per token and leaves nothing running between calls, which is why it is the default route for RAG inference.
- The model is one tunable component; most accuracy gains come from chunking, retrieval, and post-processing.
RAG with Processing Jobs
- Bedrock’s catalog is curated and lags releases; when you need a specific open-weight model you rent a GPU and serve it yourself.
- Of the ways to rent a GPU, a Processing job is the one that cannot
be forgotten. It bills while the script runs and ends on its own, with
max_runtime_in_secondsas the backstop. Use it for batch work; use Bedrock or an endpoint when you need answers in seconds. - Inference needs only the weights. Qwen3-8B is small enough to run unquantized, ~16 GB in bf16 on one 24 GB GPU, with the rest for the prompts’ attention cache; how many prompts decode together is bounded by that remainder. Larger models are quantized to fit.
- A job’s inputs and outputs are S3 prefixes mounted into the container; the notebook only stages files and reads results, so it stays a cheap CPU instance.
- The pipeline logic (
wattbot_rag.py) ships with the job unchanged from the Bedrock episode; only the two model callables differ. - Tags do not propagate from the notebook. Every job gets its own
tags=.
(Optional) RAG with a Notebook GPU
- Why self-host at all: Bedrock’s catalog is curated and lags releases; most open-weight models (including Qwen3.8-27B) are not on it. When the model you need is not offered, you rent a GPU and serve it yourself.
-
Inference uses reduced-precision weights: no
gradients means the weights are the memory cost. FP8 puts a 27B model on
one 48 GB GPU (
ml.g6e.xlarge); bf16 would need 54 GB, an 80 GB GPU or a multi-GPU instance. -
The meter never stops on its own:
ml.g6e.xlargeis$2.61/h,$167per forgotten weekend,$1,906per forgotten month, plus$14/month for the storage volume even when stopped. Stop it when you stand up; delete it when the episode is over. - Retrieval is a matrix multiply: cosine similarity over the in-memory embedding matrix is enough for a corpus this size; a vector database is the same step for a corpus of millions.
-
Units come from the data:
answer_unitis copied fromtrain_QA.csv, never guessed by the model. - Two calls per question: one answers and cites; a second, shorter one writes the explanation and names the evidence type.
-
The competition’s format:
is_blankmarks unanswerable questions and missing fields, as the scorer expects.
(Optional) The Same Jobs from the Terminal
- 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.
Resource Management and Monitoring
Always stop or delete notebook instances when not in use to avoid charges.
Stop any training, tuning or Processing job you no longer need.
Bedrock application inference profiles are not swept by the instructors’ aws-nuke run; remove them yourself.
The refusals you met in this workshop (untagged jobs, wrong instance types, endpoints) are IAM deny rules an administrator attached to the role, not SageMaker defaults; on an account you administer, the instructor pages have the policy to copy.
Regularly clean up unused S3 buckets and objects to save on storage costs.
Monitor your expenses through the AWS Billing Dashboard and set up alerts.
Use tags (set up earlier in the workshop) to track and monitor costs by resource.