<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Amr Abed</title>
    <description>The latest articles on DEV Community by Amr Abed (@amrabed).</description>
    <link>https://dev.to/amrabed</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F255832%2F370c895e-a2ce-4332-891b-502808af64e4.png</url>
      <title>DEV Community: Amr Abed</title>
      <link>https://dev.to/amrabed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amrabed"/>
    <language>en</language>
    <item>
      <title>Self-Host an AI Agent Using OpenClaw and WhatsApp Cloud API (2026)</title>
      <dc:creator>Amr Abed</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:40:19 +0000</pubDate>
      <link>https://dev.to/amrabed/self-host-an-ai-agent-using-openclaw-and-whatsapp-cloud-api-2026-36ea</link>
      <guid>https://dev.to/amrabed/self-host-an-ai-agent-using-openclaw-and-whatsapp-cloud-api-2026-36ea</guid>
      <description>&lt;h3&gt;
  
  
  &lt;em&gt;Set up a WhatsApp Business number for your AI agent in under 30 minutes — no third-party providers, no ban risk, using official WhatsApp Cloud&amp;nbsp;API&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fro0wgs23nh7yxbg3xeat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fro0wgs23nh7yxbg3xeat.png" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;OpenClaw +&amp;nbsp;WhatsApp&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You shouldn’t need to pay a middleman just to put your AI agent on WhatsApp — yet that’s the default everyone ends up recommending. After spending days wading through scattered resources, I finally got OpenClaw talking directly to the WhatsApp Cloud API. Here’s the exact path I&amp;nbsp;took.&lt;/p&gt;

&lt;p&gt;In this guide, I am&amp;nbsp;sharing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;How it&amp;nbsp;works&lt;/li&gt;
&lt;li&gt;A Step-by-step Guide&lt;/li&gt;
&lt;li&gt;The resources I&amp;nbsp;used&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;You obviously need &lt;a href="https://openclaw.ai" rel="noopener noreferrer"&gt;OpenClaw&lt;/a&gt; for this. To install it on your Linux/Mac server, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://openclaw.ai/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other installation options, follow the instructions &lt;a href="https://docs.openclaw.ai/install" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Meta Developer Account
&lt;/h4&gt;

&lt;p&gt;You will need to &lt;a href="https://developers.facebook.com/async/registration" rel="noopener noreferrer"&gt;register&lt;/a&gt; as a Meta developer if you are not&amp;nbsp;already.&lt;/p&gt;

&lt;h4&gt;
  
  
  Meta Business Portfolio
&lt;/h4&gt;

&lt;p&gt;You will also need a Meta Business Portfolio. If you don’t have one, you can create it on the &lt;a href="https://business.facebook.com/" rel="noopener noreferrer"&gt;Meta Business&amp;nbsp;Suite⁠&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Public Domain&amp;nbsp;Name
&lt;/h4&gt;

&lt;p&gt;You will need a public domain for WhatsApp to send callback requests to OpenClaw.&lt;/p&gt;

&lt;h3&gt;
  
  
  How It&amp;nbsp;Works
&lt;/h3&gt;

&lt;p&gt;The diagram below shows how the different services communicate with each other while keeping your local server&amp;nbsp;secure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgax7dz0868g5f7r8lg16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgax7dz0868g5f7r8lg16.png" alt="System architecture diagram showing request and response flow between OpenClaw AI agent and WhatsApp Cloud API via a secure tunnel" width="800" height="517"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Request/Response Flow between OpenClaw and&amp;nbsp;WhatsApp&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is how it&amp;nbsp;works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You send a message on&amp;nbsp;WhatsApp&lt;/li&gt;
&lt;li&gt;WhatsApp sends a notification to a webhook running on your server through the&amp;nbsp;tunnel&lt;/li&gt;
&lt;li&gt;The webhook passes the message to your plugin to process and pass to the OpenClaw&amp;nbsp;agent&lt;/li&gt;
&lt;li&gt;The agent processes replies to the message and passes the answer back to the&amp;nbsp;plugin&lt;/li&gt;
&lt;li&gt;The plugin then communicates with the WhatsApp Cloud API to send you back your&amp;nbsp;response&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Step-by-step Guide
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 0 (One-Time Setup): Create a WhatsApp Business&amp;nbsp;Account
&lt;/h4&gt;

&lt;p&gt;From the &lt;a href="https://business.facebook.com/latest/settings" rel="noopener noreferrer"&gt;Business Settings⁠&lt;/a&gt;, create a new WhatsApp account if you don’t have&amp;nbsp;one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;WhatsApp accounts&lt;/strong&gt; from the&amp;nbsp;sidebar&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+ Add&lt;/strong&gt; button in the top-right corner and select &lt;strong&gt;Create a WhatsApp Business&amp;nbsp;account&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter a display name and select a category, e.g., Other. Make sure the display name aligns with the &lt;a href="https://www.facebook.com/business/help/757569725593362" rel="noopener noreferrer"&gt;guidelines&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Use a display name only&lt;/strong&gt; and click &lt;strong&gt;Continue —&lt;/strong&gt;WhatsApp will create a virtual number for&amp;nbsp;you&lt;/li&gt;
&lt;li&gt;Select the new WhatsApp&amp;nbsp;account&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Phone Numbers&lt;/strong&gt;&amp;nbsp;tab&lt;/li&gt;
&lt;li&gt;Click the created phone number to open the &lt;strong&gt;Phone&amp;nbsp;Profile&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;ID&lt;/strong&gt; and store it in a secure place to use&amp;nbsp;later&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Step 1: Create a Meta app &amp;amp; Connect WhatsApp Business&amp;nbsp;account
&lt;/h4&gt;

&lt;p&gt;From the &lt;a href="https://developers.facebook.com/apps" rel="noopener noreferrer"&gt;App Dashboard&lt;/a&gt;, create a new Meta app if you don’t have&amp;nbsp;one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;strong&gt;Create&amp;nbsp;App&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter the app name and contact&amp;nbsp;email&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Connect with customers through WhatsApp&lt;/strong&gt; use&amp;nbsp;case&lt;/li&gt;
&lt;li&gt;Select an existing &lt;strong&gt;Meta Business Portfolio&lt;/strong&gt; or create&amp;nbsp;one&lt;/li&gt;
&lt;li&gt;Review details and click &lt;strong&gt;Create&amp;nbsp;app&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select the app from the App Dashboard&lt;/li&gt;
&lt;li&gt;Expand &lt;strong&gt;App settings&lt;/strong&gt; near the bottom of the sidebar and select&amp;nbsp;&lt;strong&gt;Basic&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Show and copy the &lt;strong&gt;App secret&lt;/strong&gt; and store it in a secure place to use&amp;nbsp;later&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Use cases&lt;/strong&gt; from the&amp;nbsp;sidebar&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Connect with customers through WhatsApp&lt;/strong&gt; and click &lt;strong&gt;Customize&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;API Setup&lt;/strong&gt; section, select the WhatsApp Business&amp;nbsp;Account&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frk24thf2yrriy8s1j6qb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frk24thf2yrriy8s1j6qb.png" width="800" height="691"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;3. Select **Connect with customers through WhatsApp&lt;/em&gt;* use&amp;nbsp;case*&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Generate an API Access&amp;nbsp;Token
&lt;/h4&gt;

&lt;p&gt;From the &lt;a href="https://business.facebook.com/latest/settings" rel="noopener noreferrer"&gt;Business Settings⁠&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;System users&lt;/strong&gt; from the&amp;nbsp;sidebar&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+ Add&lt;/strong&gt; button in the top-right corner to create a system&amp;nbsp;user&lt;/li&gt;
&lt;li&gt;Enter the name for the system user and select a&amp;nbsp;role&lt;/li&gt;
&lt;li&gt;Select the new system user and click &lt;strong&gt;Assign&amp;nbsp;Assets&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;From &lt;strong&gt;Apps&lt;/strong&gt;, select the app and toggle &lt;strong&gt;Test&amp;nbsp;app&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;From &lt;strong&gt;WhatsApp accounts&lt;/strong&gt;, select the account and toggle &lt;strong&gt;Everything&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Assign assets&lt;/strong&gt;&amp;nbsp;button&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Generate token&lt;/strong&gt; button to generate the API&amp;nbsp;token&lt;/li&gt;
&lt;li&gt;Add the following permissions to the token: &lt;strong&gt;whatsapp_business_messaging&lt;/strong&gt; and &lt;strong&gt;whatsapp_business_management&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the token and store it in a secure place to use&amp;nbsp;later&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Step 3: Set up a tunnel to your&amp;nbsp;server
&lt;/h4&gt;

&lt;p&gt;I am using CloudFlare for that, but feel free to use whichever setup you prefer. On your server,&amp;nbsp;run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cloudflared tunnel &lt;span class="nt"&gt;--hostname&lt;/span&gt; &amp;lt;your-subdomain&amp;gt; run &lt;span class="nt"&gt;--url&lt;/span&gt; tcp://localhost:3100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also do the same from the CloudFlare dashboard under &lt;strong&gt;Zero Trust → Networks → Connectors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure you have the CloudFlareIP list added to the trustedProxies of the OpenClaw gateway. The gateway object of the openclaw.json should look something like&amp;nbsp;this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"gateway"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18789&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"bind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"loopback"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"controlUi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"allowedOrigins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"${ALLOWED_ORIGIN}"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"auth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${OPENCLAW_GATEWAY_TOKEN}"&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"trustedProxies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"173.245.48.0/20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"103.21.244.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"103.22.200.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"103.31.4.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"141.101.64.0/18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"108.162.192.0/18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"190.93.240.0/20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"188.114.96.0/20"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"197.234.240.0/22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"198.41.128.0/17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"162.158.0.0/15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"104.16.0.0/13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"104.24.0.0/14"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"172.64.0.0/13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"131.0.72.0/22"&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"tailscale"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"resetOnExit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"nodes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"denyCommands"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"camera.snap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"camera.clip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"screen.record"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"contacts.add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"calendar.add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"reminders.add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"sms.send"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Install and configure the OpenClaw WhatsApp-Cloud plugin
&lt;/h4&gt;

&lt;p&gt;I am using this unofficial OpenClaw WhatsApp plugin: &lt;a href="https://github.com/mcostantino-dev/openclaw-whatsapp-cloud-api" rel="noopener noreferrer"&gt;openclaw-whatsapp-cloud-api&lt;/a&gt;. It is a TypeScript app that communicates with the WhatsApp Cloud API. If you prefer, you can actually build your own by following the instructions &lt;a href="https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install the plugin, use these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.openclawmkdir plugins &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;pluginsgit clone git@github.com:mcostantino-dev/openclaw-whatsapp-cloud-api.gitmv openclaw-channel-whatsapp-cloud openclaw-whatsappcd openclaw-whatsappnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run buildopenclaw plugins &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the above commands are slightly different from the ones on the&amp;nbsp;repo&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let’s configure the plugin using environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.openclawnano .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste these values into your&amp;nbsp;.env&amp;nbsp;file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# WhatsApp Cloud APIWHATSAPP_PHONE_NUMBER_ID=WHATSAPP_ACCESS_TOKEN=WHATSAPP_APP_SECRET=WHATSAPP_VERIFY_TOKEN=WHATSAPP_WEBHOOK_PATH=/webhook/whatsapp-cloudALLOWED_PHONE=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fill the values in the file with the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp Phone number ID&lt;/strong&gt;: the phone number ID from step&amp;nbsp;0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp App Secret&lt;/strong&gt;: the app secret from step&amp;nbsp;1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp Access Token&lt;/strong&gt;: the token from step&amp;nbsp;2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp Verify Token&lt;/strong&gt;: any string you prefer to use as a verify&amp;nbsp;token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allowed Phone&lt;/strong&gt;: your phone&amp;nbsp;number&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, open the openclaw.json file and update the whatsapp-cloudfields so the file looks like&amp;nbsp;that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"channels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;channels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;any&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"whatsapp-cloud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"phoneNumberId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${WHATSAPP_PHONE_NUMBER_ID}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"accessToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${WHATSAPP_ACCESS_TOKEN}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"appSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${WHATSAPP_APP_SECRET}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"verifyToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${WHATSAPP_VERIFY_TOKEN}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"webhookPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${WHATSAPP_WEBHOOK_PATH}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"webhookPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"dmPolicy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allowlist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"allowFrom"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"${ALLOWED_PHONE}"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;e.g.,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;gateway,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;skills,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;etc.&lt;/span&gt;&lt;span class="nl"&gt;"plugins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"load"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;"~/.openclaw/plugins/whatsapp-cloud"&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"entries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"openclaw-whatsapp-cloud-api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, restart the OpenClaw&amp;nbsp;gateway&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now have a webhook listening on port 3100 for WhatsApp Cloud API callback&amp;nbsp;requests&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5: Configure the&amp;nbsp;webhook
&lt;/h4&gt;

&lt;p&gt;From the &lt;a href="https://developers.facebook.com/apps" rel="noopener noreferrer"&gt;App Dashboard&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the&amp;nbsp;app&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Use cases&lt;/strong&gt; from the&amp;nbsp;sidebar&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Connect with customers through WhatsApp&lt;/strong&gt; and click &lt;strong&gt;Customize&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Configuration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Callback URL&lt;/strong&gt;, enter https:///webhook/whatsapp-cloud&lt;/li&gt;
&lt;li&gt;For the &lt;strong&gt;Verify token&lt;/strong&gt;, enter the verify token you chose in step&amp;nbsp;4&lt;/li&gt;
&lt;li&gt;The API verifies your webhook, then shows a list of webhook&amp;nbsp;fields&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Webhook fields&lt;/strong&gt;, enable&amp;nbsp;&lt;strong&gt;messages&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Step 6: Test the connection&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Open WhatsApp on your phone, &lt;strong&gt;search&lt;/strong&gt; for the WhatsApp business phone number, and start chatting. Your OpenClaw agent should respond to you.&amp;nbsp;Enjoy!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Troubleshooting&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  OpenClaw gateway failing to&amp;nbsp;start
&lt;/h4&gt;

&lt;p&gt;Make sure openclaw.json has no issues. Run the following command to&amp;nbsp;check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; openclaw-gateway.service &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should give you a list of issues in the&amp;nbsp;file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tunnel not connecting
&lt;/h4&gt;

&lt;p&gt;Make sure the webhook is listening on your server on port 3100 using this&amp;nbsp;command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;netstat &lt;span class="nt"&gt;-tap&lt;/span&gt; tcp | &lt;span class="nb"&gt;grep &lt;/span&gt;3100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tcp6  0  0 [::]:3100  [::]:*   LISTEN   123456/openclaw-gat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Webhook verification failure
&lt;/h4&gt;

&lt;p&gt;Make sure your callback URL is reachable from the internet. Try running this command on your&amp;nbsp;local:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://&amp;lt;your-subdomain&amp;gt;/webhook/whatsapp-cloud?hub.mode=subscribe&amp;amp;hub.challenge=123&amp;amp;hub.verify_token=&amp;lt;verify-token&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to replace  and with your values. You should get 123&amp;nbsp;back&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.openclaw.ai" rel="noopener noreferrer"&gt;OpenClaw documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/documentation/business-messaging/whatsapp/get-started" rel="noopener noreferrer"&gt;WhatsApp Cloud API Get&amp;nbsp;Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/documentation/business-messaging/whatsapp/whatsapp-business-accounts" rel="noopener noreferrer"&gt;WhatsApp Business Accounts documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/" rel="noopener noreferrer"&gt;CloudFlare Tunnel Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenClaw WhatsApp Plugin (unofficial): &lt;a href="https://github.com/mcostantino-dev/openclaw-whatsapp-cloud-api" rel="noopener noreferrer"&gt;mcostantino-dev/openclaw-whatsapp-cloud-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should now have a fully functioning WhatsApp number for your OpenClaw agent, running securely through your own tunnel without third-party fees. What kind of AI agent are you building with OpenClaw? Let me know in the comments below! If you run into any issues during setup, drop a question, and I’ll help you troubleshoot.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://medium.com/capsulat/self-host-openclaw-ai-agent-whatsapp-cloud-api-5a4c29bca247" rel="noopener noreferrer"&gt;Self-Host an AI Agent Using OpenClaw and WhatsApp Cloud API (2026)&lt;/a&gt; was originally published in &lt;a href="https://medium.com/capsulat" rel="noopener noreferrer"&gt;Capsulat&lt;/a&gt; on Medium, where people are continuing the conversation by highlighting and responding to this story.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>whatsapp</category>
      <category>openclaw</category>
    </item>
    <item>
      <title>Your AI Code Can Be Elegant Too</title>
      <dc:creator>Amr Abed</dc:creator>
      <pubDate>Fri, 02 Oct 2026 13:20:44 +0000</pubDate>
      <link>https://dev.to/amrabed/your-ai-code-can-be-elegant-too-coc</link>
      <guid>https://dev.to/amrabed/your-ai-code-can-be-elegant-too-coc</guid>
      <description>&lt;p&gt;As the Machine Learning Engineering Manager at an AI-powered SaaS company, I get a front-row seat to the machine learning (ML) code written by data science teams. When I'm not reviewing models and production pipelines, I dabble in the occasional Kaggle competition, though I'm more of an enthusiastic competitor than a podium regular.&lt;/p&gt;

&lt;p&gt;A recurring pattern quickly emerges: many brilliant data scientists come from mathematics, statistics, or academic research where code is treated merely as a vehicle to run an experiment. Python was adopted as a friendlier upgrade from R or MATLAB. The resulting code may hit top leaderboard accuracy, but in terms of software craftsmanship, it's often about as elegant as a spork.&lt;/p&gt;

&lt;p&gt;"Working" code is no longer enough when models move from quick experiments to production pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszd7c3g87lx861hvk35l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fszd7c3g87lx861hvk35l.png" alt="Python code on a dark screen illustrating clean ML code practices" width="799" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@cdr6934?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Chris Ried&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Should You Care About Clean ML Code?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Clean code always looks like it was written by someone who cares."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
— &lt;strong&gt;Michael Feathers&lt;/strong&gt;, quoted in Robert C. Martin's &lt;a href="https://www.goodreads.com/work/quotes/3779106" rel="noopener noreferrer"&gt;&lt;em&gt;Clean Code&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you write machine learning code, you're communicating with an audience: your future self six months from now, your teammates, and the engineers responsible for running your model in production.&lt;/p&gt;

&lt;p&gt;My software journey began in 2003 as a Computer Engineering student at one of Egypt's top universities. Starting with C++ (rather than C) naturally trained me in object-oriented programming (OOP), separation of concerns, and clean architectural design.&lt;/p&gt;

&lt;p&gt;Fast-forward to graduate school at Virginia Tech (2014–2017): I dove into machine learning and deep learning, tinkering with Pandas and early versions of TensorFlow (yes, versions 0.12 and 1.0 — Google, I’ll take that apology now).&lt;/p&gt;

&lt;p&gt;Coming from that engineering background, I’ve always had a soft spot for clean code. For me, writing clean code is like signing a piece of art. That includes machine learning code. At one point, I even took a stab at &lt;a href="https://github.com/amrabed/DL4J" rel="noopener noreferrer"&gt;rewriting DL4J&lt;/a&gt; (Deep Learning for Java) with a modern object-oriented architecture.&lt;/p&gt;

&lt;p&gt;In modern MLOps environments, orchestrating workloads on platforms like &lt;strong&gt;MLflow&lt;/strong&gt;, &lt;strong&gt;TFX&lt;/strong&gt;, &lt;strong&gt;Kubeflow&lt;/strong&gt;, and &lt;strong&gt;AWS SageMaker&lt;/strong&gt;, sloppy code isn't just an eyesore; it's a real operational risk. Silent bugs, unreproducible splits, untracked dependencies, and unreadable transformations slow down teams and break downstream services.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 3-Tier ML Code Maturity Model
&lt;/h2&gt;

&lt;p&gt;To turn this philosophy into an actionable engineering workflow, I think of ML code quality as progressing through three distinct maturity tiers:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;graph TD
    T1["Tier 1: Exploratory Script (Notebook Prototype)&amp;lt;br/&amp;gt;• Monolithic scripts, smashed imports, global variables&amp;lt;br/&amp;gt;• Unencapsulated state, unrepeatable cell execution"]
    T2["Tier 2: Clean Idiomatic Python (The 'Refactor')&amp;lt;br/&amp;gt;• Surgical imports, PEP 8 compliance, descriptive naming&amp;lt;br/&amp;gt;• Hyperparameter constants, clean logical stages"]
    T3["Tier 3: Modular Object-Oriented Architecture (Production)&amp;lt;br/&amp;gt;• Encapsulated classes (Pipeline, Classifier)&amp;lt;br/&amp;gt;• Strongly-typed Pydantic configuration models&amp;lt;br/&amp;gt;• Unit-testable, importable into APIs &amp;amp; MLOps pipelines"]

    T1 --&amp;gt;|Refactor &amp;amp; Clean| T2
    T2 --&amp;gt;|Encapsulate &amp;amp; Modularize| T3&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Let's walk through the foundational rules that take you from Tier 1 to Tier 2, and then explore how object-oriented design elevates your code to Tier 3.&lt;/p&gt;




&lt;h2&gt;
  
  
  5 Foundational Rules for Clean ML Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Learn Your Tools (Stop Reinventing Vectorized Operations)
&lt;/h3&gt;

&lt;p&gt;Libraries like NumPy, Pandas, PyTorch, and TensorFlow provide highly optimized C and CUDA backends. Take the time to study the API references before resorting to Python &lt;code&gt;for&lt;/code&gt; loops across lists.&lt;/p&gt;

&lt;p&gt;I once reviewed a pipeline where a data scientist had written a 40-line nested loop to normalize features across a DataFrame. The whole thing could be replaced with a single &lt;code&gt;sklearn.preprocessing.StandardScaler&lt;/code&gt; call — and it ran about 50x faster. If you find yourself writing custom nested loops to compute metrics or transform arrays, there's almost certainly an optimized, idiomatic operation already built for the job.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Adhere to Python Naming Conventions (PEP 8)
&lt;/h3&gt;

&lt;p&gt;In linear algebra, $X$ is a feature matrix and $y$ is a target vector. But Python doesn't care about mathematical conventions — from the interpreter's perspective, both are just variables.&lt;/p&gt;

&lt;p&gt;Variables and functions in Python use &lt;code&gt;snake_case&lt;/code&gt; (lowercase with underscores) as defined by &lt;a href="https://peps.python.org/pep-0008/#function-and-variable-names" rel="noopener noreferrer"&gt;PEP 8&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Variable names follow the same convention as function names.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;“Function names should be lowercase, with words separated by underscores as necessary to improve readability.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Give Your Variables Descriptive Names
&lt;/h3&gt;

&lt;p&gt;I can't count how many times I've opened a notebook and found &lt;code&gt;df&lt;/code&gt;, &lt;code&gt;df2&lt;/code&gt;, &lt;code&gt;df_final&lt;/code&gt;, and &lt;code&gt;df_final_v2&lt;/code&gt; all living in the same file. Single-letter abbreviations and generic shorthand make notebooks needlessly hard to follow. Replace them with names that communicate intent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cryptic / Notebook Style&lt;/th&gt;
&lt;th&gt;Descriptive &amp;amp; Explicit&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;df&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;raw_data&lt;/code&gt; / &lt;code&gt;customer_churn_data&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Identifies the actual domain entity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;features&lt;/code&gt;, &lt;code&gt;labels&lt;/code&gt; (or &lt;code&gt;targets&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Disambiguates inputs and prediction goals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;train_ds&lt;/code&gt;, &lt;code&gt;val_ds&lt;/code&gt;, &lt;code&gt;test_ds&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;training_data&lt;/code&gt;, &lt;code&gt;validation_data&lt;/code&gt;, &lt;code&gt;test_data&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Clear without requiring mental decoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;m&lt;/code&gt; or &lt;code&gt;clf&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;model&lt;/code&gt; / &lt;code&gt;classifier&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Communicates role and purpose clearly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  4. Be Precise and Surgical with Imports
&lt;/h3&gt;

&lt;p&gt;Why import the entire &lt;code&gt;numpy&lt;/code&gt; namespace when all you need is &lt;code&gt;array&lt;/code&gt; and &lt;code&gt;expand_dims&lt;/code&gt;? Why pull in all of &lt;code&gt;pandas&lt;/code&gt; when you just need &lt;code&gt;read_csv&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Instead of broad, monolithic imports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be surgical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;read_csv&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DataFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Surgical imports get rid of redundant module prefixes and make your dependencies immediately transparent.&lt;/p&gt;

&lt;p&gt;When you need functions with identical names from different packages (e.g., &lt;code&gt;load&lt;/code&gt; from &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;load&lt;/code&gt; from &lt;code&gt;pickle&lt;/code&gt;), use explicit aliases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;load_json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pickle&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;load_pickle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  The Pragmatic Rule: Clarity Over Dogmatism
&lt;/h4&gt;

&lt;p&gt;I should be honest here — in data science, aliases like &lt;code&gt;import numpy as np&lt;/code&gt; and &lt;code&gt;import pandas as pd&lt;/code&gt; are virtually universal conventions. If you're manipulating dozens of array operations or DataFrame joins across a file, typing &lt;code&gt;np.mean&lt;/code&gt; or &lt;code&gt;pd.concat&lt;/code&gt; is perfectly fine and preserves helpful namespace context.&lt;/p&gt;

&lt;p&gt;The problem arises when you import massive framework submodules wholesale:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Cluttered: Forces repetitive layers.* prefixes everywhere
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;layers&lt;/span&gt;

&lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Versus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Clean: Direct, explicit, and self-documenting
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.layers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dense&lt;/span&gt;

&lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal isn't blind dogmatism—it's &lt;strong&gt;intentionality&lt;/strong&gt;. Know when a namespace prefix adds genuine clarity versus when it simply introduces noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Graduate from Loose Notebooks to a Modern IDE
&lt;/h3&gt;

&lt;p&gt;Databricks and Google Colab are great for initial experimentation, but they're rarely enough for building robust, production-grade systems.&lt;/p&gt;

&lt;p&gt;Modern IDEs like &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; and PyCharm support Jupyter notebooks natively while giving you first-class software engineering tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Version control&lt;/strong&gt; with GitHub pull requests, branch protection, and diff reviews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated formatting &amp;amp; linting with &lt;a href="https://astral.sh/ruff" rel="noopener noreferrer"&gt;Ruff&lt;/a&gt;&lt;/strong&gt;: Written in Rust, Ruff has rapidly become the modern standard in Python engineering, replacing Black, Flake8, and isort simultaneously while running 10–100x faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data &amp;amp; Configuration validation with &lt;a href="https://docs.pydantic.dev/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt;&lt;/strong&gt;: Catch schema mismatches, type errors, and invalid hyperparameter values before running expensive multi-hour training runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static type checking with Mypy or Pyright&lt;/strong&gt;: Detect tensor dimension mistakes and invalid argument types at development time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI code assistance&lt;/strong&gt; with GitHub Copilot and Gemini&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud compute integration&lt;/strong&gt; for remote debugging on GPUs and TPUs&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro Tip for Notebook Repositories:&lt;/strong&gt; If your team must commit &lt;code&gt;.ipynb&lt;/code&gt; files to Git, install &lt;a href="https://github.com/kynan/nbstripout" rel="noopener noreferrer"&gt;&lt;code&gt;nbstripout&lt;/code&gt;&lt;/a&gt; as a pre-commit hook. It automatically strips cell outputs, execution counts, and bloated base64 image strings before commits, turning unreadable multi-thousand-line JSON diffs into clean, reviewable code changes.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Quick Win&lt;/strong&gt;: Run &lt;code&gt;pip install ruff &amp;amp;&amp;amp; ruff check .&lt;/code&gt; on your project folder today. You'll instantly catch unused imports, undefined variables, and formatting inconsistencies in milliseconds.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Case Study: Refactoring a Transfer Learning Pipeline
&lt;/h2&gt;

&lt;p&gt;Enough theory — let's look at a concrete example. Here's an image classification transfer learning workflow based on the TensorFlow/Keras documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "Before" Script (Tier 1: Exploratory Script)
&lt;/h3&gt;

&lt;p&gt;This is what typical data science code looks like before any cleanup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;layers&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tf_data&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensorflow_datasets&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tfds&lt;/span&gt;

&lt;span class="n"&gt;tfds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable_progress_bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tfds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cats_vs_dogs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# Reserve 10% for validation and 10% for test
&lt;/span&gt;    &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[:40%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[40%:50%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[50%:60%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;as_supervised&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Include labels
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of training samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of validation samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of test samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;test_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;resize_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Resizing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;train_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;validation_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;test_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;augmentation_layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;horizontal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;augmentation_layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;


&lt;span class="n"&gt;train_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;batch_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="n"&gt;train_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;validation_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;test_ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;first_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;augmented_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_dims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;augmented_image&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;int32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;base_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Xception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;imagenet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Load weights pre-trained on ImageNet.
&lt;/span&gt;    &lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;include_top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Do not include the ImageNet classifier at the top.
&lt;/span&gt;
&lt;span class="c1"&gt;# Freeze the base_model
&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;scale_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;127.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scale_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;training&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Regularize with dropout
&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;losses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fitting the top layer of the model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# Low learning rate
&lt;/span&gt;    &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;losses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;epochs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fitting the end-to-end model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_ds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;validation_ds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Test dataset evaluation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_ds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Code Review Critique
&lt;/h3&gt;

&lt;p&gt;I see several opportunities for cleanup here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unnecessary module imports&lt;/strong&gt;: &lt;code&gt;numpy&lt;/code&gt; is imported solely for &lt;code&gt;expand_dims&lt;/code&gt; and &lt;code&gt;array&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heavy plotting imports&lt;/strong&gt;: &lt;code&gt;matplotlib.pyplot&lt;/code&gt; is imported in its entirety for just four functions (&lt;code&gt;axis&lt;/code&gt;, &lt;code&gt;figure&lt;/code&gt;, &lt;code&gt;imshow&lt;/code&gt;, &lt;code&gt;subplot&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeated module prefixes&lt;/strong&gt;: Importing &lt;code&gt;layers&lt;/code&gt; causes repetitive &lt;code&gt;layers.*&lt;/code&gt; prefixes throughout the model definition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redundant package namespaces&lt;/strong&gt;: The same issue affects &lt;code&gt;keras.optimizers&lt;/code&gt;, &lt;code&gt;keras.losses&lt;/code&gt;, and &lt;code&gt;keras.metrics&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vague variable names&lt;/strong&gt;: &lt;code&gt;train_ds&lt;/code&gt;, &lt;code&gt;validation_ds&lt;/code&gt;, and &lt;code&gt;test_ds&lt;/code&gt; can be renamed to &lt;code&gt;training_data&lt;/code&gt;, &lt;code&gt;validation_data&lt;/code&gt;, and &lt;code&gt;test_data&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hidden constants&lt;/strong&gt;: &lt;code&gt;batch_size&lt;/code&gt; is a constant hyperparameter, but defined as a mutable variable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reused and redundant variables&lt;/strong&gt;: &lt;code&gt;epochs&lt;/code&gt; is defined and immediately consumed, obscuring the parameter at the call site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unformatted structure&lt;/strong&gt;: Lacks consistent code formatting (e.g., Ruff/Black) and organized import blocks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fveb6m3gvc4xdo5fopczj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fveb6m3gvc4xdo5fopczj.png" alt="WTFs per minute: the real-world metric for clean code quality and code reviews by Thom Holwerda" width="550" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image by &lt;a href="https://commadot.com/about/" rel="noopener noreferrer"&gt;Glen Lipka&lt;/a&gt; on &lt;a href="https://commadot.com/wtf-per-minute" rel="noopener noreferrer"&gt;Commadot&lt;/a&gt; (inspired by &lt;a href="https://www.osnews.com/story/author/thom-holwerda" rel="noopener noreferrer"&gt;Thom Holwerda&lt;/a&gt;’s post on &lt;a href="https://www.osnews.com/story/19266/wtfsm" rel="noopener noreferrer"&gt;OSNews&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  The Refactored Script (Tier 2: Clean Idiomatic Python)
&lt;/h3&gt;

&lt;p&gt;Here is the same code after applying the foundational rules from above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.applications&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Xception&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.layers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Resizing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.losses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryCrossentropy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryAccuracy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.optimizers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Adam&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subplot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expand_dims&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow.data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow_datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;disable_progress_bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Load and split the dataset
&lt;/span&gt;&lt;span class="nf"&gt;disable_progress_bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cats_vs_dogs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[:40%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[40%:50%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[50%:60%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;as_supervised&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Include labels
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of training samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of validation samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Number of test samples: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cardinality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Inspect training samples
&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Standardize image size
&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Resizing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;training_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;validation_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# 4. Data augmentation
&lt;/span&gt;&lt;span class="n"&gt;augmentation_layers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;horizontal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;augmentation_layers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;


&lt;span class="n"&gt;training_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# 5. Batch and optimize pipeline
&lt;/span&gt;&lt;span class="n"&gt;BATCH_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="n"&gt;training_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BATCH_SIZE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;validation_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BATCH_SIZE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BATCH_SIZE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 6. Inspect augmented batch
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;first_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;augmented_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;data_augmentation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;expand_dims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;augmented_image&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;int32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
        &lt;span class="nf"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 7. Configure pre-trained base model
&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Xception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;imagenet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Load weights pre-trained on ImageNet
&lt;/span&gt;    &lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;include_top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Exclude ImageNet top classifier
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# Freeze base weights for initial training
&lt;/span&gt;
&lt;span class="c1"&gt;# 8. Build custom classification head
&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;127.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Scale [0, 255] to [-1, 1]
&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;training&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Regularize with dropout
&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 9. Train custom head
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 10. Fine-tune end-to-end
&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;  &lt;span class="c1"&gt;# Unfreeze base model
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;show_trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# Lower learning rate to preserve learned representations
&lt;/span&gt;    &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 11. Evaluate on test set
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  The Power of Explicit Imports
&lt;/h3&gt;

&lt;p&gt;Here's what I really love about surgical imports — they give you a high-level summary of your entire model architecture right at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.applications&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Xception&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.layers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.losses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryCrossentropy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryAccuracy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.optimizers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Adam&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within seconds of opening the file, any engineer or reviewer can tell:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base Model&lt;/strong&gt;: Transfer learning with pre-trained &lt;code&gt;Xception&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layers&lt;/strong&gt;: &lt;code&gt;Rescaling&lt;/code&gt;, &lt;code&gt;GlobalAveragePooling2D&lt;/code&gt;, &lt;code&gt;Dropout&lt;/code&gt;, and &lt;code&gt;Dense&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Augmentation&lt;/strong&gt;: &lt;code&gt;RandomFlip&lt;/code&gt; and &lt;code&gt;RandomRotation&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization Strategy&lt;/strong&gt;: &lt;code&gt;Adam&lt;/code&gt; optimizer, &lt;code&gt;BinaryCrossentropy&lt;/code&gt; loss, and &lt;code&gt;BinaryAccuracy&lt;/code&gt; metric&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No need to dig through hundreds of lines of notebook code just to figure out what model is being trained.&lt;/p&gt;




&lt;h2&gt;
  
  
  Taking It to the Next Level: Object-Oriented ML Architecture (Tier 3)
&lt;/h2&gt;

&lt;p&gt;Tier 2 is a dramatic improvement, but flat procedural scripts still have real limitations when they need to live inside production software. I learned this the hard way when one of my teams tried to deploy a Tier 2 script behind a FastAPI endpoint — importing the module triggered a 2 GB dataset download on every cold start.&lt;/p&gt;

&lt;p&gt;Here are the three problems that keep showing up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Global State Pollution&lt;/strong&gt;: Variables like &lt;code&gt;base_model&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, and &lt;code&gt;training_data&lt;/code&gt; float in global module scope. In notebooks or long-running worker processes, this leads to memory leaks and accidental state bleeding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Untestable Code&lt;/strong&gt;: You can't write isolated unit tests for your data augmentation or model construction without running the entire training pipeline end-to-end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Reusability&lt;/strong&gt;: If an API engineer needs to serve inference from your trained model in FastAPI or &lt;a href="https://blog.amrabed.com/aws-lambda-templates" rel="noopener noreferrer"&gt;AWS Lambda microservices&lt;/a&gt;, they can't cleanly &lt;code&gt;import&lt;/code&gt; your model logic without triggering dataset downloads and training routines.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where &lt;strong&gt;Object-Oriented Design (OOP)&lt;/strong&gt;, &lt;strong&gt;Separation of Concerns&lt;/strong&gt;, and &lt;strong&gt;strongly-typed Pydantic models&lt;/strong&gt; come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architectural Component Flow
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;graph TD
    Config["TrainingConfig&amp;lt;br/&amp;gt;(batch_size, image_size, epochs, lr)"]
    Config --&amp;gt;|config| Pipeline["ImageDatasetPipeline&amp;lt;br/&amp;gt;• Download &amp;amp; Split&amp;lt;br/&amp;gt;• Resize &amp;amp; Augment&amp;lt;br/&amp;gt;• Batch &amp;amp; Cache (AUTOTUNE)"]
    Config --&amp;gt;|config| Classifier["TransferLearningClassifier&amp;lt;br/&amp;gt;• Base Xception (Frozen)&amp;lt;br/&amp;gt;• Custom Dense Head&amp;lt;br/&amp;gt;• Head Train / Fine-tune"]
    Pipeline --&amp;gt;|train, val, test| Classifier
    Classifier --&amp;gt; Model["Evaluated Model&amp;lt;br/&amp;gt;(Inference Ready)"]&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  Designing the Components
&lt;/h3&gt;

&lt;p&gt;I like to decompose this into three focused responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;TrainingConfig&lt;/code&gt;&lt;/strong&gt;: An immutable, validated Pydantic model holding all hyperparameters and configurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;ImageDatasetPipeline&lt;/code&gt;&lt;/strong&gt;: Handles downloading, splitting, caching, and augmenting dataset batches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;TransferLearningClassifier&lt;/code&gt;&lt;/strong&gt;: Handles building the neural network, compiling, training, fine-tuning, and evaluating.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the Tier 3 implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.applications&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Xception&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.layers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Resizing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.losses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryCrossentropy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BinaryAccuracy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;keras.optimizers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Adam&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ndarray&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ConfigDict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tensor&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow.data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tensorflow_datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;disable_progress_bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrainingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Hyperparameters and runtime settings for the model pipeline.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="n"&gt;model_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigDict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;image_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
    &lt;span class="n"&gt;initial_epochs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;fine_tune_epochs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;fine_tune_learning_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1e-5&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImageDatasetPipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Encapsulates data ingestion, preprocessing, and augmentation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TrainingConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Resizing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;augmentation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;RandomFlip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;horizontal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;RandomRotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_augment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;augmentation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataset_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cats_vs_dogs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Loads and prepares train, validation, and test dataset splits.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="nf"&gt;disable_progress_bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;dataset_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[:40%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[40%:50%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;train[50%:60%]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;as_supervised&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;augment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;augment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_augment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;prefetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AUTOTUNE&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;augment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransferLearningClassifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Encapsulates model architecture, training, and evaluation lifecycle.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TrainingConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Xception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;imagenet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;include_top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_build_model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_build_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Constructs the transfer learning model with a custom classification head.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;  &lt;span class="c1"&gt;# Freeze base weights initially
&lt;/span&gt;        &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Rescaling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;127.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;training&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GlobalAveragePooling2D&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;train_head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Trains only the newly added top classification layers.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initial_epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;val_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fine_tune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Unfreezes the base model and fine-tunes with a low learning rate.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fine_tune_learning_rate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;BinaryCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_logits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;BinaryAccuracy&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fine_tune_epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;val_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Evaluates model performance on unseen test data.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_dict&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Generates prediction probabilities for input samples.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the Modular Pipeline
&lt;/h3&gt;

&lt;p&gt;Now look at how clean the execution becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TrainingConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ImageDatasetPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TransferLearningClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;train_head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fine_tune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;training_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validation_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# For downstream inference or API serving:
&lt;/span&gt;    &lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every component now has a single, well-defined role:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to swap data augmentation strategies? Touch only &lt;code&gt;ImageDatasetPipeline&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Want to try a different learning rate or image resolution? Change one value in &lt;code&gt;TrainingConfig&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Want to write a unit test for image resizing? Test &lt;code&gt;pipeline.resize&lt;/code&gt; — no GPU, no massive neural network initialization.&lt;/li&gt;
&lt;li&gt;Want to deploy inference to a FastAPI microservice or &lt;a href="https://blog.amrabed.com/aws-lambda-templates" rel="noopener noreferrer"&gt;production AWS Lambda template&lt;/a&gt;? Import &lt;code&gt;TransferLearningClassifier&lt;/code&gt; directly and call &lt;code&gt;predict()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  💡 What Happened to the Data Visualizations?
&lt;/h3&gt;

&lt;p&gt;You might notice that Tier 3 drops the &lt;code&gt;matplotlib&lt;/code&gt; code from earlier. That's intentional. In production architecture, visualization is a downstream consumer, not a pipeline dependency. Your core model training and inference pipelines should be headless, lightweight, and free of plotting libraries. When you want to inspect data or generate confusion matrices, write a dedicated evaluation script or spin up a lightweight notebook that imports &lt;code&gt;TransferLearningClassifier&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The 3-Tier ML Architecture Cheat Sheet
&lt;/h2&gt;

&lt;p&gt;Here's how the three tiers compare side by side as a quick reference for technical reviews and design specs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Notebook Script (Tier 1)&lt;/th&gt;
&lt;th&gt;Idiomatic Script (Tier 2)&lt;/th&gt;
&lt;th&gt;Modular OOP Architecture (Tier 3)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Leaks into global namespace&lt;/td&gt;
&lt;td&gt;Top-level module scope&lt;/td&gt;
&lt;td&gt;Strictly encapsulated in class instances&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hyperparameters&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hardcoded magic numbers&lt;/td&gt;
&lt;td&gt;Module constants (&lt;code&gt;BATCH_SIZE&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Strongly-typed immutable Pydantic model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Impossible without executing all cells&lt;/td&gt;
&lt;td&gt;Difficult; relies on global state&lt;/td&gt;
&lt;td&gt;Trivially testable; components mockable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reusability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Copy-pasting cells&lt;/td&gt;
&lt;td&gt;Copying script file&lt;/td&gt;
&lt;td&gt;Importable module into FastAPI, Celery, or Kubeflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Type Safety&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Partial hints&lt;/td&gt;
&lt;td&gt;End-to-end type annotations (&lt;code&gt;Dataset&lt;/code&gt;, &lt;code&gt;tuple&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Clean ML Checklist
&lt;/h2&gt;

&lt;p&gt;Before submitting an ML pull request or moving notebook code into production, I run through this checklist. It doubles as a quick health scorecard — if you can't confidently check most of these, the code isn't production-ready yet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Reproducibility&lt;/strong&gt;: Can a new engineer clone the repo and run the entire pipeline with a single command? Are random seeds set explicitly?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Descriptive Naming&lt;/strong&gt;: Are variables named for their domain roles (&lt;code&gt;features&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;customer_data&lt;/code&gt;) rather than single letters (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;df&lt;/code&gt;)?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Surgical Imports&lt;/strong&gt;: Are you importing only the functions, classes, and layers you actually use?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Separation of Concerns&lt;/strong&gt;: Is data loading separated from model definition and training logic?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Encapsulated State&lt;/strong&gt;: Are models and pipelines encapsulated in classes rather than loose global variables?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Configurability&lt;/strong&gt;: Are hyperparameters externalized into a typed, validated Pydantic model rather than hardcoded?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Testability&lt;/strong&gt;: Can you test your data transformations without spinning up a GPU?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Modularity&lt;/strong&gt;: Can your trained model be imported into an API without triggering a training run?&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Linter &amp;amp; Formatter&lt;/strong&gt;: Did you run &lt;code&gt;ruff check&lt;/code&gt; and &lt;code&gt;ruff format&lt;/code&gt; before committing?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Writing clean code in machine learning isn't pedantic nitpicking — it directly impacts your team's velocity, prevents subtle data leaks, and bridges the gap between quick prototypes and reliable production systems.&lt;/p&gt;

&lt;p&gt;Moving from loose notebook cells to clean Python scripts — and ultimately to modular, object-oriented pipelines — is how data science code becomes resilient software. Whether it's a weekend Kaggle submission or an enterprise ML pipeline, your teammates (and your future self) will thank you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the biggest friction point your team faces when taking ML code from notebook experiments to production? Do you enforce OOP pipelines, or do you prefer functional scripts? I'd love to hear your thoughts in the comments below!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>machinelearning</category>
      <category>mlops</category>
      <category>ai</category>
    </item>
    <item>
      <title>Stop Writing Lambda Boilerplate</title>
      <dc:creator>Amr Abed</dc:creator>
      <pubDate>Thu, 01 Oct 2026 02:30:28 +0000</pubDate>
      <link>https://dev.to/amrabed/stop-writing-lambda-boilerplate-42b0</link>
      <guid>https://dev.to/amrabed/stop-writing-lambda-boilerplate-42b0</guid>
      <description>&lt;p&gt;Introducing the &lt;a href="https://github.com/cur8d/lambda" rel="noopener noreferrer"&gt;&lt;strong&gt;cur8d/lambda&lt;/strong&gt;&lt;/a&gt; open-source repository — a collection of production-ready Python Lambda templates for Bedrock Agent, REST API, GraphQL, DynamoDB Stream, EventBridge, S3, and SQS scenarios. These templates come pre-integrated with &lt;strong&gt;AWS Lambda Powertools&lt;/strong&gt;, &lt;strong&gt;AWS CDK&lt;/strong&gt;, &lt;strong&gt;Pydantic&lt;/strong&gt;, and a robust testing infrastructure.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk37l33r673fu02kgtbsz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk37l33r673fu02kgtbsz.png" alt="cover.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every serverless developer knows the feeling. You spin up a new Lambda project, and before writing a single line of business logic, you're already copying boilerplate from a previous project: setting up AWS Lambda Powertools, wiring up structured logging, configuring X-Ray tracing, and building yet another Repository class for DynamoDB access.&lt;/p&gt;

&lt;p&gt;This repetitive setup isn't just tedious — it's a source of inconsistency across projects and a hidden risk. Teams often skip best practices under time pressure, and the "quick Lambda" becomes the undocumented, untested function that nobody dares touch six months later.&lt;/p&gt;

&lt;p&gt;That's why I built &lt;a href="https://github.com/cur8d/lambda" rel="noopener noreferrer"&gt;&lt;strong&gt;cur8d/lambda&lt;/strong&gt;&lt;/a&gt; — a collection of production-ready, plug-and-play Python Lambda templates for some of the common real-world scenarios on AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Lambda Bootstrapping
&lt;/h2&gt;

&lt;p&gt;AWS Lambda's promise is simplicity: deploy a function, it scales. But production Lambda functions require significantly more than a handler file. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured logging&lt;/strong&gt; that integrates with CloudWatch Insights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed tracing&lt;/strong&gt; with AWS X-Ray&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt; for operational visibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch processing&lt;/strong&gt; for event sources like SQS and DynamoDB Streams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong typing&lt;/strong&gt; to catch bugs at development time, not runtime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code,&lt;/strong&gt; so your function is reproducible and auditable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive tests&lt;/strong&gt; with AWS service mocking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most developers piece this together manually each time — or worse, they copy a "good enough" version from a previous project and gradually accumulate inconsistencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing cur8d/lambda
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/cur8d/lambda" rel="noopener noreferrer"&gt;cur8d/lambda&lt;/a&gt; is a GitHub template repository that gives you a complete, opinionated, production-grade starting point for Python Lambda development. It currently covers seven real-world scenarios out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bedrock Agent&lt;/strong&gt; — Handle function-based actions from Amazon Bedrock Agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL API&lt;/strong&gt; — Resolve AppSync GraphQL requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REST API&lt;/strong&gt; — Handle API Gateway REST requests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB Stream&lt;/strong&gt; — Batch-process stream events with failure handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; — React to events and call external APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 to SQS&lt;/strong&gt; — Queue messages on S3 object changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQS to DynamoDB&lt;/strong&gt; — Batch-process SQS messages into DynamoDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each template is a fully self-contained starting point. Pick your scenario, rename the project, and start writing business logic immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Pre-Wired for You
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS Lambda Powertools
&lt;/h3&gt;

&lt;p&gt;Every template integrates &lt;a href="https://docs.aws.amazon.com/powertools/python" rel="noopener noreferrer"&gt;AWS Lambda Powertools for Python&lt;/a&gt; — AWS's first-party library for Lambda best practices. This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured JSON logging&lt;/strong&gt; with correlation IDs automatically injected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudWatch EMF Metrics&lt;/strong&gt; for operational dashboards without custom code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS X-Ray Tracing&lt;/strong&gt; with automatic subsegment creation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch processing&lt;/strong&gt; utilities for SQS and DynamoDB Streams, including partial failure handling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter and Secrets loading&lt;/strong&gt; with caching built in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event source data classes&lt;/strong&gt; for type-safe event parsing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't configure any of this — it's already there. More on that later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pydantic Data Modeling
&lt;/h3&gt;

&lt;p&gt;All input/output models are defined using &lt;a href="https://docs.pydantic.dev/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt;, giving you automatic validation, serialization, and type safety.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid4&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic.alias_generators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;to_camel&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alias_generator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;to_camel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;populate_by_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unique item identifier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Human-readable item name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;alias_generator=to_camel&lt;/code&gt; configuration means the JSON payload from API Gateway uses &lt;code&gt;camelCase&lt;/code&gt; while the Python code uses &lt;code&gt;snake_case&lt;/code&gt; — matching JSON conventions on the wire and Python conventions in code, with zero manual mapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure as Code with AWS CDK
&lt;/h3&gt;

&lt;p&gt;Every template ships with a matching &lt;a href="https://aws.amazon.com/cdk" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt; stack under &lt;code&gt;infra/stacks/&lt;/code&gt;. Deploy any stack with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make deploy &lt;span class="nv"&gt;STACK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No manual console clicks. No documentation to update. The infrastructure is the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Architecture with the Repository Pattern
&lt;/h3&gt;

&lt;p&gt;All database access is encapsulated in a &lt;code&gt;Repository&lt;/code&gt; class, separating your business logic from AWS service calls. This makes testing trivial and keeps your handler functions focused on what matters: the business logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing That Actually Tests Things
&lt;/h3&gt;

&lt;p&gt;The test suite uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pytest.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;pytest&lt;/strong&gt;&lt;/a&gt; for test orchestration&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://docs.getmoto.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;moto&lt;/strong&gt;&lt;/a&gt; for AWS service mocking (DynamoDB, SQS, S3 — all mocked locally)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hypothesis.readthedocs.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Hypothesis&lt;/strong&gt;&lt;/a&gt; for property-based testing, automatically generating edge-case inputs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://coverage.readthedocs.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;coverage&lt;/strong&gt;&lt;/a&gt; for coverage reporting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the entire suite with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code Quality, Automated
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.astral.sh/ruff" rel="noopener noreferrer"&gt;&lt;strong&gt;ruff&lt;/strong&gt;&lt;/a&gt; for linting and formatting (replacing Flake8, isort, Black)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://microsoft.github.io/pyright" rel="noopener noreferrer"&gt;&lt;strong&gt;pyright&lt;/strong&gt;&lt;/a&gt; for static type checking&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pre-commit.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;pre-commit&lt;/strong&gt;&lt;/a&gt; hooks to enforce quality before every commit&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/code-security/dependabot" rel="noopener noreferrer"&gt;&lt;strong&gt;Dependabot&lt;/strong&gt;&lt;/a&gt; for automated dependency updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Developer Experience
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.visualstudio.com/docs/devcontainers/containers" rel="noopener noreferrer"&gt;&lt;strong&gt;Dev Containers&lt;/strong&gt;&lt;/a&gt; support means you can open the repo in VS Code and have the entire development environment running in Docker — Python, Poetry, CDK, and all tools pre-installed—no setup required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.mkdocs.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;MkDocs&lt;/strong&gt;&lt;/a&gt; for auto-generated API documentation published to GitHub Pages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub Actions&lt;/strong&gt;&lt;/a&gt; workflows for CI/CD and documentation deployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI Agent guidelines&lt;/strong&gt; (&lt;code&gt;AGENTS.md&lt;/code&gt;) providing context for AI coding assistants working in the repo&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AWS Lambda Powertools — In Practice
&lt;/h2&gt;

&lt;p&gt;Every template integrates&amp;nbsp;&lt;a href="https://docs.aws.amazon.com/powertools/python" rel="noopener noreferrer"&gt;&lt;strong&gt;AWS Lambda Powertools for Python&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;as a first-class citizen — not as an afterthought bolted on after the fact. Here's how it actually shapes each template.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch Processing with Partial Failure Handling
&lt;/h3&gt;

&lt;p&gt;This is where Powertools saves the most code — and prevents the most production incidents.&lt;/p&gt;

&lt;p&gt;Without Powertools, batch processing from SQS or streams requires you to manually track which records succeeded and which failed, then construct a &lt;code&gt;batchItemFailures&lt;/code&gt; response telling Lambda which messages to retry. Get it wrong and you either re-process successfully handled messages (causing duplicates) or silently drop failed ones.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;SQS&lt;/strong&gt; template uses &lt;code&gt;BatchProcessor&lt;/code&gt; to handle this automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.batch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;BatchProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;process_partial_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.batch.types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PartialItemFailureResponse&lt;/span&gt;

&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BatchProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SQS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to process record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;  &lt;span class="c1"&gt;# Re-raise so BatchProcessor marks it as a failed item
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PartialItemFailureResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;process_partial_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;record_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;handle_record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;handle_record&lt;/code&gt; raises for one message, &lt;code&gt;BatchProcessor&lt;/code&gt; catches it, logs the failure, continues processing the rest of the batch, and returns the correct &lt;code&gt;batchItemFailures&lt;/code&gt; response. Your DLQ only receives the genuinely failed messages — not the whole batch.&lt;/p&gt;

&lt;p&gt;The same pattern applies to &lt;strong&gt;DynamoDB Streams&lt;/strong&gt;, where handling partial failures is equally critical to prevent stream stalls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.batch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;BatchProcessor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;process_partial_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BatchProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DynamoDBStreams&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to process record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;  &lt;span class="c1"&gt;# Re-raise so BatchProcessor marks it as a failed item
&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;process_partial_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;record_handler&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;handle_record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Event Parsing and Handling
&lt;/h3&gt;

&lt;p&gt;Lambda Powertools really shines here. Whether it’s handling a Bedrock Agent tool use, REST API request, or a GraphQL query, Powertools provides resolvers that eliminate custom event parsing.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Bedrock Agent&lt;/strong&gt; template uses the &lt;code&gt;BedrockAgentFunctionResolver&lt;/code&gt; and the &lt;code&gt;@app.tool&lt;/code&gt; decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.event_handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentFunctionResolver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.data_classes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentEvent&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentFunctionResolver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;getItem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Gets item details by ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;


&lt;span class="nd"&gt;@app.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;createItem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creates a new item with name and optional description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;str | None = None) -&amp;gt; dict: ...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lambda entry point for the Bedrock Agent handler&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;REST API&lt;/strong&gt; template uses the &lt;code&gt;APIGatewayRestResolver&lt;/code&gt; and Flask-like decorators — meaning if you've used Flask or FastAPI, you'll feel right at home:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.event_handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APIGatewayRestResolver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.event_handler.api_gateway&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIGatewayRestResolver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/&amp;lt;id&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Retrieve an item by ID&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Create a new item from the request body&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json_body&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lambda entry point for the API Gateway handler&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;EventBridge&lt;/strong&gt; template uses the &lt;code&gt;event_parser&lt;/code&gt; to ensure your events match your Pydantic models before your logic even runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.parser&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;event_parser&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.parser.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EventBridgeModel&lt;/span&gt;


&lt;span class="nd"&gt;@event_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EventBridgeModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EventBridgeModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Combining Powertools with Pydantic
&lt;/h3&gt;

&lt;p&gt;One of the most useful patterns across the templates is combining Powertools event data classes with Pydantic models for end-to-end type safety.&lt;/p&gt;

&lt;p&gt;Powertools parses the raw Lambda event into a typed object (so you're not indexing into raw dicts). Pydantic then validates and deserializes the&amp;nbsp;&lt;em&gt;business payload&lt;/em&gt;&amp;nbsp;within that event:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.event_handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APIGatewayRestResolver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIGatewayRestResolver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Powertools resolves the typed API Gateway envelope
&lt;/span&gt;    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json_body&lt;/span&gt;
    &lt;span class="c1"&gt;# Pydantic validates the business payload
&lt;/span&gt;    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;strong&gt;Bedrock Agent&lt;/strong&gt; template, the same pattern applies via &lt;code&gt;BedrockAgentFunctionResolver&lt;/code&gt; — Powertools resolves the agent event, and typed function signatures replace manual parameter extraction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# templates/agent/handler.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.event_handler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentFunctionResolver&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.data_classes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentEvent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;templates.agent.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;

&lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentFunctionResolver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@app.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;getItem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Gets item details by ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Item &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; not found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;


&lt;span class="nd"&gt;@app.tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;createItem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creates a new item with name and optional description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;str | None = None) -&amp;gt; dict:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by_alias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exclude_none&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lambda entry point for the Bedrock Agent handler&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetching Parameters and Secrets
&lt;/h3&gt;

&lt;p&gt;In the &lt;strong&gt;EventBridge&lt;/strong&gt; template, the handler calls an external API using an API token stored in the &lt;strong&gt;Secrets Manager&lt;/strong&gt;. With Lambda Powertools, that adds exactly three lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.parameters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SecretsProvider&lt;/span&gt;

&lt;span class="n"&gt;secret_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecretsProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secret_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;secret_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same goes for loading configuration from the &lt;strong&gt;Parameter Store&lt;/strong&gt; (&lt;code&gt;SSMProvider&lt;/code&gt;), &lt;strong&gt;AppConfig&lt;/strong&gt; (&lt;code&gt;AppConfigProvider&lt;/code&gt;), or a &lt;strong&gt;DynamoDB&lt;/strong&gt; table (&lt;code&gt;DynamoDBProvider&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.utilities.parameters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SSMProvider&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SSMProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;configuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Structured Logging That Travels With Your Request
&lt;/h3&gt;

&lt;p&gt;The logger is initialized once at module level and injected into every handler via the&amp;nbsp;&lt;code&gt;@logger.inject_lambda_context&lt;/code&gt;&amp;nbsp;decorator. This automatically appends the Lambda context (function name, version, cold start flag, and AWS request ID) to every log line — without you writing a single line of configuration code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@logger.inject_lambda_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_event&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;APIGatewayProxyEventV2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output in CloudWatch is structured JSON from the first line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Processing request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"function_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-api-handler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cold_start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"aws_request_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc-123"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This matters at scale&lt;/strong&gt;: CloudWatch Logs Insights can now query your logs by any of these fields. Finding all cold starts, or all errors on a specific path, becomes a one-line query instead of a regex hunt through raw strings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracing Without Instrumentation Noise
&lt;/h3&gt;

&lt;p&gt;X-Ray tracing is applied via two decorators that require no additional configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tracer&lt;/span&gt;

&lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# On methods — creates child subsegments in X-Ray
&lt;/span&gt;&lt;span class="nd"&gt;@tracer.capture_method&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SQSRecord&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="c1"&gt;# On the Lambda handler — creates the root X-Ray segment
&lt;/span&gt;&lt;span class="nd"&gt;@tracer.capture_lambda_handler&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The&amp;nbsp;&lt;code&gt;@tracer.capture_lambda_handler&lt;/code&gt;&amp;nbsp;decorator creates the root X-Ray segment, and&amp;nbsp;&lt;code&gt;@tracer.capture_method&lt;/code&gt;&amp;nbsp;on Repository methods creates child subsegments — so your X-Ray service map shows handler → repository → DynamoDB as distinct, timed segments. You can see exactly where latency lives without writing a single&amp;nbsp;&lt;code&gt;xray_recorder.begin_subsegment()&lt;/code&gt;&amp;nbsp;call.&lt;/p&gt;

&lt;h3&gt;
  
  
  CloudWatch Metrics Without Custom Namespaces
&lt;/h3&gt;

&lt;p&gt;Most Lambda functions either skip custom metrics entirely — relying on the default Lambda service metrics — or end up with a tangled mix of&amp;nbsp;&lt;code&gt;boto3&lt;/code&gt;&amp;nbsp;CloudWatch&amp;nbsp;&lt;code&gt;put_metric_data&lt;/code&gt;&amp;nbsp;calls scattered across the codebase. Neither approach is great in production.Powertools solves this with the&amp;nbsp;&lt;code&gt;Metrics&lt;/code&gt;&amp;nbsp;utility, which uses&amp;nbsp;&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html" rel="noopener noreferrer"&gt;&lt;strong&gt;CloudWatch Embedded Metric Format (EMF)&lt;/strong&gt;&lt;/a&gt;&amp;nbsp;to emit custom metrics as structured log lines. No&amp;nbsp;&lt;code&gt;boto3&lt;/code&gt;&amp;nbsp;calls, no extra latency, no IAM permissions beyond what CloudWatch Logs already has.&lt;/p&gt;

&lt;p&gt;Each template initializes a&amp;nbsp;&lt;code&gt;Metrics&lt;/code&gt;&amp;nbsp;instance at module level with a shared namespace and service name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Metrics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;aws_lambda_powertools.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MetricUnit&lt;/span&gt;

&lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Metrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics_namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MetricUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@metrics.log_metrics&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LambdaContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The&amp;nbsp;&lt;code&gt;@metrics.log_metrics&lt;/code&gt;&amp;nbsp;decorator flushes all buffered metrics at the end of each invocation as a single EMF-formatted log line — CloudWatch automatically parses it and makes those metrics available in dashboards and alarms without any additional infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;capture_cold_start_metric=True&lt;/code&gt;&lt;/strong&gt;&amp;nbsp;is a one-liner that adds a&amp;nbsp;&lt;code&gt;ColdStart&lt;/code&gt;&amp;nbsp;metric to every function automatically. In production, tracking cold starts per function gives you a clear signal for when to invest in provisioned concurrency — no custom instrumentation needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started in Under 5 Minutes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Create your repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;a href="https://github.com/amrabed/aws-lambda-templates/generate" rel="noopener noreferrer"&gt;Use this template&lt;/a&gt; on GitHub to create a new repository from the template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Rename the project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After cloning, run the setup command once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make project &lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"new-name"&lt;/span&gt; &lt;span class="nv"&gt;DESCRIPTION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"New description"&lt;/span&gt; &lt;span class="nv"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Your Name"&lt;/span&gt; &lt;span class="nv"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"you@example.com"&lt;/span&gt; &lt;span class="nv"&gt;GITHUB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yourusername"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This renames all references throughout the codebase in a single step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Install and run&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nb"&gt;install&lt;/span&gt;      &lt;span class="c"&gt;# Install dependencies via Poetry&lt;/span&gt;
make precommit    &lt;span class="c"&gt;# Install pre-commit hooks&lt;/span&gt;
make &lt;span class="nb"&gt;test&lt;/span&gt;         &lt;span class="c"&gt;# Run tests with coverage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Deploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it. You're shipping production-grade Lambda code, not maintaining boilerplate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make deploy &lt;span class="nv"&gt;STACK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api    &lt;span class="c"&gt;# Deploy the REST API scenario&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Design Decisions Worth Noting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.14+&lt;/strong&gt;: The templates target the latest Python runtime. Lambda supports Python 3.14, and you should be using it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poetry over pip/requirements.txt&lt;/strong&gt;: Deterministic dependency resolution and lock files eliminate the "works on my machine" problem. &lt;code&gt;pyproject.toml&lt;/code&gt; is the single source of truth for the entire project configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Makefile as the interface&lt;/strong&gt;: All common operations — install, test, lint, deploy, docs — are exposed through &lt;code&gt;make&lt;/code&gt; commands. This creates a consistent interface regardless of the underlying tools, making CI/CD pipeline configuration trivial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;camelCase for JSON, snake_case for Python&lt;/strong&gt;: AWS services speak camelCase; Python speaks snake_case. Pydantic's &lt;code&gt;alias_generator=to_camel&lt;/code&gt; bridges the gap automatically, keeping both sides idiomatic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bedrock Agent Template
&lt;/h2&gt;

&lt;p&gt;One template deserves special mention: the &lt;strong&gt;Bedrock Agent&lt;/strong&gt; template. As generative AI workloads move to production on AWS, Lambda functions increasingly serve as the action executors behind Amazon Bedrock Agents. This template gives you a proper starting point for building agent action groups — with typed request/response models, error handling, and the exact response schema Bedrock expects.&lt;/p&gt;

&lt;p&gt;It's production-ready for the AI-native workloads being built today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;The repository is open source under the MIT license. Contributions are welcome — whether that's a new template scenario, improved infrastructure code, additional test coverage, or documentation improvements. Check out the &lt;a href="https://github.com/amrabed/aws-lambda-templates/blob/main/docs/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contributing guidelines&lt;/a&gt; to get started.&lt;/p&gt;




&lt;p&gt;If you're building on AWS Lambda and you find yourself writing the same setup for the third time, I hope &lt;code&gt;cur8d/lambda&lt;/code&gt; saves you that time and helps you ship better, more consistent serverless code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to start?&lt;/strong&gt; Head over to the repository and click &lt;strong&gt;"Use this template"&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/cur8d/lambda" rel="noopener noreferrer"&gt;&lt;strong&gt;github.com/cur8d/lambda&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>aws</category>
      <category>serverless</category>
      <category>lambda</category>
    </item>
    <item>
      <title>The Only AIP-C01 Study Plan You Need</title>
      <dc:creator>Amr Abed</dc:creator>
      <pubDate>Thu, 01 Oct 2026 02:30:26 +0000</pubDate>
      <link>https://dev.to/amrabed/the-only-aip-c01-study-plan-you-need-h9m</link>
      <guid>https://dev.to/amrabed/the-only-aip-c01-study-plan-you-need-h9m</guid>
      <description>&lt;h4&gt;
  
  
  &lt;em&gt;How I Passed as One of the First 5,000 — And the Exact Plan I&amp;nbsp;Used&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;I recently passed the new AWS Certified Generative AI Developer Professional (AIP-C01) exam as an early adopter (one of the first 5,000 worldwide). Here’s the exact 6-week plan I used, so you don’t have to figure it out from&amp;nbsp;scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjug2tkuwicggk9nzx318.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjug2tkuwicggk9nzx318.png" width="340" height="340"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Certified AWS Generative AI Developer Professional Badge&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What you’ll find here is a complete, curated, sequenced study plan — the one I wish someone had handed me before I started. No fluff, just the resources that matter, in the order they&amp;nbsp;matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this guide, you’ll&amp;nbsp;find:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Fast Track (if you’re short on&amp;nbsp;time)&lt;/li&gt;
&lt;li&gt;Detailed Study&amp;nbsp;Plan&lt;/li&gt;
&lt;li&gt;Notion Tracking&amp;nbsp;Template&lt;/li&gt;
&lt;li&gt;Time-Saving Lab Strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do I really need to&amp;nbsp;prepare?
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;“I have been using AWS Generative AI for the last year or so. Do I really need to prepare?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Short answer:&amp;nbsp;Yes!&lt;/p&gt;

&lt;p&gt;No matter how long you have been working with AWS Generative AI tools, you may not be using all the tools covered by the exam in your day-to-day experience, or you may not have encountered all the scenarios seen on the exam. That’s proven true for any AWS certification exam, not only this one. If you have taken any AWS certification exam before, you already know that. In short, being *AWS-*ome at what you do daily and passing an AWS certification exam are two different skills, though highly interconnected.&lt;/p&gt;

&lt;p&gt;That said, a minimum level of familiarity with the exam topic and at least some of the tools covered is required to pass. No amount of preparation can make up for that. Always make sure you are prepared before scheduling and taking the&amp;nbsp;exam.&lt;/p&gt;

&lt;h4&gt;
  
  
  How long does it&amp;nbsp;take?
&lt;/h4&gt;

&lt;p&gt;Plan for 6–8 weeks at roughly 2–3 hours per day, depending on your existing Bedrock experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  What to&amp;nbsp;expect?
&lt;/h4&gt;

&lt;p&gt;If you’re wondering how hard the AIP-C01 is, it felt harder than the AWS Machine Learning Specialty exam but more focused than the Solutions Architect exam. Expect Bedrock depth and several multi-service scenario questions. My practice scores plateaued at around 75% for the first couple of weeks, then eventually rose to around 95%. Don’t panic if progress feels slow mid-way. The domains click together in the final&amp;nbsp;stretch.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fast&amp;nbsp;Track
&lt;/h3&gt;

&lt;p&gt;If you are pressed for&amp;nbsp;time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide" rel="noopener noreferrer"&gt;Bedrock User Guide&lt;/a&gt; and the &lt;a href="https://skillbuilder.aws/learning-plan/9VXVGYT38G/exam-prep-plan-aws-certified-generative-ai-developer--professional-aipc01--english/4SCMN2659K" rel="noopener noreferrer"&gt;Exam Prep&amp;nbsp;Plan&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e1-7424609466043600896" rel="noopener noreferrer"&gt;Generative AI for Developers&lt;/a&gt; videos are highly recommended for some exam tips and&amp;nbsp;tricks&lt;/li&gt;
&lt;li&gt;You can just read only the topics that address any knowledge gaps you find in the &lt;a href="https://skillbuilder.aws/learning-plan/BGTH16YCTU/aws-generative-ai-developer-advanced-learning-plan-includes-labs/ZDN46CX881" rel="noopener noreferrer"&gt;Advanced Learning&amp;nbsp;Plan&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Notion Tracking&amp;nbsp;Template
&lt;/h3&gt;

&lt;p&gt;I have created a Notion database of study-plan items to track my preparation progress and group, sort, or filter by certification, plan, format, and domain. I am sharing it here so others can benefit as well. The database is available as a template at &lt;a href="http://amrabed.notion.site/aws-exam-prep" rel="noopener noreferrer"&gt;amrabed.notion.site/aws-exam-prep&lt;/a&gt;. Feel free to duplicate and use right&amp;nbsp;away.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The database has content for other exams as well. Remember to filter by certification for AWS Certified Generative AI Developer — Professional&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff68zewbn02o0i8wk5bzi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff68zewbn02o0i8wk5bzi.png" width="800" height="449"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Notion database for AWS Exam Preparation&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparation Material
&lt;/h3&gt;

&lt;p&gt;The AWS Training &amp;amp; Certification team recommends these two learning plans for preparation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learning-plan/9VXVGYT38G/exam-prep-plan-aws-certified-generative-ai-developer--professional-aipc01--english/4SCMN2659K" rel="noopener noreferrer"&gt;Exam Prep Plan: AWS Certified Generative AI Developer — Professional&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learning-plan/BGTH16YCTU/aws-generative-ai-developer-advanced-learning-plan-includes-labs/ZDN46CX881" rel="noopener noreferrer"&gt;AWS Generative AI Developer Advanced Learning Plan&lt;/a&gt; &lt;em&gt;(as&amp;nbsp;needed)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I added a couple more learning plans for more hands-on practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learning-plan/66NZQBVQD7/builder-labs-implement-generative-ai-and-agentic-applications/UYVE81N2Y7" rel="noopener noreferrer"&gt;Builder Labs: Implement Generative AI Applications on&amp;nbsp;AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learning-plan/CVTBV11V1K/aws-simulearn-generative-ai-architect/U39NTGR28K" rel="noopener noreferrer"&gt;AWS SimuLearn: Generative AI Architect&lt;/a&gt; or &lt;a href="https://skillbuilder.aws/learn/PFYH348EK2/aws-cloud-quest-generative-ai-architect/B3Q26P97G8" rel="noopener noreferrer"&gt;AWS Cloud Quest: Generative AI Architect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learning-plan/3HCD821CNZ/aws-simulearn-generative-ai-practitioner/BFKGA5VM8H" rel="noopener noreferrer"&gt;AWS SimuLearn: Generative AI Practitioner&lt;/a&gt; or &lt;a href="https://skillbuilder.aws/learn/5YB3FCEE1H/aws-cloud-quest-generative-ai-practitioner/26A81MG83V" rel="noopener noreferrer"&gt;AWS Cloud Quest: Generative AI Practitioner&lt;/a&gt; (&lt;em&gt;Free&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both the AWS SimuLearn and the AWS Cloud Quest plans share the same labs. The list below points to the AWS SimuLearn labs, but you may want to do the Cloud Quest plan instead to earn a training&amp;nbsp;badge.&lt;/p&gt;

&lt;p&gt;Amazon Web Services (AWS) also produced a dedicated LinkedIn Live 4-episode series for the exam, &lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e1-7424609466043600896" rel="noopener noreferrer"&gt;Generative AI for Developers&lt;/a&gt;. I highly recommend watching them for some exam tips and&amp;nbsp;tricks.&lt;/p&gt;

&lt;p&gt;Last but definitely not least, the &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide" rel="noopener noreferrer"&gt;Bedrock User Guide&lt;/a&gt; is a must-read for this exam. I have highlighted the most relevant parts for each domain&amp;nbsp;below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Create an&lt;/em&gt; &lt;a href="https://skillsprofile.skillbuilder.aws/" rel="noopener noreferrer"&gt;&lt;em&gt;AWS skills profile&lt;/em&gt;&lt;/a&gt; &lt;em&gt;if you don’t already have one. You will earn points and training badges during your preparation, and you want to showcase&amp;nbsp;them.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9wclf09d576efzgmr1r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9wclf09d576efzgmr1r4.png" width="800" height="560"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Skills&amp;nbsp;Profile&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Before you&amp;nbsp;start
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go over the &lt;a href="https://docs.aws.amazon.com/aws-certification/latest/ai-professional-01/ai-professional-01.html" rel="noopener noreferrer"&gt;Exam Guide&lt;/a&gt; 🆓 to understand the exam structure&lt;/li&gt;
&lt;li&gt;Take the &lt;a href="https://skillbuilder.aws/learn/HSEKTD11NX/official-practice-question-set-aws-certified--generative-ai-developer--professional-aipc01--english/ZDANP82P4V" rel="noopener noreferrer"&gt;Official Practice Question Set&lt;/a&gt; 🆓 to identify your knowledge gaps&lt;/li&gt;
&lt;li&gt;Go over the &lt;a href="https://skillbuilder.aws/learn/U91QQB8S2Q/exam-prep-overview-aws-certified-generative-ai-developer--professional-aipc01--english" rel="noopener noreferrer"&gt;Exam Prep Overview&lt;/a&gt;&amp;nbsp;🆓&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The 6-Week&amp;nbsp;Plan
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Day 0&lt;/strong&gt;: Exam guide + Practice Questions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 1–13&lt;/strong&gt;: Domain 1&amp;nbsp;(31%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 14–24&lt;/strong&gt;: Domain 2&amp;nbsp;(26%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 25–31&lt;/strong&gt;: Domain 3&amp;nbsp;(20%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 32–40&lt;/strong&gt;: Domains 4 &amp;amp; 5&amp;nbsp;(23%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 41–42&lt;/strong&gt;: Final Review &amp;amp;&amp;nbsp;Pretest&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  My Comprehensive Study&amp;nbsp;Plan
&lt;/h3&gt;

&lt;p&gt;I have curated the list below covering the readings, labs, videos, and practice questions from the material above in a recommended &lt;em&gt;best-effort&lt;/em&gt; sequence that aligns with the exam guide and provides the most comprehensive preparation.&lt;/p&gt;

&lt;p&gt;Most of the items on the list require a subscription. The free items are marked 🆓. The subscription is currently $29 per month — totally worth it! And, you can always try to complete all the paid items on the list within one month&amp;nbsp;😉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Please feel free to copy the list and use it as a preparation checklist.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Domain 1: FM Integration, Data Management, and Compliance
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html" rel="noopener noreferrer"&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/models.html" rel="noopener noreferrer"&gt;Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/bda.html" rel="noopener noreferrer"&gt;Data Automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base.html" rel="noopener noreferrer"&gt;Knowledge Bases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-engineering-guidelines.html" rel="noopener noreferrer"&gt;Prompt engineering concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-management.html" rel="noopener noreferrer"&gt;Prompt management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models.html" rel="noopener noreferrer"&gt;Model customization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hands-on Labs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Overview&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explore the Amazon Bedrock Playgrounds 🆓&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/ZCZVUZGPSS/aws-simulearn-get-started-with-generative-ai/T7TJ3K6WVZ" rel="noopener noreferrer"&gt;Get Started with Generative AI&lt;/a&gt;&amp;nbsp;🆓&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/2BDPR3RDK2/aws-simulearn-use-ai-services-with-amazon-sagemaker/FQCRQT43XZ" rel="noopener noreferrer"&gt;Use AI Services with Amazon SageMaker&lt;/a&gt; 🆓&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/UB55676Q4S/aws-simulearn-introduction-to-generative-ai/QS1YCMKAFR" rel="noopener noreferrer"&gt;Introduction to Generative AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/VENBUUH881/aws-simulearn-generative-ai-for-personalized-marketing/3NHRSJWH5S?parentId=U39NTGR28K" rel="noopener noreferrer"&gt;Generative AI for Personalized Marketing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Foundation Models&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/9DKZV5768F/lab--exploring-the-amazon-nova-micro-model-for-text-generation/2WPQYJMYH3" rel="noopener noreferrer"&gt;Exploring the Amazon Nova Micro Model for Text Generation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/E6PY767C2N/lab--exploring-amazon-nova-canvas-model-and-amazon-nova-reel-model-for-image-and-video-generation-and-editing/9YNXNBH3YE" rel="noopener noreferrer"&gt;Exploring Amazon Nova Canvas Model and Amazon Nova Reel Model for Image and Video Generation and&amp;nbsp;Editing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/YHFYBR9YTB/lab--exploring-amazon-nova-lite-model-for-multimodal-understanding/8G34Y3R1TR" rel="noopener noreferrer"&gt;Exploring Amazon Nova Lite Model for Multimodal Understanding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/NC3GDYFK1H/domain-1-practice-aws-simulearn--aws-certified-generative-ai-developer--professional-aipc01--english/261CTRTY13" rel="noopener noreferrer"&gt;Domain 1 Practice — Exploring Amazon Nova Models Using Amazon Bedrock Playgrounds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Prompt Engineering&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/FC13FQVQYG/aws-simulearn-prompt-engineering-with-amazon-bedrock/QDGW58VYHP" rel="noopener noreferrer"&gt;Prompt Engineering with Amazon&amp;nbsp;Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/Q86946Z2N6/aws-simulearn-code-generation-with-prompt-engineering/E9X7TRY1QP" rel="noopener noreferrer"&gt;Code Generation with Prompt Engineering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Knowledge Bases&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/7E4FETUE2Y/aws-simulearn-create-an-enterprise-knowledge-assistant/2F4Q5XU8WB" rel="noopener noreferrer"&gt;Create an Enterprise Knowledge Assistant&lt;/a&gt; 🆓&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/82XQH1A396/aws-simulearn-enhance-llm-capabilities-with-a-vector-database/7354CYJWJR" rel="noopener noreferrer"&gt;Enhance LLM Capabilities with a Vector&amp;nbsp;Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/49C422WMXP/aws-simulearn-modern-data-architectures-with-llms/BXJVWVR5ZX" rel="noopener noreferrer"&gt;Modern Data Architectures with&amp;nbsp;LLMs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/8EJFZ7R45W/lab--develop-retrieval-augmented-generation-rag-applications-with-amazon-bedrock-knowledge-bases/7B21X9MR8W" rel="noopener noreferrer"&gt;Develop RAG Applications with Amazon Bedrock Knowledge Bases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/JRGWCFYT67/lab--build-and-evaluate-retrieval-augmented-generation-rag-applications-using-knowledge-bases-for-amazon-bedrock/A4MN58JB7A" rel="noopener noreferrer"&gt;Build and Evaluate RAG Applications using Knowledge Bases for Amazon&amp;nbsp;Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/FWEY6R46Q3/lab--intelligent-document-processing-for-financial-services-industry/7USBXQZE5Q" rel="noopener noreferrer"&gt;Intelligent Document Processing for the Financial Services&amp;nbsp;Industry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/UHZTEZPYG6/aws-simulearn-nocode-insights-extraction-using-generative-ai/TTMWH3EU1C" rel="noopener noreferrer"&gt;No-Code Insights Extraction Using Generative AI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Fine Tuning&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/9V57WCXR4B/aws-simulearn-finetuning-an-llm-on-amazon-sagemaker/W3HW8X5NDX" rel="noopener noreferrer"&gt;Fine-Tuning an LLM on Amazon SageMaker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/AJY3PDJ476/aws-simulearn-automate-finetuning-of-an-llm/EEZRBZXXW9" rel="noopener noreferrer"&gt;Automate Fine-Tuning of an&amp;nbsp;LLM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/AT1JAP9Y95/aws-simulearn-finetune-a-base-model-with-rlhf/SZD4BQF742" rel="noopener noreferrer"&gt;Fine-Tune a Base Model with&amp;nbsp;RLHF&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review and Questions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/GT2P1KK636/domain-1-review-aws-certified-generative-ai-developer--professional-aipc01-english/4GWFTZBZ74" rel="noopener noreferrer"&gt;Domain 1 Review&lt;/a&gt;&amp;nbsp;🆓&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/V5N6SFRR6S/domain-1-practice-aws-certified-generative-ai-developer--professional-aipc01-english/NRSMYNRGY3" rel="noopener noreferrer"&gt;Domain 1 Questions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e1-7424609466043600896/theater" rel="noopener noreferrer"&gt;Generative AI For Developers | S1 E1 | Exam Overview and FM Integrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/9J5FH9NB4R/aws-generative-ai-developer--analyze-requirements-and-design-generative-ai-solutions/MWP57JVX51" rel="noopener noreferrer"&gt;Analyze Requirements and Design Generative AI Solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/4X8CFYAMFR/aws-generative-ai-developer--select-and-configure-foundation-models/7FXZYRFQA6" rel="noopener noreferrer"&gt;Select and Configure Foundation Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/697EZTMUJU/aws-generative-ai-developer--implement-data-validation-and-processing-pipelines/T58PCURDU8" rel="noopener noreferrer"&gt;Implement data validation and processing pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/XU57YH2BKJ/aws-generative-ai-developer--design-and-implement-vector-store-solutions/QHZVNUHSP4" rel="noopener noreferrer"&gt;Design and Implement Vector Store Solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/BFXZR1G81B/aws-generative-ai-developer--design-retrieval-mechanisms-for-fm-augmentation/R64WEX5EJQ" rel="noopener noreferrer"&gt;Design Retrieval Mechanisms for FM Augmentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/AZ7ZCM788F/aws-generative-ai-developer--implement-prompt-engineering-strategies-and-governance/G4NTVS56ZT" rel="noopener noreferrer"&gt;Implement Prompt Engineering Strategies and Governance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Domain 2: Implementation and Integration
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/agents.html" rel="noopener noreferrer"&gt;Agents: Automate&amp;nbsp;tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/tool-use.html" rel="noopener noreferrer"&gt;Tool use&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/inference.html" rel="noopener noreferrer"&gt;Inference: Generate responses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/amazon-bedrock-marketplace.html" rel="noopener noreferrer"&gt;Amazon Bedrock Marketplace&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/flows.html" rel="noopener noreferrer"&gt;Flows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/sessions.html" rel="noopener noreferrer"&gt;Session management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hands-on Labs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Agentic AI&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/PT6HBMUFM8/aws-simulearn-create-an-ai-smart-assistant/9VN4PQCUR8" rel="noopener noreferrer"&gt;Create an AI Smart Assistant&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/4ETUEUZRB1/aws-simulearn-build-and-deploy-tools-using-llm-agents/M7VV5H3EQC" rel="noopener noreferrer"&gt;Build and Deploy Tools Using LLM&amp;nbsp;Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/EYJP8ZK9VK/lab--explore-amazon-bedrock-agents-integrated-with-amazon-bedrock-knowledge-bases-and-amazon-bedrock-guardrails/R3GGAEJHGG" rel="noopener noreferrer"&gt;Explore Amazon Bedrock Agents integrated with Amazon Bedrock Knowledge Bases and Amazon Bedrock Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/BGXTVZ2DPE/aws-simulearn-financial-insights-with-multimodal-agents/PJJUWE8UXB" rel="noopener noreferrer"&gt;Financial Insights with Multimodal Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/ZUWYHSY7FZ/lab--explore-generative-ai-use-cases-with-langchain-and-amazon-bedrock/HADKRVY9AU" rel="noopener noreferrer"&gt;Explore Generative AI Use Cases with LangChain and Amazon&amp;nbsp;Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Model Deployment &amp;amp; Integration&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/67YQK61VA2/aws-simulearn-harness-the-power-of-langchain/7FRRY3YXUZ" rel="noopener noreferrer"&gt;Harness the Power of LangChain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/DABTKGUWNU/aws-simulearn-intelligent-video-and-audio-qa-with-llms/WJ5DNJUJPB" rel="noopener noreferrer"&gt;Intelligent Video and Audio Q&amp;amp;A with&amp;nbsp;LLMs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/JVCXW4FCXN/aws-simulearn-generate-an-aws-qa-application/115N1G8V1C" rel="noopener noreferrer"&gt;Generate an AWS Q&amp;amp;A Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/X68QZAMTTR/aws-simulearn-serverless-chatbot-using-private-data/NVMAXPWEDA" rel="noopener noreferrer"&gt;Serverless Chatbot Using Private&amp;nbsp;Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/BS5JKBDZJU/aws-simulearn-generative-ai-app-for-teaching-and-learning/QVX1D419KT" rel="noopener noreferrer"&gt;Generative AI App for Teaching and&amp;nbsp;Learning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/HEUG44UCYW/aws-simulearn-build-generative-ai-apps-with-foundation-models/J7X4P4FKME" rel="noopener noreferrer"&gt;Build Generative AI Apps with Foundation Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/46TU77TNJG/lab--develop-conversation-pattern-with-amazon-bedrock-apis/6319ZBY9Z4" rel="noopener noreferrer"&gt;Develop Conversation Pattern with Amazon Bedrock&amp;nbsp;APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/QD6GGAVZXS/lab--integrate-amazon-bedrock-foundation-models-into-a-serverless-app/5XTGQEF5TV" rel="noopener noreferrer"&gt;Integrate Amazon Bedrock Foundation Models into a Serverless App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/EZYZ4XS4CS/lab--create-functions-using-aws-sdk-for-python-with-amazon-bedrock-api/AKJ7YYSGJN" rel="noopener noreferrer"&gt;Create functions using AWS SDK for Python with Amazon Bedrock&amp;nbsp;API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/VECTFQJ18G/lab--build-productionready-generative-ai-applications-on-aws/B1B29VA81R?parentId=UYVE81N2Y7" rel="noopener noreferrer"&gt;Build Production-Ready Generative AI Applications on&amp;nbsp;AWS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/G9DCFD6UCB/domain-2-practice-aws-simulearn--aws-certified-generative-ai-developer--professional-aipc01--english/9FJJU2CTMS" rel="noopener noreferrer"&gt;Domain 2 Practice — Document Processing with Amazon&amp;nbsp;Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Development Tools&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/XR5XSR3BHZ/aws-simulearn-generate-code-for-a-webpage/SFXMVX8EFH" rel="noopener noreferrer"&gt;Generate Code for a Webpage&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/Y2FQ5WF2R2/aws-simulearn-build-and-understand-code-with-amazon-q/1C5TAE62YQ" rel="noopener noreferrer"&gt;Build and Understand Code with Amazon Q&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/W77W8SC1U6/aws-simulearn-improve-code-quality-using-generative-ai/71DWERDPX2" rel="noopener noreferrer"&gt;Improve Code Quality Using Generative AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/CFU2FUX3C6/lab--implement-security-fixes-to-codebase-using-amazon-q-developer/B7RAF1BU6N" rel="noopener noreferrer"&gt;Implement Security Fixes to Codebase using Amazon Q Developer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review and Questions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/AK4C3YGY67/domain-2-review-aws-certified-generative-ai-developer--professional-aipc01--english/NJ1JV3UWM9" rel="noopener noreferrer"&gt;Domain 2 Review&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/RVEJWM1KBZ/domain-2-practice-aws-certified-generative-ai-developer--professional-aipc01--english/SVE4Q3JSN3" rel="noopener noreferrer"&gt;Domain 2 Questions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e2-7427431654769594369/theater" rel="noopener noreferrer"&gt;Generative AI For Developers | S1 E2 | Implementation and Integration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/EFHFQHUM7R/aws-generative-ai-developer--agentic-ai-solutions-and-tool-integrations/P7JC8RMXSU" rel="noopener noreferrer"&gt;Agentic AI Solutions and Tool Integrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/QE4JV2ZM2J/aws-generative-ai-developer--model-deployment-strategies/CEVRFXYVGN" rel="noopener noreferrer"&gt;Model Deployment Strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/WJW5Y7GEGJ/aws-generative-ai-developer--enterprise-integration-architectures/GFT1NS9GE6" rel="noopener noreferrer"&gt;Enterprise Integration Architectures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/SWBETBZRSG/aws-generative-ai-developer--foundation-model-api-integrations/UCQPEKXKSS" rel="noopener noreferrer"&gt;Foundation Model API Integrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/B1XJFH5DYA/aws-generative-ai-developer--implement-application-integration-patterns-and-development-tools/PDGRMSKNVD" rel="noopener noreferrer"&gt;Implement Application Integration Patterns and Development Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Domain 3: AI Safety, Security, and Governance
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/security-overview.html" rel="noopener noreferrer"&gt;Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html" rel="noopener noreferrer"&gt;Bedrock Guardrails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hands-on Labs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/6XKW5KV9FS/aws-simulearn-secure-conversational-ai-with-guardrails/R6NFKDHSND" rel="noopener noreferrer"&gt;Secure Conversational AI with Guardrails&lt;/a&gt; 🆓&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/MFJEGXVW7B/aws-simulearn-set-up-private-access-to-amazon-bedrock/D3KX66AZKB" rel="noopener noreferrer"&gt;Set Up Private Access to Amazon&amp;nbsp;Bedrock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/D4UVDVA8GE/aws-simulearn-provision-sagemaker-in-a-secure-environment/M8XRRN2TPR?parentId=U39NTGR28K" rel="noopener noreferrer"&gt;Provision SageMaker in a Secure Environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/DEFW74BV18/lab--building-secure-and-responsible-gen-ai-with-guardrails-for-amazon-bedrock/EWW6F5XMSH" rel="noopener noreferrer"&gt;Building Secure and Responsible Generative AI with GuardRails&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/V3VK57AYEK/aws-simulearn-moderate-generative-ai-chat-app-conversations/ECJXM14K7Z" rel="noopener noreferrer"&gt;Moderate Generative AI Chat App Conversations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/ZDUNTYGAC8/aws-simulearn-moderator-for-generative-ai-content/QYHZDNUZHK" rel="noopener noreferrer"&gt;Moderator for Generative AI&amp;nbsp;Content&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/7ZWAKHCJ39/aws-simulearn-bias-mitigation-for-a-translation-service/HGKPZPAY13" rel="noopener noreferrer"&gt;Bias Mitigation for a Translation Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/EB4JJXDGKZ/lab--monitor-a-model-for-data-drift/F8YT3RH3ZA" rel="noopener noreferrer"&gt;Monitor a Model for Data&amp;nbsp;Drift&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review and Questions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/9UFTNQDJ8U/domain-3-review-aws-certified-generative-ai-developer--professional-aipc01--english/J43656ADK3" rel="noopener noreferrer"&gt;Domain 3 Review&lt;/a&gt;&amp;nbsp;🆓&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/ASBN3JAAUG/domain-3-practice-aws-certified-generative-ai-developer--professional-aipc01--english/SUU236RXNR" rel="noopener noreferrer"&gt;Domain 3 Questions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e3-7429961169710297088/theater" rel="noopener noreferrer"&gt;Generative AI For Developers | S1 E3 | AI Safety, Security, and Governance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/9U6AYCC64R/aws-generative-ai-developer--safe-user-interactions-with-generative-ai-applications/RRCESSXBYG" rel="noopener noreferrer"&gt;Safe User Interactions with Generative AI Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/SD43YU6AYA/aws-generative-ai-developer--implement-data-security-and-privacy-controls/EY9XC5AXFR" rel="noopener noreferrer"&gt;Implement Data Security and Privacy&amp;nbsp;Controls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/ESR9ZRK27V/aws-generative-ai-developer--implement-ai-governance-compliance-and-transparency/P93ZF42V9J" rel="noopener noreferrer"&gt;Implement AI Governance, Compliance, and Transparency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Domain 4: Operational Efficiency and Optimization for AI Applications
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/capacity-limits-cost-optimization.html" rel="noopener noreferrer"&gt;Capacity, Limits, and Cost Optimization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/monitoring.html" rel="noopener noreferrer"&gt;Monitoring&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review and Questions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/PEYR7XMDFQ/domain-4-review-aws-certified-generative-ai-developer--professional-aipc01--english/RKHB3VMJ23" rel="noopener noreferrer"&gt;Domain 4 Review&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/E78PRJA6T4/domain-4-practice-aws-certified-generative-ai-developer--professional-aipc01--english/NSE8TTQEZ8" rel="noopener noreferrer"&gt;Domain 4 Questions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e4-7432203857402916864/theater" rel="noopener noreferrer"&gt;Generative AI For Developers | S1 E4 | Operations and Troubleshooting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/C7DDZ8ETP4/aws-generative-ai-developer--implementing-cost-optimization-and-resource-efficiency-strategies/VD6YGCBDPG" rel="noopener noreferrer"&gt;Implementing Cost Optimization and Resource Efficiency Strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/C3CQ1ZJ212/aws-generative-ai-developer--optimize-application-performance/9KT2NT8H8U" rel="noopener noreferrer"&gt;Optimize Application Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/YJZUP11TPR/aws-generative-ai-developer--implement-monitoring-systems/QHPEZJM69R" rel="noopener noreferrer"&gt;Implement Monitoring Systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Domain 5: Testing, Validation, and Troubleshooting
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/evaluation.html" rel="noopener noreferrer"&gt;Evaluate models&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Review and Questions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://skillbuilder.aws/learn/UHY3CG2Q5T/domain-5-review-aws-certified-generative-ai-developer--professional-aipc01--english/Q6K7K67UEW" rel="noopener noreferrer"&gt;Domain 5 Review&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/P3ENCEB2E7/domain-5-practice-aws-certified-generative-ai-developer--professional-aipc01--english/HNDP65ZV2F" rel="noopener noreferrer"&gt;Domain 5 Bonus Questions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt; 🆓&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/events/generativeaifordevelopers-s1e4-7432203857402916864/theater" rel="noopener noreferrer"&gt;&lt;em&gt;Episode 4&lt;/em&gt;&lt;/a&gt; &lt;em&gt;also covers domain 5 in the last 10&amp;nbsp;minutes&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Reading&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/AM9M42X85W/aws-generative-ai-developer--implement-evaluation-systems-for-generative-ai/YFBR1Z47E3" rel="noopener noreferrer"&gt;Implement Evaluation Systems for Generative AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://skillbuilder.aws/learn/WB1ECBCME1/aws-generative-ai-developer--troubleshoot-generative-ai-applications/8CPC5ZV39G" rel="noopener noreferrer"&gt;Troubleshoot Generative AI Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Final Review and&amp;nbsp;Pretest
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Go over the &lt;a href="https://skillbuilder.aws/learn/F67DBSMZ9V/exam-prep-summary-aws-certified-generative-ai-developer--professional-aipc01--english/RFJWMN3DXQ" rel="noopener noreferrer"&gt;Exam Prep Summary&lt;/a&gt;&amp;nbsp;&lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Retake: &lt;a href="https://skillbuilder.aws/learn/U91QQB8S2Q/exam-prep-overview-aws-certified-generative-ai-developer--professional-aipc01--english/SZ29259FX6" rel="noopener noreferrer"&gt;Official Practice Question Set&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/YZDUMAQABG/aws-simulearn-explore-the-amazon-bedrock-playgrounds/88NAE39D3Z" rel="noopener noreferrer"&gt;🆓,&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/V5N6SFRR6S/domain-1-practice-aws-certified-generative-ai-developer--professional-aipc01-english/NRSMYNRGY3" rel="noopener noreferrer"&gt;Domain 1 Questions,&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/RVEJWM1KBZ/domain-2-practice-aws-certified-generative-ai-developer--professional-aipc01--english/SVE4Q3JSN3" rel="noopener noreferrer"&gt;Domain 2 Questions,&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/ASBN3JAAUG/domain-3-practice-aws-certified-generative-ai-developer--professional-aipc01--english/SUU236RXNR" rel="noopener noreferrer"&gt;Domain 3 Questions,&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/E78PRJA6T4/domain-4-practice-aws-certified-generative-ai-developer--professional-aipc01--english/NSE8TTQEZ8" rel="noopener noreferrer"&gt;Domain 4 Questions,&lt;/a&gt; &lt;a href="https://skillbuilder.aws/learn/P3ENCEB2E7/domain-5-practice-aws-certified-generative-ai-developer--professional-aipc01--english/HNDP65ZV2F" rel="noopener noreferrer"&gt;Domain 5 Questions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Take the &lt;a href="https://skillbuilder.aws/learn/24FDAZ9UKG/official-pretest-aws-certified--generative-ai-developer--professional-aipc01--english/VFBSB1C83U" rel="noopener noreferrer"&gt;Official&amp;nbsp;Pretest&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Bonus
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Take the &lt;a href="https://skillbuilder.aws/learn/32Y249P272/aws-agentic-ai-demonstrated/TTAJ5WKYTS" rel="noopener noreferrer"&gt;AWS Agentic AI Demonstrated&lt;/a&gt; microcredential&lt;/li&gt;
&lt;li&gt;Play the Generative AI track on &lt;a href="https://cardclash.skillbuilder.aws/" rel="noopener noreferrer"&gt;AWS Card Clash&lt;/a&gt; just for&amp;nbsp;fun!&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Would you still like&amp;nbsp;more?
&lt;/h4&gt;

&lt;p&gt;If you need even more training, you can always search the AWS Skill Builder content with filters&amp;nbsp;like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Roles&lt;/em&gt;: Generative AI Development Engineer&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Format&lt;/em&gt;: Learning&amp;nbsp;plan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvao1agu51c4l36szuapt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvao1agu51c4l36szuapt.png" width="800" height="693"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;AWS Skill Builder Gen AI Learning&amp;nbsp;Plans&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Time-Saving Tips
&lt;/h3&gt;

&lt;p&gt;As you see in the study plan above, there is a lot to cover, ideally in no more than a month or two. So, you’ll need to save as much time as you can during your preparation. Here are a few tips and tricks based on my experience, especially if you decide to take the hands-on labs. You will notice that most of the lab time is consumed by provisioning the environment, deploying model endpoints, and running Jupyter notebooks. Here is how you can finish the labs&amp;nbsp;faster.&lt;/p&gt;

&lt;h4&gt;
  
  
  No idle&amp;nbsp;time
&lt;/h4&gt;

&lt;p&gt;While the lab environment is being provisioned, don’t wait for provisioning to complete before starting. Go through the instructions for all three stages (Learn, Practice, and DIY) to hit the ground running once the environment is&amp;nbsp;ready.&lt;/p&gt;

&lt;h4&gt;
  
  
  Parallelize tasks
&lt;/h4&gt;

&lt;p&gt;Many DIY sections do not depend on the practice sections, which means you can complete both practice and DIY together. For instance, the practice section may ask you to start a 2-instance cluster, which the DIY asks to scale up to 3 instances. You can just go ahead and start a 3-instance cluster right away. Moreover, some steps are independent of one another, so open multiple tabs and continue to the next step while the current one completes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Run all&amp;nbsp;cells
&lt;/h4&gt;

&lt;p&gt;For the Jupyter notebooks, skim through the notebook to understand the concepts, add any missing configuration or code, then run all cells rather than cell by&amp;nbsp;cell.&lt;/p&gt;

&lt;h4&gt;
  
  
  Split screen
&lt;/h4&gt;

&lt;p&gt;This is not technically a preparation tip, but it helps. Once the AWS sandbox environment is loaded, split the screen between the lab window with instructions and the AWS environment window to follow along more&amp;nbsp;quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to schedule the&amp;nbsp;exam
&lt;/h3&gt;

&lt;p&gt;I prefer to schedule the exam only when I can answer at least 90% of the questions correctly, with each question taking no more than 90 seconds on average. That gives me confidence that I can pass the exam smoothly, even under the added&amp;nbsp;stress.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I only schedule the exam when I can hit 90%+ accuracy, spending no more than 90 seconds per question. That’s my personal go/no-go&amp;nbsp;signal.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;If you want to dig deeper into some of the topics covered in the exam, here are a few AWS resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/index.html" rel="noopener noreferrer"&gt;Amazon Bedrock User Guide&lt;/a&gt; (&lt;em&gt;A must-read for this&amp;nbsp;exam&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/index.html" rel="noopener noreferrer"&gt;AgentCore Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html" rel="noopener noreferrer"&gt;AWS Well-Architected Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html" rel="noopener noreferrer"&gt;AWS Step Functions Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/sagemaker/latest/dg" rel="noopener noreferrer"&gt;Amazon SageMaker AI Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/opensearch-service/latest/developerguide/index.html" rel="noopener noreferrer"&gt;Amazon OpenSearch Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A big thank-you to the AWS Training &amp;amp; Certification team for the incredibly well-structured content on AWS Skill Builder. The domain-by-domain video series, the hands-on labs, and the Official Practice Questions were the backbone of my preparation. This article is essentially a curated map of their&amp;nbsp;work.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;I passed this exam before most study guides existed. If this plan helped you pass or saved you time, let me know in a comment. I’d love to hear what worked best for you, and what you’d add. If you find it useful, share it with the next engineer searching for where to start and give it a clap 👏 (or 50 😉) — it helps other engineers find&amp;nbsp;it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>generativeai</category>
      <category>awscertification</category>
    </item>
  </channel>
</rss>
