<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[AI Research by Vedant Pandya]]></title><description><![CDATA[AI Research by Vedant Pandya]]></description><link>https://airesearch.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 08 Sep 2026 19:47:47 GMT</lastBuildDate><atom:link href="https://airesearch.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Unlocking the Power of Hybrid RAG Systems: A Deep Dive into LlamaCloud's City Query Solution]]></title><description><![CDATA[Project Overview
This project implements a hybrid Retrieval-Augmented Generation (RAG) system that combines structured database queries with unstructured document retrieval. The application allows users to ask natural language questions about US citi...]]></description><link>https://airesearch.hashnode.dev/unlocking-the-power-of-hybrid-rag-systems-a-deep-dive-into-llamaclouds-city-query-solution</link><guid isPermaLink="true">https://airesearch.hashnode.dev/unlocking-the-power-of-hybrid-rag-systems-a-deep-dive-into-llamaclouds-city-query-solution</guid><category><![CDATA[Gemini2]]></category><category><![CDATA[Hybrid RAG Systems]]></category><category><![CDATA[Structured and Unstructured Data]]></category><category><![CDATA[LlamaCloud Document Retrieval]]></category><category><![CDATA[Gemini 2.0 Flash Integration]]></category><category><![CDATA[Intelligent Query Routing]]></category><category><![CDATA[SQL and Document Retrieval Integration]]></category><category><![CDATA[Semantic Retrieval]]></category><category><![CDATA[LlamaIndex for SQL Conversion]]></category><category><![CDATA[RAG ]]></category><category><![CDATA[LlamaIndex]]></category><category><![CDATA[SQL]]></category><category><![CDATA[Retrieval-Augmented Generation]]></category><category><![CDATA[natural language processing]]></category><dc:creator><![CDATA[Vedant Pandya]]></dc:creator><pubDate>Fri, 14 Mar 2025 12:47:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741956343236/be68324f-5420-4634-ac1d-4e0db1dcd6fc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h2 id="heading-project-overview">Project Overview</h2>
<p>This project implements a hybrid Retrieval-Augmented Generation (RAG) system that combines structured database queries with unstructured document retrieval. The application allows users to ask natural language questions about US cities and receive accurate, contextual responses. The system uses a dual-pipeline approach:</p>
<ol>
<li><p><strong>Structured Data Pipeline</strong>: SQL database containing city statistics (population, state)</p>
</li>
<li><p><strong>Unstructured Data Pipeline</strong>: LlamaCloud for document retrieval of general city information</p>
</li>
</ol>
<p>The application is built with a Streamlit frontend that provides an intuitive chat interface, allowing users to interact with the system conversationally.</p>
<hr />
<h2 id="heading-architecture-details">Architecture Details</h2>
<h3 id="heading-component-breakdown">Component Breakdown</h3>
<h4 id="heading-1-user-interface-layer">1. User Interface Layer</h4>
<ul>
<li><p><strong>Technology</strong>: Streamlit</p>
</li>
<li><p><strong>Purpose</strong>: Provides chat interface, API key configuration, and displays responses</p>
</li>
<li><p><strong>Key Features</strong>:</p>
<ul>
<li><p>Chat history tracking using session state</p>
</li>
<li><p>Sidebar configuration for API keys and LlamaCloud settings</p>
</li>
<li><p>Real-time response generation with loading indicators</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-2-structured-data-layer">2. Structured Data Layer</h4>
<ul>
<li><p><strong>Technology</strong>: SQLite (in-memory), SQLAlchemy</p>
</li>
<li><p><strong>Purpose</strong>: Stores and queries factual city information</p>
</li>
<li><p><strong>Components</strong>:</p>
<ul>
<li><p><code>setup_database()</code>: Initializes the database with city data</p>
</li>
<li><p><code>CityQueryEngine</code>: Custom class for direct SQL querying</p>
</li>
<li><p><code>NLSQLTableQueryEngine</code>: LlamaIndex component for natural language to SQL conversion</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-3-unstructured-data-layer">3. Unstructured Data Layer</h4>
<ul>
<li><p><strong>Technology</strong>: LlamaCloud</p>
</li>
<li><p><strong>Purpose</strong>: Stores and retrieves document-based city information</p>
</li>
<li><p><strong>Components</strong>:</p>
<ul>
<li><p><code>LlamaCloudIndex</code>: Connects to pre-indexed documents in LlamaCloud</p>
</li>
<li><p>Vector query engine for semantic retrieval</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-4-llm-integration-layer">4. LLM Integration Layer</h4>
<ul>
<li><p><strong>Technology</strong>: Gemini 2.0 Flash</p>
</li>
<li><p><strong>Purpose</strong>: Natural language understanding and response generation</p>
</li>
<li><p><strong>Components</strong>:</p>
<ul>
<li><p>Text generation model for synthesizing responses</p>
</li>
<li><p>Embedding model for vector search (when needed)</p>
</li>
</ul>
</li>
</ul>
<h4 id="heading-5-query-orchestration-layer">5. Query Orchestration Layer</h4>
<ul>
<li><p><strong>Purpose</strong>: Routes queries to appropriate backends based on content</p>
</li>
<li><p><strong>Logic</strong>:</p>
<ul>
<li><p>Population/statistic queries → SQL pipeline</p>
</li>
<li><p>General information queries → LlamaCloud pipeline</p>
</li>
</ul>
</li>
</ul>
<hr />
<h2 id="heading-data-flow">Data Flow</h2>
<ol>
<li><p><strong>Input Phase</strong>:</p>
<ul>
<li><p>User submits query through Streamlit chat interface</p>
</li>
<li><p>Query is added to chat history</p>
</li>
<li><p>System analyzes query content</p>
</li>
</ul>
</li>
<li><p><strong>Processing Phase</strong>:</p>
<ul>
<li><p>If query contains population keywords:</p>
<ul>
<li><p>First attempt direct SQL via pattern matching</p>
</li>
<li><p>Fall back to NLSQLTableQueryEngine if needed</p>
</li>
</ul>
</li>
<li><p>If query is about general information:</p>
<ul>
<li>Route to LlamaCloud vector search</li>
</ul>
</li>
<li><p>Response is generated using retrieved context</p>
</li>
</ul>
</li>
<li><p><strong>Output Phase</strong>:</p>
<ul>
<li><p>Response displayed in chat interface</p>
</li>
<li><p>Source of information (Database or LlamaCloud) is displayed</p>
</li>
<li><p>Response added to chat history</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-implementation-details">Implementation Details</h2>
<h3 id="heading-database-schema">Database Schema</h3>
<ul>
<li>The application uses a simple SQLite database with a single table:</li>
</ul>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> city_stats (
    city_name <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">16</span>) PRIMARY <span class="hljs-keyword">KEY</span>,
    population <span class="hljs-built_in">INTEGER</span>,
    state <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">16</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>
);
</code></pre>
<p>Data is populated with information about six major US cities:</p>
<ul>
<li><p>New York City (New York)</p>
</li>
<li><p>Los Angeles (California)</p>
</li>
<li><p>Chicago (Illinois)</p>
</li>
<li><p>Houston (Texas)</p>
</li>
<li><p>Miami (Florida)</p>
</li>
<li><p>Seattle (Washington)</p>
</li>
</ul>
<hr />
<h2 id="heading-sql-query-engine">SQL Query Engine</h2>
<p>The custom <code>CityQueryEngine</code> class provides specialized query capabilities:</p>
<ol>
<li><p><strong>Direct Execution</strong>: <code>execute_query()</code> method runs raw SQL and formats results</p>
</li>
<li><p><strong>Specialized Queries</strong>:</p>
<ul>
<li><p><code>query_highest_population()</code>: Finds city with highest population</p>
</li>
<li><p><code>query_lowest_population()</code>: Finds city with lowest population</p>
</li>
<li><p><code>query_all_cities_ranked()</code>: Orders all cities by population</p>
</li>
<li><p><code>query_by_state()</code>: Filters cities by state name</p>
</li>
</ul>
</li>
<li><p><strong>Natural Language Processing</strong>:</p>
<ul>
<li><p><code>process_population_query()</code>: Uses regular expressions and keyword matching to convert natural language to appropriate SQL queries</p>
</li>
<li><p>Pattern matching for terms like "highest", "lowest", "in [state]", etc.</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-llamacloud-integration">LlamaCloud Integration</h2>
<p>The application connects to LlamaCloud for document retrieval:</p>
<ol>
<li><p><strong>Configuration</strong>:</p>
<ul>
<li><p>API key</p>
</li>
<li><p>Organization ID</p>
</li>
<li><p>Project name</p>
</li>
<li><p>Index name</p>
</li>
</ul>
</li>
<li><p><strong>Index Connection</strong>:</p>
<ul>
<li><p>Creates <code>LlamaCloudIndex</code> object</p>
</li>
<li><p>Configures vector query engine</p>
</li>
</ul>
</li>
<li><p><strong>Query Execution</strong>:</p>
<ul>
<li><p>Sends natural language query directly to LlamaCloud</p>
</li>
<li><p>Retrieves relevant document chunks</p>
</li>
<li><p>Uses context for response generation</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-model-configuration">Model Configuration</h2>
<p>The application uses Gemini 2.0 Flash for both understanding and generation:</p>
<ol>
<li><p><strong>LLM Model</strong>:</p>
<pre><code class="lang-python"> gemini_model = Gemini(
     model=<span class="hljs-string">"models/gemini-2.0-flash"</span>,
     api_key=st.session_state.GOOGLE_API_KEY,
     temperature=<span class="hljs-number">0.2</span>
 )
</code></pre>
</li>
<li><p><strong>Embedding Model</strong>:</p>
<pre><code class="lang-python"> gemini_embed_model = GeminiEmbedding(
     model_name=<span class="hljs-string">"models/embedding-001"</span>,
     api_key=st.session_state.GOOGLE_API_KEY
 )
</code></pre>
</li>
<li><p><strong>Global Settings</strong>:</p>
<pre><code class="lang-python"> Settings.llm = gemini_model
 Settings.embed_model = gemini_embed_model
</code></pre>
</li>
</ol>
<hr />
<h2 id="heading-query-processing-logic">Query Processing Logic</h2>
<p>The core logic that determines how to handle each query:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Check if this is a population query</span>
<span class="hljs-keyword">if</span> any(word <span class="hljs-keyword">in</span> prompt.lower() <span class="hljs-keyword">for</span> word <span class="hljs-keyword">in</span> [<span class="hljs-string">'population'</span>, <span class="hljs-string">'populous'</span>, <span class="hljs-string">'big city'</span>, <span class="hljs-string">'large city'</span>, <span class="hljs-string">'small city'</span>]):
    <span class="hljs-comment"># Try direct SQL approach first</span>
    result = city_query_engine.process_population_query(prompt)
    <span class="hljs-keyword">if</span> result:
        message_placeholder.markdown(<span class="hljs-string">f"<span class="hljs-subst">{result}</span>\n\n*Source: Database (Direct SQL)*"</span>)
    <span class="hljs-keyword">else</span>:
        <span class="hljs-comment"># Fall back to LLM-based SQL</span>
        response = sql_query_engine.query(prompt)
        message_placeholder.markdown(<span class="hljs-string">f"<span class="hljs-subst">{str(response)}</span>\n\n*Source: Database*"</span>)
<span class="hljs-keyword">elif</span> have_llamacloud:
    <span class="hljs-comment"># For general information, use LlamaCloud</span>
    response = vector_query_engine.query(prompt)
    message_placeholder.markdown(<span class="hljs-string">f"<span class="hljs-subst">{str(response)}</span>\n\n*Source: LlamaCloud*"</span>)
<span class="hljs-keyword">else</span>:
    <span class="hljs-comment"># If neither available</span>
    message_placeholder.markdown(<span class="hljs-string">"I'm unable to answer that question with the current configuration."</span>)
</code></pre>
<hr />
<h2 id="heading-error-handling-and-edge-cases">Error Handling and Edge Cases</h2>
<p>The application includes several error handling mechanisms:</p>
<ol>
<li><p><strong>API Key Validation</strong>:</p>
<ul>
<li><p>Checks if Google API key is present</p>
</li>
<li><p>Displays warning if missing</p>
</li>
</ul>
</li>
<li><p><strong>LlamaCloud Connection</strong>:</p>
<ul>
<li><p>Try/except block for connection attempts</p>
</li>
<li><p>Fallback to SQL-only mode if connection fails</p>
</li>
<li><p>UI indicators for connection status</p>
</li>
</ul>
</li>
<li><p><strong>Query Processing</strong>:</p>
<ul>
<li><p>Handles failed queries gracefully</p>
</li>
<li><p>Provides feedback on processing errors</p>
</li>
<li><p>Suggests query reformulation</p>
</li>
</ul>
</li>
<li><p><strong>Empty Results</strong>:</p>
<ul>
<li><p>Handles case where no cities match query criteria</p>
</li>
<li><p>Returns informative message</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-installation-and-dependencies">Installation and Dependencies</h2>
<h3 id="heading-required-packages">Required Packages</h3>
<pre><code class="lang-python">streamlit==<span class="hljs-number">1.31</span><span class="hljs-number">.0</span>
llama-index==<span class="hljs-number">0.10</span><span class="hljs-number">.0</span>
llama-index-llms-gemini==<span class="hljs-number">0.1</span><span class="hljs-number">.3</span>
llama-index-embeddings-gemini==<span class="hljs-number">0.1</span><span class="hljs-number">.3</span>
llama-index-indices-managed-llama-cloud==<span class="hljs-number">0.1</span><span class="hljs-number">.0</span>
llama-index-core==<span class="hljs-number">0.10</span><span class="hljs-number">.0</span>
sqlalchemy==<span class="hljs-number">2.0</span><span class="hljs-number">.27</span>
pandas==<span class="hljs-number">2.1</span><span class="hljs-number">.4</span>
</code></pre>
<hr />
<h2 id="heading-environment-setup">Environment Setup</h2>
<ol>
<li><p><strong>Virtual Environment</strong>:</p>
<pre><code class="lang-bash"> python -m venv venv
 <span class="hljs-built_in">source</span> venv/bin/activate  <span class="hljs-comment"># On Windows: venv\Scripts\activate</span>
</code></pre>
</li>
<li><p><strong>Package Installation</strong>:</p>
<pre><code class="lang-bash"> pip install -r requirements.txt
</code></pre>
</li>
<li><p><strong>API Keys</strong>:</p>
<ul>
<li><p>Google API key for Gemini</p>
</li>
<li><p>LlamaCloud API key, organization ID, project, and index name</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-running-the-application">Running the Application</h2>
<ol>
<li><p><strong>Start Application</strong>:</p>
<pre><code class="lang-bash"> streamlit run app.py
</code></pre>
</li>
<li><p><strong>Configuration</strong>:</p>
<ul>
<li><p>Enter API keys in sidebar</p>
</li>
<li><p>Confirm LlamaCloud connection status</p>
</li>
</ul>
</li>
<li><p><strong>Usage</strong>:</p>
<ul>
<li><p>Ask questions in the chat input</p>
</li>
<li><p>View responses with source attribution</p>
</li>
<li><p>Chat history is maintained during session</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-example-queries-and-responses">Example Queries and Responses</h2>
<h3 id="heading-structured-data-queries">Structured Data Queries</h3>
<ol>
<li><p><strong>Query</strong>: "What is the population of New York City?" <strong>Response</strong>: "New York City has a population of 8,336,000 people and is located in New York." <strong>Source</strong>: Database (Direct SQL)</p>
</li>
<li><p><strong>Query</strong>: "Which city has the highest population?" <strong>Response</strong>: "New York City has a population of 8,336,000 people and is located in New York." <strong>Source</strong>: Database (Direct SQL)</p>
</li>
<li><p><strong>Query</strong>: "List all cities in California" <strong>Response</strong>: "City information:</p>
<ul>
<li>Los Angeles: 3,822,000 people in California" <strong>Source</strong>: Database (Direct SQL)</li>
</ul>
</li>
</ol>
<h3 id="heading-unstructured-data-queries">Unstructured Data Queries</h3>
<ol>
<li><p><strong>Query</strong>: "Tell me about the history of Chicago" <strong>Response</strong>: [Detailed information about Chicago's history, retrieved from documents] <strong>Source</strong>: LlamaCloud</p>
</li>
<li><p><strong>Query</strong>: "What are the main attractions in Miami?" <strong>Response</strong>: [Information about Miami attractions, retrieved from documents] <strong>Source</strong>: LlamaCloud</p>
</li>
</ol>
<hr />
<h2 id="heading-advanced-customization">Advanced Customization</h2>
<h3 id="heading-adding-more-cities">Adding More Cities</h3>
<p>To expand the database with additional cities:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Add new city data</span>
additional_rows = [
    {<span class="hljs-string">"city_name"</span>: <span class="hljs-string">"San Francisco"</span>, <span class="hljs-string">"population"</span>: <span class="hljs-number">874961</span>, <span class="hljs-string">"state"</span>: <span class="hljs-string">"California"</span>},
    {<span class="hljs-string">"city_name"</span>: <span class="hljs-string">"Boston"</span>, <span class="hljs-string">"population"</span>: <span class="hljs-number">675647</span>, <span class="hljs-string">"state"</span>: <span class="hljs-string">"Massachusetts"</span>},
    <span class="hljs-comment"># Add more cities as needed</span>
]

<span class="hljs-comment"># Insert into database</span>
<span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> additional_rows:
    stmt = insert(city_stats_table).values(**row)
    <span class="hljs-keyword">with</span> engine.begin() <span class="hljs-keyword">as</span> connection:
        connection.execute(stmt)
</code></pre>
<h3 id="heading-supporting-additional-query-types">Supporting Additional Query Types</h3>
<p>To enhance query capabilities, extend the <code>CityQueryEngine</code> class:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">query_by_population_range</span>(<span class="hljs-params">self, min_pop, max_pop</span>):</span>
    <span class="hljs-string">"""Query cities within a population range"""</span>
    query = <span class="hljs-string">f"SELECT city_name, population, state FROM city_stats WHERE population BETWEEN <span class="hljs-subst">{min_pop}</span> AND <span class="hljs-subst">{max_pop}</span> ORDER BY population DESC"</span>
    <span class="hljs-keyword">return</span> self.execute_query(query)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_population_query</span>(<span class="hljs-params">self, query_text</span>):</span>
    <span class="hljs-comment"># Add pattern matching for population range</span>
    range_match = re.search(<span class="hljs-string">r"between\s+(\d[\d,]*)\s+and\s+(\d[\d,]*)"</span>, query_lower)
    <span class="hljs-keyword">if</span> range_match:
        min_pop = int(range_match.group(<span class="hljs-number">1</span>).replace(<span class="hljs-string">','</span>, <span class="hljs-string">''</span>))
        max_pop = int(range_match.group(<span class="hljs-number">2</span>).replace(<span class="hljs-string">','</span>, <span class="hljs-string">''</span>))
        <span class="hljs-keyword">return</span> self.query_by_population_range(min_pop, max_pop)
</code></pre>
<h3 id="heading-enhancing-llamacloud-document-retrieval">Enhancing LlamaCloud Document Retrieval</h3>
<p>To improve document retrieval settings:</p>
<pre><code class="lang-python">vector_query_engine = index.as_query_engine(
    similarity_top_k=<span class="hljs-number">3</span>,  <span class="hljs-comment"># Retrieve more documents</span>
    response_mode=<span class="hljs-string">"tree_summarize"</span>,  <span class="hljs-comment"># Use tree summarization for better responses</span>
    streaming=<span class="hljs-literal">True</span>  <span class="hljs-comment"># Enable streaming responses</span>
)
</code></pre>
<hr />
<h2 id="heading-troubleshooting">Troubleshooting</h2>
<h3 id="heading-common-issues-and-solutions">Common Issues and Solutions</h3>
<ol>
<li><p><strong>API Key Errors</strong>:</p>
<ul>
<li><p>Error: "Error: Invalid API key"</p>
</li>
<li><p>Solution: Verify Google API key in the sidebar or environment variables</p>
</li>
</ul>
</li>
<li><p><strong>LlamaCloud Connection Failures</strong>:</p>
<ul>
<li><p>Error: "Error connecting to LlamaCloud"</p>
</li>
<li><p>Solution: Check organization ID, project name, and index name</p>
</li>
</ul>
</li>
<li><p><strong>SQL Engine Errors</strong>:</p>
<ul>
<li><p>Error: "Error setting up SQL query engine"</p>
</li>
<li><p>Solution: Ensure SQLAlchemy is properly installed and database setup is correct</p>
</li>
</ul>
</li>
<li><p><strong>No Response to Queries</strong>:</p>
<ul>
<li><p>Issue: System doesn't respond to certain questions</p>
</li>
<li><p>Solution: Check query routing logic and ensure appropriate engine is available</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-performance-optimization">Performance Optimization</h2>
<ol>
<li><p><strong>Query Caching</strong>:</p>
<ul>
<li><p>Implement Streamlit caching for repeated queries</p>
</li>
<li><p>Add <code>@st.cache_data</code> decorator to query functions</p>
</li>
</ul>
</li>
<li><p><strong>Model Temperature</strong>:</p>
<ul>
<li><p>Lower temperature (currently 0.2) for more deterministic responses</p>
</li>
<li><p>Increase for more creative but potentially less accurate answers</p>
</li>
</ul>
</li>
<li><p><strong>SQL Query Optimization</strong>:</p>
<ul>
<li><p>Use prepared statements for frequent queries</p>
</li>
<li><p>Add indexes for larger datasets</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-security-considerations">Security Considerations</h2>
<ol>
<li><p><strong>API Key Management</strong>:</p>
<ul>
<li><p>Use environment variables instead of session state for production</p>
</li>
<li><p>Implement key rotation and expiration policies</p>
</li>
</ul>
</li>
<li><p><strong>Input Validation</strong>:</p>
<ul>
<li><p>Sanitize user input before processing</p>
</li>
<li><p>Validate SQL queries to prevent injection</p>
</li>
</ul>
</li>
<li><p><strong>Data Privacy</strong>:</p>
<ul>
<li><p>Consider data retention policies for chat history</p>
</li>
<li><p>Implement user authentication for sensitive data</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-future-enhancements">Future Enhancements</h2>
<ol>
<li><p><strong>Expanded Database</strong>:</p>
<ul>
<li><p>Add more cities and additional attributes (GDP, crime rate, etc.)</p>
</li>
<li><p>Support for historical population data</p>
</li>
</ul>
</li>
<li><p><strong>Advanced NLP</strong>:</p>
<ul>
<li><p>Implement intent classification for better query routing</p>
</li>
<li><p>Add support for multi-turn conversations with context awareness</p>
</li>
</ul>
</li>
<li><p><strong>UI Improvements</strong>:</p>
<ul>
<li><p>Add visualization for city comparison</p>
</li>
<li><p>Implement map view for geographical context</p>
</li>
</ul>
</li>
<li><p><strong>Integration Options</strong>:</p>
<ul>
<li><p>Support for additional vector databases (Qdrant, Pinecone)</p>
</li>
<li><p>Option to use alternative LLMs (locally via Ollama or through APIs)</p>
</li>
</ul>
</li>
<li><p><strong>Evaluation Framework</strong>:</p>
<ul>
<li><p>Implement CometML's Opik for tracing and observability</p>
</li>
<li><p>Add metrics for answer quality and retrieval relevance</p>
</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>This LlamaCloud RAG Demo showcases an effective approach to combining structured and unstructured data for comprehensive question answering. The hybrid architecture leverages the strengths of both SQL databases (for precise factual queries) and document retrieval (for nuanced, contextual information).</p>
<p>Key takeaways from this implementation:</p>
<ol>
<li><p><strong>Intelligent Query Routing</strong>: The system automatically determines the best source for answering each question</p>
</li>
<li><p><strong>Streamlined User Experience</strong>: Simple chat interface hides the complexity of the underlying systems</p>
</li>
<li><p><strong>Extensible Architecture</strong>: Can be expanded with additional data sources and query capabilities</p>
</li>
<li><p><strong>Production-Ready Components</strong>: Uses industry-standard tools like LlamaIndex, SQLAlchemy, and Gemini</p>
</li>
</ol>
<p>By effectively combining these technologies, the application demonstrates a powerful approach to building knowledge-intensive applications that can handle both structured and unstructured information within a unified interface.</p>
]]></content:encoded></item><item><title><![CDATA[Gemma 3: Advancing Open-Source Multimodal AI with Scalable Training and Efficient Architectures]]></title><description><![CDATA[Google’s Gemma 3 marks a pivotal advancement in open-weight multimodal AI, demonstrating unparalleled efficiency, scalability, and safety. With enhanced long-context processing, optimized transformer architectures, and robust multimodal integration, ...]]></description><link>https://airesearch.hashnode.dev/gemma-3-advancing-open-source-multimodal-ai-with-scalable-training-and-efficient-architectures</link><guid isPermaLink="true">https://airesearch.hashnode.dev/gemma-3-advancing-open-source-multimodal-ai-with-scalable-training-and-efficient-architectures</guid><category><![CDATA[Gemma3]]></category><category><![CDATA[Transformer Architectures]]></category><category><![CDATA[Multilingualmodel]]></category><category><![CDATA[AIScalability]]></category><category><![CDATA[opensourceai]]></category><category><![CDATA[Google AI]]></category><category><![CDATA[#multimodalai]]></category><category><![CDATA[#AIEfficiency]]></category><category><![CDATA[Aisafety]]></category><dc:creator><![CDATA[Vedant Pandya]]></dc:creator><pubDate>Thu, 13 Mar 2025 11:46:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741866476215/6eaf4c8d-b6a6-4e84-9d1c-2a3352e3791a.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://storage.googleapis.com/gweb-uniblog-publish-prod/images/Gemma3_KeywordBlog_RD3_V01b.width-1200.format-webp.webp" alt="Gemma 3 logo in blue box on dark background with icons and text: Vision Language Tasks, 140 Languages, 128K Tokens." /></p>
<p>Google’s <strong>Gemma 3</strong> marks a pivotal advancement in <strong>open-weight multimodal AI</strong>, demonstrating <strong>unparalleled efficiency, scalability, and safety</strong>. With <strong>enhanced long-context processing, optimized transformer architectures, and robust multimodal integration</strong>, it extends the possibilities of open-source AI. Here’s an in-depth exploration of the research innovations driving Gemma 3.</p>
<hr />
<h2 id="heading-1-pre-training-scaling-knowledge-while-ensuring-diversity"><strong>1. Pre-training: Scaling Knowledge While Ensuring Diversity</strong></h2>
<h3 id="heading-dataset-scale-and-composition"><strong>Dataset Scale and Composition</strong></h3>
<p>🔹 <strong>14 Trillion Tokens for the 27B Model</strong> – The sheer scale of Gemma 3’s training dataset ensures a <strong>rich and nuanced understanding of language</strong>. The focus is not just on volume but on <strong>curating a balanced dataset</strong> that generalizes well across domains.<br />🔹 <strong>Multilingual Expansion</strong> – Covering <strong>140+ languages</strong>, Gemma 3 incorporates a diverse set of linguistic structures, making it one of the most <strong>comprehensive open-weight multilingual models</strong> available.<br />🔹 <strong>Multimodal Integration</strong> – Unlike previous iterations, Gemma 3’s <strong>pre-training includes image data</strong>, which enhances its ability to <strong>understand and generate</strong> cross-modal outputs.<br />🔹 <strong>Decontamination and Responsible Data Curation</strong> – A <strong>rigorous decontamination process</strong> was employed to mitigate risks related to <strong>memorization, sensitive data leakage, and bias</strong>, reinforcing <strong>Google’s commitment to responsible AI development</strong>.</p>
<h3 id="heading-tokenization-optimizing-for-efficiency"><strong>Tokenization: Optimizing for Efficiency</strong></h3>
<p>🔹 <strong>SentencePiece Tokenizer</strong> – Chosen for its <strong>subword tokenization capabilities</strong>, SentencePiece allows Gemma 3 to effectively process <strong>out-of-vocabulary words</strong>, <strong>morphologically rich languages</strong>, and <strong>diverse scripts</strong>.<br />🔹 <strong>Efficiency Gains</strong> – By refining tokenization strategies, the model achieves <strong>better compression and improved language modeling</strong>, reducing unnecessary token overhead.</p>
<h3 id="heading-computational-infrastructure-scaling-training-efficiently"><strong>Computational Infrastructure: Scaling Training Efficiently</strong></h3>
<p>🔹 <strong>Trained on Google TPUs (TPUv4p, TPUv5p, TPUv5e)</strong> – These next-generation accelerators provide <strong>unmatched efficiency</strong> in matrix computations, <strong>reducing both training time and energy consumption</strong>.<br />🔹 <strong>Optimized for Large-Scale Training</strong> – Leveraging <strong>distributed training strategies</strong>, Gemma 3 maximizes hardware utilization, ensuring the best performance-to-compute ratio.</p>
<pre><code class="lang-python"><span class="hljs-comment"># SECTION 1: Pre-training - Dataset Processing and Tokenization</span>
<span class="hljs-string">"""
This example demonstrates how to process a multilingual dataset and apply
tokenization techniques similar to those used in Gemma 3's pre-training.
"""</span>

<span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np
<span class="hljs-keyword">import</span> pandas <span class="hljs-keyword">as</span> pd
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List, Dict, Any
<span class="hljs-keyword">from</span> sentencepiece <span class="hljs-keyword">import</span> SentencePieceProcessor

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GemmaDatasetProcessor</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, tokenizer_path: str, languages: List[str] = None</span>):</span>
        <span class="hljs-string">"""Initialize the dataset processor with a SentencePiece tokenizer."""</span>
        self.tokenizer = SentencePieceProcessor()
        self.tokenizer.Load(tokenizer_path)
        self.languages = languages <span class="hljs-keyword">or</span> [<span class="hljs-string">"en"</span>, <span class="hljs-string">"fr"</span>, <span class="hljs-string">"de"</span>, <span class="hljs-string">"es"</span>, <span class="hljs-string">"zh"</span>, <span class="hljs-string">"ja"</span>, <span class="hljs-string">"ar"</span>, <span class="hljs-string">"hi"</span>]
        self.stats = {<span class="hljs-string">"token_count"</span>: <span class="hljs-number">0</span>, <span class="hljs-string">"examples_per_lang"</span>: {lang: <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> lang <span class="hljs-keyword">in</span> self.languages}}

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">load_and_process_data</span>(<span class="hljs-params">self, data_paths: Dict[str, str]</span>) -&gt; List[Dict[str, Any]]:</span>
        <span class="hljs-string">"""Load and process data from multiple sources, keeping track of statistics."""</span>
        processed_data = []

        <span class="hljs-keyword">for</span> lang, path <span class="hljs-keyword">in</span> data_paths.items():
            <span class="hljs-keyword">if</span> lang <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> self.languages:
                <span class="hljs-keyword">continue</span>

            print(<span class="hljs-string">f"Processing <span class="hljs-subst">{lang}</span> data from <span class="hljs-subst">{path}</span>"</span>)
            <span class="hljs-comment"># Load data (simplified example)</span>
            raw_texts = pd.read_csv(path)[<span class="hljs-string">"text"</span>].tolist()

            <span class="hljs-keyword">for</span> text <span class="hljs-keyword">in</span> raw_texts:
                <span class="hljs-comment"># Apply tokenization</span>
                tokens = self.tokenizer.EncodeAsIds(text)

                <span class="hljs-comment"># Apply decontamination logic (simplified)</span>
                is_clean = self._decontaminate_text(text)

                <span class="hljs-keyword">if</span> is_clean <span class="hljs-keyword">and</span> len(tokens) &gt; <span class="hljs-number">0</span>:
                    processed_example = {
                        <span class="hljs-string">"language"</span>: lang,
                        <span class="hljs-string">"text"</span>: text,
                        <span class="hljs-string">"tokens"</span>: tokens,
                        <span class="hljs-string">"n_tokens"</span>: len(tokens)
                    }
                    processed_data.append(processed_example)

                    <span class="hljs-comment"># Update statistics</span>
                    self.stats[<span class="hljs-string">"token_count"</span>] += len(tokens)
                    self.stats[<span class="hljs-string">"examples_per_lang"</span>][lang] += <span class="hljs-number">1</span>

        print(<span class="hljs-string">f"Processed <span class="hljs-subst">{len(processed_data)}</span> examples with <span class="hljs-subst">{self.stats[<span class="hljs-string">'token_count'</span>]}</span> tokens"</span>)
        <span class="hljs-keyword">return</span> processed_data

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">_decontaminate_text</span>(<span class="hljs-params">self, text: str</span>) -&gt; bool:</span>
        <span class="hljs-string">"""
        Simplified decontamination that checks for sensitive patterns.
        In a real implementation, this would be much more sophisticated.
        """</span>
        sensitive_patterns = [<span class="hljs-string">"password:"</span>, <span class="hljs-string">"secret:"</span>, <span class="hljs-string">"private key"</span>]
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">not</span> any(pattern <span class="hljs-keyword">in</span> text.lower() <span class="hljs-keyword">for</span> pattern <span class="hljs-keyword">in</span> sensitive_patterns)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_dataset_stats</span>(<span class="hljs-params">self</span>) -&gt; Dict[str, Any]:</span>
        <span class="hljs-string">"""Return statistics about the processed dataset."""</span>
        <span class="hljs-keyword">return</span> {
            <span class="hljs-string">"total_tokens"</span>: self.stats[<span class="hljs-string">"token_count"</span>],
            <span class="hljs-string">"languages"</span>: len(self.languages),
            <span class="hljs-string">"language_distribution"</span>: {
                lang: count / sum(self.stats[<span class="hljs-string">"examples_per_lang"</span>].values())
                <span class="hljs-keyword">for</span> lang, count <span class="hljs-keyword">in</span> self.stats[<span class="hljs-string">"examples_per_lang"</span>].items() <span class="hljs-keyword">if</span> count &gt; <span class="hljs-number">0</span>
            }
        }

<span class="hljs-comment"># Example usage (not executed)</span>
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:
    processor = GemmaDatasetProcessor(<span class="hljs-string">"path/to/sentencepiece_model.model"</span>)
    data_paths = {
        <span class="hljs-string">"en"</span>: <span class="hljs-string">"path/to/english_data.csv"</span>,
        <span class="hljs-string">"fr"</span>: <span class="hljs-string">"path/to/french_data.csv"</span>,
        <span class="hljs-comment"># Add more languages</span>
    }
    processed_data = processor.load_and_process_data(data_paths)
    stats = processor.get_dataset_stats()
    print(<span class="hljs-string">f"Dataset statistics: <span class="hljs-subst">{stats}</span>"</span>)
</code></pre>
<hr />
<h2 id="heading-2-architectural-innovations-balancing-efficiency-and-scalability"><strong>2. Architectural Innovations: Balancing Efficiency and Scalability</strong></h2>
<h3 id="heading-enhanced-attention-mechanisms"><strong>Enhanced Attention Mechanisms</strong></h3>
<p>🔹 <strong>Interleaved Local and Global Attention</strong> – This novel strategy mitigates the <strong>quadratic complexity of self-attention</strong>, allowing Gemma 3 to efficiently process <strong>longer contexts (up to 128K tokens)</strong>.<br />🔹 <strong>Grouped-Query Attention (GQA) &amp; QK-Norm</strong> – These refinements <strong>reduce memory overhead</strong> while maintaining <strong>high-quality representations</strong>, making the model more practical for <strong>real-time and production applications</strong>.<br />🔹 <strong>Refined Rotary Positional Embeddings (RoPE)</strong> – Adjustments to <strong>RoPE base frequency</strong> improve the model’s ability to <strong>track relationships over long sequences</strong>, further strengthening its <strong>context retention</strong>.</p>
<h3 id="heading-multimodal-capabilities-a-step-towards-general-intelligence"><strong>Multimodal Capabilities: A Step Towards General Intelligence</strong></h3>
<p>🔹 <strong>SigLIP Vision Encoder</strong> – A key addition enabling <strong>seamless image-text processing</strong>, making the model more adept at handling <strong>multimodal queries</strong>.<br />🔹 <strong>Adaptive Windowing for Images</strong> – This technique allows Gemma 3 to dynamically process <strong>images of varying resolutions and aspect ratios</strong>, improving its <strong>visual comprehension abilities</strong>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># SECTION 2: Architectural Innovations - Implementing Enhanced Attention Mechanisms</span>
<span class="hljs-string">"""
This example demonstrates how to implement the enhanced attention mechanisms 
used in Gemma 3, including interleaved local and global attention and grouped-query attention.
"""</span>

<span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">import</span> torch.nn <span class="hljs-keyword">as</span> nn
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Optional, Tuple

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GemmaRotaryEmbedding</span>(<span class="hljs-params">nn.Module</span>):</span>
    <span class="hljs-string">"""Rotary positional embeddings with frequency adjustments."""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, dim: int, base=<span class="hljs-number">10000.0</span>, scaling_factor=<span class="hljs-number">1.0</span></span>):</span>
        super().__init__()
        self.dim = dim
        self.base = base * scaling_factor
        inv_freq = <span class="hljs-number">1.0</span> / (self.base ** (torch.arange(<span class="hljs-number">0</span>, dim, <span class="hljs-number">2</span>).float() / dim))
        self.register_buffer(<span class="hljs-string">"inv_freq"</span>, inv_freq)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span>(<span class="hljs-params">self, seq_len: int, device: torch.device</span>):</span>
        t = torch.arange(seq_len, device=device).type_as(self.inv_freq)
        freqs = torch.einsum(<span class="hljs-string">"i,j-&gt;ij"</span>, t, self.inv_freq)
        emb = torch.cat((freqs, freqs), dim=<span class="hljs-number">-1</span>)
        <span class="hljs-keyword">return</span> emb

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">apply_rotary_pos_emb</span>(<span class="hljs-params">q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor</span>):</span>
    <span class="hljs-string">"""Apply rotary position embeddings to query and key tensors."""</span>
    <span class="hljs-comment"># Reshape for broadcasting</span>
    cos = cos[:, :, <span class="hljs-literal">None</span>, :]  <span class="hljs-comment"># [batch, seq_len, 1, dim]</span>
    sin = sin[:, :, <span class="hljs-literal">None</span>, :]  <span class="hljs-comment"># [batch, seq_len, 1, dim]</span>

    <span class="hljs-comment"># Apply rotation using complex multiplication logic</span>
    q_embed = (q * cos) + (rotate_half(q) * sin)
    k_embed = (k * cos) + (rotate_half(k) * sin)

    <span class="hljs-keyword">return</span> q_embed, k_embed

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">rotate_half</span>(<span class="hljs-params">x: torch.Tensor</span>) -&gt; torch.Tensor:</span>
    <span class="hljs-string">"""Rotate half of the hidden dims."""</span>
    x1, x2 = x.chunk(<span class="hljs-number">2</span>, dim=<span class="hljs-number">-1</span>)
    <span class="hljs-keyword">return</span> torch.cat((-x2, x1), dim=<span class="hljs-number">-1</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">GemmaAttention</span>(<span class="hljs-params">nn.Module</span>):</span>
    <span class="hljs-string">"""
    Enhanced attention module implementing interleaved local and global attention
    with Grouped-Query Attention (GQA) and QK-Norm.
    """</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">
        self,
        hidden_size: int,
        num_heads: int,
        num_kv_heads: int = None,  <span class="hljs-comment"># For GQA</span>
        window_size: int = <span class="hljs-number">1024</span>,  <span class="hljs-comment"># For local attention</span>
        qk_norm: bool = True,
        dropout_prob: float = <span class="hljs-number">0.0</span>,
    </span>):</span>
        super().__init__()
        self.hidden_size = hidden_size
        self.num_heads = num_heads
        self.num_kv_heads = num_kv_heads <span class="hljs-keyword">or</span> num_heads
        self.head_dim = hidden_size // num_heads
        self.window_size = window_size
        self.qk_norm = qk_norm

        <span class="hljs-comment"># Calculate grouping factor for GQA</span>
        self.num_groups = self.num_heads // self.num_kv_heads

        <span class="hljs-comment"># Projection matrices</span>
        self.q_proj = nn.Linear(hidden_size, hidden_size, bias=<span class="hljs-literal">False</span>)
        self.k_proj = nn.Linear(hidden_size, self.num_kv_heads * self.head_dim, bias=<span class="hljs-literal">False</span>)
        self.v_proj = nn.Linear(hidden_size, self.num_kv_heads * self.head_dim, bias=<span class="hljs-literal">False</span>)
        self.o_proj = nn.Linear(hidden_size, hidden_size, bias=<span class="hljs-literal">False</span>)

        <span class="hljs-comment"># Rotary embeddings</span>
        self.rotary_emb = GemmaRotaryEmbedding(self.head_dim, scaling_factor=<span class="hljs-number">0.1</span>)  <span class="hljs-comment"># Adjusted base freq</span>

        <span class="hljs-comment"># Layer norms for QK-Norm</span>
        <span class="hljs-keyword">if</span> qk_norm:
            self.q_norm = nn.LayerNorm(self.head_dim)
            self.k_norm = nn.LayerNorm(self.head_dim)

        self.dropout = nn.Dropout(dropout_prob)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span>(<span class="hljs-params">
        self,
        hidden_states: torch.Tensor,
        attention_mask: Optional[torch.Tensor] = None,
        is_local: bool = True,  <span class="hljs-comment"># Switch between local and global attention</span>
        position_ids: Optional[torch.LongTensor] = None,
    </span>) -&gt; Tuple[torch.Tensor, torch.Tensor]:</span>
        <span class="hljs-string">"""
        Forward pass with support for interleaved local and global attention.

        Args:
            hidden_states: Input tensor [batch_size, seq_len, hidden_size]
            attention_mask: Attention mask [batch_size, 1, 1, seq_len]
            is_local: Whether to use local attention (True) or global attention (False)
            position_ids: Optional explicit position IDs

        Returns:
            output: Output tensor [batch_size, seq_len, hidden_size]
            attention_weights: Attention weights for visualization
        """</span>
        batch_size, seq_length, _ = hidden_states.shape

        <span class="hljs-comment"># Project inputs to queries, keys, and values</span>
        q = self.q_proj(hidden_states).view(batch_size, seq_length, self.num_heads, self.head_dim)
        k = self.k_proj(hidden_states).view(batch_size, seq_length, self.num_kv_heads, self.head_dim)
        v = self.v_proj(hidden_states).view(batch_size, seq_length, self.num_kv_heads, self.head_dim)

        <span class="hljs-comment"># Apply QK-Norm if enabled</span>
        <span class="hljs-keyword">if</span> self.qk_norm:
            q = self.q_norm(q)
            k = self.k_norm(k)

        <span class="hljs-comment"># Apply rotary embeddings</span>
        <span class="hljs-keyword">if</span> position_ids <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            position_ids = torch.arange(seq_length, device=hidden_states.device)

        cos, sin = self.rotary_emb(seq_length, hidden_states.device)
        cos = cos[position_ids].unsqueeze(<span class="hljs-number">0</span>)  <span class="hljs-comment"># [1, seq_len, dim]</span>
        sin = sin[position_ids].unsqueeze(<span class="hljs-number">0</span>)  <span class="hljs-comment"># [1, seq_len, dim]</span>

        q, k = apply_rotary_pos_emb(q, k, cos, sin)

        <span class="hljs-comment"># Grouped-Query Attention: Repeat KV heads for each query group</span>
        <span class="hljs-keyword">if</span> self.num_groups &gt; <span class="hljs-number">1</span>:
            k = k.unsqueeze(<span class="hljs-number">2</span>).expand(<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>, self.num_groups, <span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>)
            v = v.unsqueeze(<span class="hljs-number">2</span>).expand(<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>, self.num_groups, <span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>)
            k = k.reshape(batch_size, seq_length, self.num_heads, self.head_dim)
            v = v.reshape(batch_size, seq_length, self.num_heads, self.head_dim)

        <span class="hljs-comment"># Transpose for attention computation</span>
        q = q.transpose(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)  <span class="hljs-comment"># [batch_size, num_heads, seq_length, head_dim]</span>
        k = k.transpose(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)  <span class="hljs-comment"># [batch_size, num_heads, seq_length, head_dim]</span>
        v = v.transpose(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)  <span class="hljs-comment"># [batch_size, num_heads, seq_length, head_dim]</span>

        <span class="hljs-comment"># Create local or global attention pattern</span>
        <span class="hljs-keyword">if</span> is_local:
            <span class="hljs-comment"># Local attention with window</span>
            attention_weights = torch.zeros(
                batch_size, self.num_heads, seq_length, seq_length, 
                device=hidden_states.device
            )

            <span class="hljs-comment"># For each position, attend only to nearby positions within window</span>
            <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(seq_length):
                start = max(<span class="hljs-number">0</span>, i - self.window_size // <span class="hljs-number">2</span>)
                end = min(seq_length, i + self.window_size // <span class="hljs-number">2</span> + <span class="hljs-number">1</span>)

                local_q = q[:, :, i:i+<span class="hljs-number">1</span>]  <span class="hljs-comment"># [batch_size, num_heads, 1, head_dim]</span>
                local_k = k[:, :, start:end]  <span class="hljs-comment"># [batch_size, num_heads, window_size, head_dim]</span>
                local_v = v[:, :, start:end]  <span class="hljs-comment"># [batch_size, num_heads, window_size, head_dim]</span>

                <span class="hljs-comment"># Compute attention scores for this position</span>
                attn_scores = torch.matmul(local_q, local_k.transpose(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>)) / math.sqrt(self.head_dim)

                <span class="hljs-keyword">if</span> attention_mask <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
                    local_mask = attention_mask[:, :, :, start:end]
                    attn_scores = attn_scores + local_mask

                attn_probs = torch.softmax(attn_scores, dim=<span class="hljs-number">-1</span>)
                attn_probs = self.dropout(attn_probs)

                <span class="hljs-comment"># Update the value for this position</span>
                local_output = torch.matmul(attn_probs, local_v)
                attention_weights[:, :, i, start:end] = attn_probs.squeeze(<span class="hljs-number">2</span>)

                <span class="hljs-keyword">if</span> i == <span class="hljs-number">0</span>:
                    output = local_output
                <span class="hljs-keyword">else</span>:
                    output = torch.cat([output, local_output], dim=<span class="hljs-number">2</span>)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-comment"># Global attention (standard self-attention)</span>
            attention_scores = torch.matmul(q, k.transpose(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>)) / math.sqrt(self.head_dim)

            <span class="hljs-keyword">if</span> attention_mask <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-literal">None</span>:
                attention_scores = attention_scores + attention_mask

            attention_weights = torch.softmax(attention_scores, dim=<span class="hljs-number">-1</span>)
            attention_weights = self.dropout(attention_weights)

            output = torch.matmul(attention_weights, v)

        <span class="hljs-comment"># Restore original shape</span>
        output = output.transpose(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>).reshape(batch_size, seq_length, self.hidden_size)

        <span class="hljs-comment"># Final projection</span>
        output = self.o_proj(output)

        <span class="hljs-keyword">return</span> output, attention_weights
</code></pre>
<hr />
<h2 id="heading-3-post-training-refining-the-model-through-alignment-and-safety"><strong>3. Post-training: Refining the Model Through Alignment and Safety</strong></h2>
<h3 id="heading-knowledge-distillation-for-efficient-deployment"><strong>Knowledge Distillation for Efficient Deployment</strong></h3>
<p>🔹 <strong>Distillation from Large Models to Smaller Variants</strong> – By leveraging <strong>teacher-student learning</strong>, smaller models inherit the capabilities of larger counterparts, making them ideal for <strong>resource-constrained environments (e.g., edge devices)</strong>.</p>
<h3 id="heading-instruction-tuning-it-and-reinforcement-learning-rl"><strong>Instruction Tuning (IT) and Reinforcement Learning (RL)</strong></h3>
<p>🔹 <strong>Improved Instruction Following</strong> – IT significantly enhances Gemma 3’s ability to <strong>understand, execute, and generalize user instructions</strong>.<br />🔹 <strong>RLHF &amp; RLMF for Alignment</strong> – Reinforcement Learning from Human Feedback (RLHF) and Machine Feedback (RLMF) optimize the model’s reasoning skills, particularly improving its <strong>mathematical and logical consistency</strong>.</p>
<h3 id="heading-safety-and-responsible-ai"><strong>Safety and Responsible AI</strong></h3>
<p>🔹 <strong>Robust Safety Evaluations</strong> – The model underwent <strong>extensive red-teaming and adversarial testing</strong> to detect and mitigate <strong>harmful content generation, biases, and privacy risks</strong>.<br />🔹 <strong>Alignment for Ethical AI</strong> – Special attention was given to reducing <strong>toxic outputs, representational harms, and information leakage</strong>, ensuring Gemma 3 meets <strong>high ethical and safety standards</strong>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># SECTION 3: Post-training - Knowledge Distillation and Safety</span>
<span class="hljs-string">"""
This example demonstrates how to implement knowledge distillation to transfer knowledge
from a large teacher model to a smaller student model, as well as a basic safety classifier.
"""</span>

<span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">import</span> torch.nn <span class="hljs-keyword">as</span> nn
<span class="hljs-keyword">import</span> torch.nn.functional <span class="hljs-keyword">as</span> F
<span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> AutoModelForCausalLM, AutoTokenizer
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Dict, List, Tuple

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KnowledgeDistillationTrainer</span>:</span>
    <span class="hljs-string">"""Trainer for knowledge distillation from a larger Gemma 3 model to a smaller one."""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">
        self,
        teacher_model_id: str,
        student_model_id: str,
        alpha: float = <span class="hljs-number">0.5</span>,  <span class="hljs-comment"># Balance between distillation and ground truth</span>
        temperature: float = <span class="hljs-number">2.0</span>,  <span class="hljs-comment"># Temperature for softening probability distributions</span>
    </span>):</span>
        <span class="hljs-comment"># Initialize teacher model (larger model like Gemma 3 27B)</span>
        self.teacher_model = AutoModelForCausalLM.from_pretrained(teacher_model_id)
        self.teacher_tokenizer = AutoTokenizer.from_pretrained(teacher_model_id)

        <span class="hljs-comment"># Initialize student model (smaller model to be trained)</span>
        self.student_model = AutoModelForCausalLM.from_pretrained(student_model_id)
        self.student_tokenizer = AutoTokenizer.from_pretrained(student_model_id)

        <span class="hljs-comment"># Freeze teacher parameters</span>
        <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> self.teacher_model.parameters():
            param.requires_grad = <span class="hljs-literal">False</span>

        self.alpha = alpha
        self.temperature = temperature

        <span class="hljs-comment"># Optimizer for student model</span>
        self.optimizer = torch.optim.AdamW(self.student_model.parameters(), lr=<span class="hljs-number">5e-5</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compute_distillation_loss</span>(<span class="hljs-params">
        self,
        teacher_logits: torch.Tensor,
        student_logits: torch.Tensor,
        target_ids: torch.Tensor,
        attention_mask: torch.Tensor
    </span>) -&gt; Tuple[torch.Tensor, Dict[str, float]]:</span>
        <span class="hljs-string">"""
        Compute the knowledge distillation loss.

        Args:
            teacher_logits: Logits from teacher model [batch, seq_len, vocab_size]
            student_logits: Logits from student model [batch, seq_len, vocab_size]
            target_ids: Target token IDs [batch, seq_len]
            attention_mask: Attention mask [batch, seq_len]

        Returns:
            total_loss: Combined distillation and cross-entropy loss
            loss_dict: Dictionary containing individual loss components
        """</span>
        <span class="hljs-comment"># Apply temperature to soften probability distributions</span>
        soft_teacher_logits = teacher_logits / self.temperature
        soft_student_logits = student_logits / self.temperature

        <span class="hljs-comment"># Compute KL divergence loss for knowledge distillation</span>
        distillation_loss = F.kl_div(
            F.log_softmax(soft_student_logits, dim=<span class="hljs-number">-1</span>),
            F.softmax(soft_teacher_logits, dim=<span class="hljs-number">-1</span>),
            reduction=<span class="hljs-string">"batchmean"</span>
        ) * (self.temperature ** <span class="hljs-number">2</span>)

        <span class="hljs-comment"># Compute cross-entropy loss against ground truth</span>
        ce_loss = F.cross_entropy(
            student_logits.view(<span class="hljs-number">-1</span>, student_logits.size(<span class="hljs-number">-1</span>)),
            target_ids.view(<span class="hljs-number">-1</span>),
            ignore_index=<span class="hljs-number">-100</span>
        )

        <span class="hljs-comment"># Combine losses</span>
        total_loss = self.alpha * distillation_loss + (<span class="hljs-number">1</span> - self.alpha) * ce_loss

        <span class="hljs-keyword">return</span> total_loss, {
            <span class="hljs-string">"total_loss"</span>: total_loss.item(),
            <span class="hljs-string">"distillation_loss"</span>: distillation_loss.item(),
            <span class="hljs-string">"ce_loss"</span>: ce_loss.item()
        }

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">train_step</span>(<span class="hljs-params">self, batch: Dict[str, torch.Tensor]</span>) -&gt; Dict[str, float]:</span>
        <span class="hljs-string">"""Perform a single training step with knowledge distillation."""</span>
        <span class="hljs-comment"># Move batch to device</span>
        input_ids = batch[<span class="hljs-string">"input_ids"</span>]
        attention_mask = batch[<span class="hljs-string">"attention_mask"</span>]
        target_ids = batch[<span class="hljs-string">"labels"</span>]

        <span class="hljs-comment"># Forward pass through teacher model (no gradients)</span>
        <span class="hljs-keyword">with</span> torch.no_grad():
            teacher_outputs = self.teacher_model(
                input_ids=input_ids,
                attention_mask=attention_mask,
                return_dict=<span class="hljs-literal">True</span>
            )
            teacher_logits = teacher_outputs.logits

        <span class="hljs-comment"># Forward pass through student model</span>
        student_outputs = self.student_model(
            input_ids=input_ids,
            attention_mask=attention_mask,
            return_dict=<span class="hljs-literal">True</span>
        )
        student_logits = student_outputs.logits

        <span class="hljs-comment"># Compute loss</span>
        loss, loss_dict = self.compute_distillation_loss(
            teacher_logits, student_logits, target_ids, attention_mask
        )

        <span class="hljs-comment"># Backward pass and update student parameters</span>
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

        <span class="hljs-keyword">return</span> loss_dict


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SafetyClassifier</span>(<span class="hljs-params">nn.Module</span>):</span>
    <span class="hljs-string">"""Safety classifier based on a pre-trained model to detect harmful content."""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, base_model_id: str, num_safety_categories: int = <span class="hljs-number">8</span></span>):</span>
        super().__init__()
        <span class="hljs-comment"># Load base model</span>
        self.tokenizer = AutoTokenizer.from_pretrained(base_model_id)
        self.encoder = AutoModelForCausalLM.from_pretrained(base_model_id)

        <span class="hljs-comment"># Freeze base model</span>
        <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> self.encoder.parameters():
            param.requires_grad = <span class="hljs-literal">False</span>

        <span class="hljs-comment"># Classification head</span>
        self.safety_head = nn.Sequential(
            nn.Linear(self.encoder.config.hidden_size, <span class="hljs-number">512</span>),
            nn.ReLU(),
            nn.Dropout(<span class="hljs-number">0.1</span>),
            nn.Linear(<span class="hljs-number">512</span>, num_safety_categories)
        )

        <span class="hljs-comment"># Safety categories</span>
        self.safety_categories = [
            <span class="hljs-string">"hate_speech"</span>,
            <span class="hljs-string">"harassment"</span>,
            <span class="hljs-string">"self_harm"</span>,
            <span class="hljs-string">"sexual_content"</span>,
            <span class="hljs-string">"violence"</span>,
            <span class="hljs-string">"dangerous_content"</span>,
            <span class="hljs-string">"misinformation"</span>,
            <span class="hljs-string">"personal_data"</span>
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span>(<span class="hljs-params">self, input_ids: torch.Tensor, attention_mask: torch.Tensor</span>) -&gt; torch.Tensor:</span>
        <span class="hljs-string">"""Forward pass to classify text for safety risks."""</span>
        <span class="hljs-comment"># Get embeddings from base model</span>
        <span class="hljs-keyword">with</span> torch.no_grad():
            outputs = self.encoder(
                input_ids=input_ids,
                attention_mask=attention_mask,
                output_hidden_states=<span class="hljs-literal">True</span>,
                return_dict=<span class="hljs-literal">True</span>
            )

            <span class="hljs-comment"># Use the last hidden state of the final token</span>
            last_token_indices = attention_mask.sum(dim=<span class="hljs-number">1</span>) - <span class="hljs-number">1</span>
            batch_indices = torch.arange(input_ids.size(<span class="hljs-number">0</span>))
            last_token_hidden = outputs.hidden_states[<span class="hljs-number">-1</span>][batch_indices, last_token_indices]

        <span class="hljs-comment"># Pass through safety classification head</span>
        safety_logits = self.safety_head(last_token_hidden)
        <span class="hljs-keyword">return</span> safety_logits

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">classify_text</span>(<span class="hljs-params">self, text: str, threshold: float = <span class="hljs-number">0.5</span></span>) -&gt; Dict[str, float]:</span>
        <span class="hljs-string">"""Classify a text for safety risks."""</span>
        <span class="hljs-comment"># Tokenize text</span>
        inputs = self.tokenizer(
            text,
            return_tensors=<span class="hljs-string">"pt"</span>,
            truncation=<span class="hljs-literal">True</span>,
            max_length=<span class="hljs-number">512</span>,
            padding=<span class="hljs-literal">True</span>
        )

        <span class="hljs-comment"># Get safety logits</span>
        safety_logits = self(inputs.input_ids, inputs.attention_mask)

        <span class="hljs-comment"># Apply sigmoid to get probabilities</span>
        safety_probs = torch.sigmoid(safety_logits).squeeze().detach().numpy()

        <span class="hljs-comment"># Create results dictionary</span>
        results = {
            category: float(prob)
            <span class="hljs-keyword">for</span> category, prob <span class="hljs-keyword">in</span> zip(self.safety_categories, safety_probs)
        }

        <span class="hljs-comment"># Add overall safety assessment</span>
        results[<span class="hljs-string">"is_unsafe"</span>] = any(prob &gt; threshold <span class="hljs-keyword">for</span> prob <span class="hljs-keyword">in</span> safety_probs)
        results[<span class="hljs-string">"max_risk_category"</span>] = self.safety_categories[safety_probs.argmax()]
        results[<span class="hljs-string">"max_risk_score"</span>] = float(safety_probs.max())

        <span class="hljs-keyword">return</span> results
</code></pre>
<hr />
<h2 id="heading-4-benchmarking-performance-at-scale"><strong>4. Benchmarking: Performance at Scale</strong></h2>
<h3 id="heading-competitive-performance-against-leading-open-models"><strong>Competitive Performance Against Leading Open Models</strong></h3>
<p>✅ Outperforms <strong>Llama 3 and DeepSeek R1</strong> across multiple language and reasoning benchmarks.<br />✅ Excels in <strong>multilingual NLP tasks</strong>, leveraging its <strong>diverse training data</strong>.</p>
<h3 id="heading-long-context-mastery"><strong>Long-Context Mastery</strong></h3>
<p>✅ With a <strong>128K token context window</strong>, Gemma 3 can <strong>retain and utilize information over extended sequences</strong>, making it ideal for applications requiring <strong>document synthesis, code completion, and legal/academic analysis</strong>.</p>
<h3 id="heading-safety-and-trustworthiness"><strong>Safety and Trustworthiness</strong></h3>
<p>✅ <strong>Significant improvements in safety benchmarks</strong>, reflecting <strong>a lower propensity for harmful or misleading outputs</strong>.</p>
<pre><code class="lang-python"><span class="hljs-comment"># SECTION 3: Post-training - Knowledge Distillation and Safety</span>
<span class="hljs-string">"""
This example demonstrates how to implement knowledge distillation to transfer knowledge
from a large teacher model to a smaller student model, as well as a basic safety classifier.
"""</span>

<span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">import</span> torch.nn <span class="hljs-keyword">as</span> nn
<span class="hljs-keyword">import</span> torch.nn.functional <span class="hljs-keyword">as</span> F
<span class="hljs-keyword">from</span> transformers <span class="hljs-keyword">import</span> AutoModelForCausalLM, AutoTokenizer
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Dict, List, Tuple

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KnowledgeDistillationTrainer</span>:</span>
    <span class="hljs-string">"""Trainer for knowledge distillation from a larger Gemma 3 model to a smaller one."""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">
        self,
        teacher_model_id: str,
        student_model_id: str,
        alpha: float = <span class="hljs-number">0.5</span>,  <span class="hljs-comment"># Balance between distillation and ground truth</span>
        temperature: float = <span class="hljs-number">2.0</span>,  <span class="hljs-comment"># Temperature for softening probability distributions</span>
    </span>):</span>
        <span class="hljs-comment"># Initialize teacher model (larger model like Gemma 3 27B)</span>
        self.teacher_model = AutoModelForCausalLM.from_pretrained(teacher_model_id)
        self.teacher_tokenizer = AutoTokenizer.from_pretrained(teacher_model_id)

        <span class="hljs-comment"># Initialize student model (smaller model to be trained)</span>
        self.student_model = AutoModelForCausalLM.from_pretrained(student_model_id)
        self.student_tokenizer = AutoTokenizer.from_pretrained(student_model_id)

        <span class="hljs-comment"># Freeze teacher parameters</span>
        <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> self.teacher_model.parameters():
            param.requires_grad = <span class="hljs-literal">False</span>

        self.alpha = alpha
        self.temperature = temperature

        <span class="hljs-comment"># Optimizer for student model</span>
        self.optimizer = torch.optim.AdamW(self.student_model.parameters(), lr=<span class="hljs-number">5e-5</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compute_distillation_loss</span>(<span class="hljs-params">
        self,
        teacher_logits: torch.Tensor,
        student_logits: torch.Tensor,
        target_ids: torch.Tensor,
        attention_mask: torch.Tensor
    </span>) -&gt; Tuple[torch.Tensor, Dict[str, float]]:</span>
        <span class="hljs-string">"""
        Compute the knowledge distillation loss.

        Args:
            teacher_logits: Logits from teacher model [batch, seq_len, vocab_size]
            student_logits: Logits from student model [batch, seq_len, vocab_size]
            target_ids: Target token IDs [batch, seq_len]
            attention_mask: Attention mask [batch, seq_len]

        Returns:
            total_loss: Combined distillation and cross-entropy loss
            loss_dict: Dictionary containing individual loss components
        """</span>
        <span class="hljs-comment"># Apply temperature to soften probability distributions</span>
        soft_teacher_logits = teacher_logits / self.temperature
        soft_student_logits = student_logits / self.temperature

        <span class="hljs-comment"># Compute KL divergence loss for knowledge distillation</span>
        distillation_loss = F.kl_div(
            F.log_softmax(soft_student_logits, dim=<span class="hljs-number">-1</span>),
            F.softmax(soft_teacher_logits, dim=<span class="hljs-number">-1</span>),
            reduction=<span class="hljs-string">"batchmean"</span>
        ) * (self.temperature ** <span class="hljs-number">2</span>)

        <span class="hljs-comment"># Compute cross-entropy loss against ground truth</span>
        ce_loss = F.cross_entropy(
            student_logits.view(<span class="hljs-number">-1</span>, student_logits.size(<span class="hljs-number">-1</span>)),
            target_ids.view(<span class="hljs-number">-1</span>),
            ignore_index=<span class="hljs-number">-100</span>
        )

        <span class="hljs-comment"># Combine losses</span>
        total_loss = self.alpha * distillation_loss + (<span class="hljs-number">1</span> - self.alpha) * ce_loss

        <span class="hljs-keyword">return</span> total_loss, {
            <span class="hljs-string">"total_loss"</span>: total_loss.item(),
            <span class="hljs-string">"distillation_loss"</span>: distillation_loss.item(),
            <span class="hljs-string">"ce_loss"</span>: ce_loss.item()
        }

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">train_step</span>(<span class="hljs-params">self, batch: Dict[str, torch.Tensor]</span>) -&gt; Dict[str, float]:</span>
        <span class="hljs-string">"""Perform a single training step with knowledge distillation."""</span>
        <span class="hljs-comment"># Move batch to device</span>
        input_ids = batch[<span class="hljs-string">"input_ids"</span>]
        attention_mask = batch[<span class="hljs-string">"attention_mask"</span>]
        target_ids = batch[<span class="hljs-string">"labels"</span>]

        <span class="hljs-comment"># Forward pass through teacher model (no gradients)</span>
        <span class="hljs-keyword">with</span> torch.no_grad():
            teacher_outputs = self.teacher_model(
                input_ids=input_ids,
                attention_mask=attention_mask,
                return_dict=<span class="hljs-literal">True</span>
            )
            teacher_logits = teacher_outputs.logits

        <span class="hljs-comment"># Forward pass through student model</span>
        student_outputs = self.student_model(
            input_ids=input_ids,
            attention_mask=attention_mask,
            return_dict=<span class="hljs-literal">True</span>
        )
        student_logits = student_outputs.logits

        <span class="hljs-comment"># Compute loss</span>
        loss, loss_dict = self.compute_distillation_loss(
            teacher_logits, student_logits, target_ids, attention_mask
        )

        <span class="hljs-comment"># Backward pass and update student parameters</span>
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

        <span class="hljs-keyword">return</span> loss_dict


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SafetyClassifier</span>(<span class="hljs-params">nn.Module</span>):</span>
    <span class="hljs-string">"""Safety classifier based on a pre-trained model to detect harmful content."""</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, base_model_id: str, num_safety_categories: int = <span class="hljs-number">8</span></span>):</span>
        super().__init__()
        <span class="hljs-comment"># Load base model</span>
        self.tokenizer = AutoTokenizer.from_pretrained(base_model_id)
        self.encoder = AutoModelForCausalLM.from_pretrained(base_model_id)

        <span class="hljs-comment"># Freeze base model</span>
        <span class="hljs-keyword">for</span> param <span class="hljs-keyword">in</span> self.encoder.parameters():
            param.requires_grad = <span class="hljs-literal">False</span>

        <span class="hljs-comment"># Classification head</span>
        self.safety_head = nn.Sequential(
            nn.Linear(self.encoder.config.hidden_size, <span class="hljs-number">512</span>),
            nn.ReLU(),
            nn.Dropout(<span class="hljs-number">0.1</span>),
            nn.Linear(<span class="hljs-number">512</span>, num_safety_categories)
        )

        <span class="hljs-comment"># Safety categories</span>
        self.safety_categories = [
            <span class="hljs-string">"hate_speech"</span>,
            <span class="hljs-string">"harassment"</span>,
            <span class="hljs-string">"self_harm"</span>,
            <span class="hljs-string">"sexual_content"</span>,
            <span class="hljs-string">"violence"</span>,
            <span class="hljs-string">"dangerous_content"</span>,
            <span class="hljs-string">"misinformation"</span>,
            <span class="hljs-string">"personal_data"</span>
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">forward</span>(<span class="hljs-params">self, input_ids: torch.Tensor, attention_mask: torch.Tensor</span>) -&gt; torch.Tensor:</span>
        <span class="hljs-string">"""Forward pass to classify text for safety risks."""</span>
        <span class="hljs-comment"># Get embeddings from base model</span>
        <span class="hljs-keyword">with</span> torch.no_grad():
            outputs = self.encoder(
                input_ids=input_ids,
                attention_mask=attention_mask,
                output_hidden_states=<span class="hljs-literal">True</span>,
                return_dict=<span class="hljs-literal">True</span>
            )

            <span class="hljs-comment"># Use the last hidden state of the final token</span>
            last_token_indices = attention_mask.sum(dim=<span class="hljs-number">1</span>) - <span class="hljs-number">1</span>
            batch_indices = torch.arange(input_ids.size(<span class="hljs-number">0</span>))
            last_token_hidden = outputs.hidden_states[<span class="hljs-number">-1</span>][batch_indices, last_token_indices]

        <span class="hljs-comment"># Pass through safety classification head</span>
        safety_logits = self.safety_head(last_token_hidden)
        <span class="hljs-keyword">return</span> safety_logits

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">classify_text</span>(<span class="hljs-params">self, text: str, threshold: float = <span class="hljs-number">0.5</span></span>) -&gt; Dict[str, float]:</span>
        <span class="hljs-string">"""Classify a text for safety risks."""</span>
        <span class="hljs-comment"># Tokenize text</span>
        inputs = self.tokenizer(
            text,
            return_tensors=<span class="hljs-string">"pt"</span>,
            truncation=<span class="hljs-literal">True</span>,
            max_length=<span class="hljs-number">512</span>,
            padding=<span class="hljs-literal">True</span>
        )

        <span class="hljs-comment"># Get safety logits</span>
        safety_logits = self(inputs.input_ids, inputs.attention_mask)

        <span class="hljs-comment"># Apply sigmoid to get probabilities</span>
        safety_probs = torch.sigmoid(safety_logits).squeeze().detach().numpy()

        <span class="hljs-comment"># Create results dictionary</span>
        results = {
            category: float(prob)
            <span class="hljs-keyword">for</span> category, prob <span class="hljs-keyword">in</span> zip(self.safety_categories, safety_probs)
        }

        <span class="hljs-comment"># Add overall safety assessment</span>
        results[<span class="hljs-string">"is_unsafe"</span>] = any(prob &gt; threshold <span class="hljs-keyword">for</span> prob <span class="hljs-keyword">in</span> safety_probs)
        results[<span class="hljs-string">"max_risk_category"</span>] = self.safety_categories[safety_probs.argmax()]
        results[<span class="hljs-string">"max_risk_score"</span>] = float(safety_probs.max())

        <span class="hljs-keyword">return</span> results
</code></pre>
<hr />
<p><img src="https://storage.googleapis.com/gweb-uniblog-publish-prod/images/Chatbot_Arena_ELO_Score.width-1000.format-webp.webp" alt="Bar graph titled &quot;Chatbot Arena Elo Score&quot; showing performance of various chatbots. Gemma 3 27B is highlighted with a score of 1338. Other chatbots include DeepSeek R1, DeepSeek v3, o3-mini, Llama3-405B, Mistral Large, and Gemma 2 27B, with scores ranging from 1363 to 1220. Below each bar, the model size is listed, and the number of NVIDIA H100 GPUs required is represented by a grid of dots, with Gemma 3 27B requiring 8 GPUs." /></p>
<h2 id="heading-final-thoughts-the-future-of-open-ai"><strong>Final Thoughts: The Future of Open AI</strong></h2>
<p>Gemma 3 represents a <strong>significant advancement in scalable, efficient, and safe AI</strong>, demonstrating <strong>Google’s commitment to open research and responsible AI development</strong>.</p>
<p>With its <strong>cutting-edge transformer refinements, long-context capabilities, and multimodal integration</strong>, this model is poised to <strong>accelerate progress in AI research and real-world applications</strong>.</p>
<p><a target="_blank" href="https://blog.google/technology/developers/gemma-3/">Gemma 3 Blog - Google</a></p>
<p><a target="_blank" href="https://storage.googleapis.com/deepmind-media/gemma/Gemma3Report.pdf">Gemma 3 Technical Report</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Gemma 3 stands as a remarkable leap forward in the realm of open-source multimodal AI, showcasing Google's dedication to advancing AI technology responsibly and efficiently. With its innovative transformer architectures, extensive multilingual capabilities, and robust multimodal integration, Gemma 3 is set to drive significant progress in AI research and practical applications. Its ability to process long contexts and handle diverse tasks with improved safety and ethical standards positions it as a pivotal tool for future developments in AI. As the landscape of AI continues to evolve, Gemma 3 exemplifies the potential of open-weight models to contribute to a more inclusive and advanced technological future.</p>
<p>#AI #MachineLearning #LLM #OpenSource #MultimodalAI #Gemma3 #GoogleAI #GoogleDeepMind</p>
]]></content:encoded></item></channel></rss>