<?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" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Barhoumi Mosbeh on Medium]]></title>
        <description><![CDATA[Stories by Barhoumi Mosbeh on Medium]]></description>
        <link>https://medium.com/@Mosbeh_Barhoumi?source=rss-541d7f6904a2------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*7sBDxkKv1qNblAJJ8o-Trw.jpeg</url>
            <title>Stories by Barhoumi Mosbeh on Medium</title>
            <link>https://medium.com/@Mosbeh_Barhoumi?source=rss-541d7f6904a2------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 10 Nov 2026 05:45:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@Mosbeh_Barhoumi/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Why Do Chinese LLMs Switch to Chinese in Complex Interactions?]]></title>
            <link>https://pub.towardsai.net/why-do-chinese-llms-switch-to-chinese-in-complex-interactions-d18daac872b8?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/d18daac872b8</guid>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[genai]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Tue, 10 Dec 2024 20:02:03 GMT</pubDate>
            <atom:updated>2024-12-10T20:02:03.449Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*j9XXAAQ7RzeNIbgv3a28EQ.jpeg" /><figcaption><a href="https://x.com/DanraeP/status/1835564238791647445/photo/1">source</a></figcaption></figure><p>When I was a kid, my parents always encouraged me to learn other languages and even aim to speak 3 or 4 fluently. They especially emphasized learning English because most of the best resources on the internet are written in English. I often heard the same advice from my teachers: “If you know two languages, you have two brains.” That’s 100% true! My native language is Arabic, but when it comes to writing something like this, I find it almost impossible to do it in Arabic. I learned AI and other technical skills in English, so it’s much easier for me to express myself in it (and it’s easier on the keyboard too, xD).</p><p>Recently, I’ve been using DeepSeek, one of the most advanced AI models out there, and I have to say, it’s been a game-changer. It’s helped me solve some really tough technical problems with its deep thinking option. However, I’ve noticed something strange: <strong>Sometimes, for particularly hard tasks, it switches to Chinese for no apparent reason. It’s weird to ask a question in English and get an answer in Chinese (or a part of the answer). This got me thinking about this phenomenon. Why does this happen?</strong></p><p>Chinese LLMs are designed to understand and generate text in multiple languages, including English and Chinese. The decision to switch languages mid-conversation could be influenced by several factors, including the model’s training data, the context of the conversation, and the specific instructions or prompts provided by the user.</p><h3>Why?</h3><p>I have seen a lot of posts on Reddit or LinkedIn saying that these models switch to their “mother language” like humans do when they have to think about “hard” cases. For me, for example, when I had a deep conversation, I may not be able to go deeper with a native speaker about elections in the US and the results. I don’t have that much deep knowledge in politics in English, but I’ll be able to speak about the situation in the Middle East with you for about consecutive 10 hours because I have enough knowledge specifically in Arabic. This is because most of the time, I’m reading and hearing the news in Arabic.</p><p>Can this be the case with Chinese LLMs? Short answer: no! I don’t believe that this is the case with these models. It’s just an issue that can be the result of many problems in training data imbalance, or how reinforcement learning (RL) is done.</p><h3>Training Data Imbalance</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*c-PKzi1Hf6NDoUkvD6j6eA.png" /><figcaption>image from the author</figcaption></figure><p>One of the primary reasons for this language shift is the composition of the training data. These models are often trained on vast amounts of Chinese text, which makes them more proficient and confident in Chinese. When faced with intricate queries, the model might revert to Chinese because it has a richer understanding and more comprehensive data in this language. This is somewhat analogous to how humans might switch to their mother tongue when discussing complex topics, as it offers a more nuanced and precise means of expression.</p><h3>Model Architecture and Reinforcement Learning</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/596/1*d-shG0lvrYdaENf9V2_IUQ.png" /><figcaption><a href="https://x.com/karpathy/status/1835561952258723930?s=19">source</a></figcaption></figure><p>The architecture of these models plays a significant role in their language choice. If the model is designed with a bias towards Chinese, either due to the training data or the reinforcement learning from human feedback (RLHF) process, it might naturally favor Chinese responses. For instance, if the feedback used in the RLHF process is predominantly in Chinese, the model might learn to prefer Chinese outputs, even in mixed-language conversations.</p><h3>Cultural and Linguistic Nuances</h3><p>Chinese language and culture are deeply intertwined, offering a rich tapestry of expressions and nuances that might be better suited for certain discussions. The model might prefer Chinese for complex tasks because it can express subtleties and context more effectively in this language. This cultural and linguistic richness can make Chinese a more efficient medium for intricate conversations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*SR468pqat_PKDg8oanUl9Q.png" /><figcaption>image from the author</figcaption></figure><h3>Technical Considerations: Tokenization and Efficiency</h3><p>From a technical standpoint, the model’s internal processing, including tokenization and language modeling, might be more efficient in Chinese for certain tasks. If processing Chinese text requires fewer computational resources or offers more efficient representations, the model might default to Chinese for resource-intensive tasks.</p><p><strong>The advantage of “thinking” in Chinese is that a single token contains so much more information than Western languages.</strong> In Chinese, a single character can represent an entire word or concept, whereas in languages like English, multiple characters (letters) are often needed to form a single word. This means that Chinese text can be tokenized into fewer units, which can significantly reduce the computational load and improve processing speed.</p><p>For example, the phrase “中华人民共和国” (People’s Republic of China) consists of just five characters, but if translated into English, it becomes “People’s Republic of China,” which requires more tokens to represent. This efficiency in tokenization can lead to better performance, especially in tasks that require deep understanding and long-range dependencies.</p><p><strong>I would not be surprised if they discover that having a chain of thoughts in Chinese improves overall performance and optimizes context length.</strong> The ability to convey complex ideas with fewer tokens can allow the model to maintain a longer and more coherent context, which is crucial for tasks that require reasoning and deep understanding.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*mltUE0D5pC7235OpCdYhkA.png" /><figcaption>image from the author</figcaption></figure><h3>User Interaction and Prompt Influence</h3><p>User interaction patterns can also influence the model’s language choice. If the majority of users interacting with the model are Chinese-speaking, the model might naturally gravitate towards Chinese responses. Additionally, the structure and content of prompts can guide the language output. Prompts containing Chinese keywords or cultural references might trigger a Chinese response, as the model seeks to provide contextually appropriate answers.</p><h3>Conclusion</h3><p>In summary, the tendency of Chinese LLMs to switch to Chinese during complex interactions is a multifaceted phenomenon. It is influenced by the composition of their training data, architectural design, user interaction patterns, cultural nuances, and technical efficiencies. Understanding these factors provides valuable insights into the behavior of these models and highlights the importance of considering language biases and cultural contexts in the development of AI systems.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d18daac872b8" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/why-do-chinese-llms-switch-to-chinese-in-complex-interactions-d18daac872b8">Why Do Chinese LLMs Switch to Chinese in Complex Interactions?</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Apple: LLMs CANNOT Reason]]></title>
            <link>https://pub.towardsai.net/apple-llms-cannot-reason-acdaeab9b796?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/acdaeab9b796</guid>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[intelligence]]></category>
            <category><![CDATA[gpt]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Wed, 20 Nov 2024 12:02:08 GMT</pubDate>
            <atom:updated>2024-11-20T12:02:08.599Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/900/1*XFsDMgoWFrk4YjLtaGR--Q.png" /><figcaption><a href="https://news.mit.edu/2024/reasoning-skills-large-language-models-often-overestimated-0711">source</a></figcaption></figure><p>When ChatGPT first came out, like everyone else, I was amazed by how smart it seemed. But then we all started asking: is it really smart, or is it just copying and mixing up responses from its training data? After just a year, people began talking about AGI and what it means to be intelligent. Then a few months ago, Apple dropped a research paper saying:</p><blockquote>We think LLMs are getting worse at some tasks because they can’t really do logical thinking. Instead, they just try to copy the thinking steps they saw in their training data.</blockquote><p>This reminds me of when I was a kid arguing with my friend who was the top student in my class. I used to tell him, “You’re not really smart you’re just better at remembering things. That’s why you’re good at history, but I’m better at math and physics.” Now I’m an engineer and he’s a doctor (fair enough xD).</p><p>It’s funny how this is just like what we’re doing now with LLMs asking if they’re smart or can think, even though we know they’re already better than humans at many things. We know they’re repeating or copying things because they learned from our data, so of course they will! In this article, I’ll share my thoughts about this and what researchers think about whether LLMs can really reason or not.</p><h3>Reasoning</h3><p>When someone asks you a simple question like “what’s 1+1?”, you don’t need to think, you just know it’s 2 right away. That’s not reasoning.</p><p>But when someone asks “what’s 641+237?”, you need more time to think. A kid might solve it step by step:</p><ul><li>First: 7+1=8</li><li>Then: 3+4=7</li><li>Finally: 6+2=8 So the answer is 878</li></ul><p>Here’s the interesting part: if I ask 10 different people to solve this, they’ll all get 878, but they might solve it in different ways. Some might start from the left, others from the right, but they all reach the same answer.</p><p>The Apple team made testing LLMs really simple. They just changed small some attributes in easy problems to see if the LLMs could still solve them. You can see what they did in the image below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1011/1*EHxSE_hfHC7vq7xJKYDtZw.png" /><figcaption><a href="https://arxiv.org/pdf/2410.05229v1">source</a></figcaption></figure><h3>How much these changes affect the results</h3><p>The Apple team did a simple test. They took GSM8K (a dataset where most LLMs perform well) and made small changes to it — like switching names, family members, and numbers. Their thinking was simple: if LLMs can truly reason, they should perform just as well on these slightly changed problems as they do on the original ones.</p><p>You’d expect the results to be the same — after all, changing “John has 5 apples” to “Mary has 5 apples” shouldn’t affect the math, right? But surprisingly, every LLM’s performance dropped. Looking at the image:</p><ul><li>Smaller and mid-size models showed the biggest drop</li><li>Larger models were less affected:</li></ul><blockquote>GPT-4o only dropped by -0.3%</blockquote><blockquote>o1-preview dropped by -2.2% (The new series of reasoning models for solving hard problems from OpenAI it’s actually worse than GPT-4o)</blockquote><p>This trend shows something interesting: bigger models seem more resistant to these small changes. But the key point remains all models, even the largest ones, still showed some drop in performance. This suggests that LLMs might not be truly reasoning through the problems, but rather relying on recognizing patterns from their training data, just in different degrees based on their size.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dSMrq8XyNBJdlu1pYz9IoA.png" /><figcaption><a href="https://arxiv.org/pdf/2410.05229v1">source</a></figcaption></figure><h3>Funniest part</h3><p>Researchers also conducted various tests of LLMs’ reasoning abilities, but one particularly fascinating experiment stood out. Instead of just making problems more complex with additional relevant clauses, they tested how models handle irrelevant information by:</p><ol><li>Starting with a simple mathematical word problem</li><li>Adding a single irrelevant clause that sounds related but shouldn’t affect the calculation</li></ol><p>Here’s their test case:</p><p><strong>Original question:</strong> Oliver picks 44 kiwis on Friday. Then he picks 58 kiwis on Saturday. On Sunday, he picks double the number of kiwis he did on Friday. How many kiwis does Oliver have?</p><p><strong>Modified version:</strong> They simply added “but five of them were a bit smaller than average” to the problem.</p><p>The results were revealing: Both o1-mini and Llama3–8B fell into the trap. Despite this information being purely descriptive and irrelevant to the counting task, both models incorrectly subtracted these 5 kiwis from the total. This shows an interesting limitation in their ability to distinguish between relevant and irrelevant information in word problems.</p><p>This simple test effectively exposed how LLMs can be misled by irrelevant details that seem contextually related to the problem but shouldn’t affect the mathematical solution.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2PKSR6CnzM_--1xL_oFeeA.png" /><figcaption><a href="https://arxiv.org/pdf/2410.05229v1">source</a></figcaption></figure><h3>Are LLMs Really Reasoning?</h3><p>After diving into these experiments, one thing becomes crystal clear: LLMs are impressive, but they’re not reasoning the way humans do. They’re incredibly sophisticated pattern-matching machines that can mimic reasoning, but fundamentally, they’re still struggling with true logical thinking.</p><p>The Apple research and other experiments reveal a crucial insight: <strong>LLMs tend to rely heavily on pattern recognition from their training data.</strong> When problems are slightly modified, their performance drops. When irrelevant information is introduced, they can get confused. It’s like they’re memorizing solutions rather than truly understanding the underlying logic.</p><p>Interestingly, the size of the model matters. Larger models like GPT-4o show more resistance to these small changes, suggesting that with scale, these systems might get closer to genuine reasoning. But “closer” doesn’t mean “there yet”.</p><h4>LLMs be <strong>like:</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/470/1*ldATW94Boti8S2gvIMUmYw.png" /><figcaption><a href="https://www.reddit.com/r/OpenAI/comments/1g26o4b/apple_research_paper_llms_cannot_reason_they_rely/">source</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=acdaeab9b796" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/apple-llms-cannot-reason-acdaeab9b796">Apple: LLMs CANNOT Reason</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Qwen 2.5 Coder 32B: Is This Best Open Weight Model Better than GPT-4o and Claude 3.5 Sonnet]]></title>
            <link>https://pub.towardsai.net/qwen-2-5-coder-32b-is-this-best-open-weight-model-better-than-gpt-4o-and-claude-3-5-sonnet-9d9cba7d25fa?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/9d9cba7d25fa</guid>
            <category><![CDATA[alibaba]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[code]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Mon, 18 Nov 2024 12:02:39 GMT</pubDate>
            <atom:updated>2024-11-18T12:02:39.083Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VCjOflU1i-Y9u92iLdgY-Q.jpeg" /><figcaption><a href="https://qwen2.org/qwen2-5-coder-32b-instruct/">source</a></figcaption></figure><p>On November 11, Alibaba announced its most advanced coding model to date: <strong>Qwen 2.5-Coder-32B-Instruct</strong>. But that’s not all, it’s actually part of a whole family of coding models! In addition to the 32B model, there are versions with 0.5B, 1.5B, 3B, 7B, and 14B parameters. Before writing this article, I reviewed feedback from many of YouTubers, writers, and technical experts, and the consensus has been overwhelmingly positive. Today, we’ll explore whether it really lives up to the hype.</p><p>I’ve been using ChatGPT, Gemini, and Claude for a while, and I can confidently say that <strong>Claude is the best at coding and understanding complex tasks.</strong> To be honest, Gemini is in a different league altogether. Fun fact: I once won a machine learning competition two years ago using Bard (now rebranded as Gemini) because everyone else was using ChatGPT. Bard’s performance gave me a competitive edge back then. Today, I believe Gemini might be the best vision model available, but overall, I’m not a big fan.</p><p>To <strong>evaluate</strong> the model’s performance in coding, we should cover the following three key aspects: <strong>Code Generation</strong>, <strong>Code Repair</strong>, and <strong>Code Reasoning</strong>. Additionally, we need to consider how many programming languages the model supports and its alignment with human preferences.</p><h3>Overview</h3><p>Before testing out Alibaba’s model, let’s take a look at the performance results they have announced.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Olo_zJmTQdmNzyfNfQwwA.png" /><figcaption><a href="https://qwen2.org/qwen2-5-coder-32b-instruct/">source</a></figcaption></figure><p>Based on their internal benchmarks, it even outperforms GPT-4 and comes very close to Claude 3.5. However, I personally don’t place too much weight on internal benchmarks alone, but the results seem very interesting according to those who have tried it.</p><p>You can find more details about the performance here:</p><p><a href="https://qwen2.org/qwen2-5-coder-32b-instruct/">Qwen2.5-Coder-32B-Instruct - Qwen2</a></p><p>I’m testing the model locally using <strong>Ollama</strong>:</p><p><a href="https://ollama.com/library/qwen2.5-coder:32b">qwen2.5-coder:32b</a></p><p>You can also try out the model on the demo page of Hugging Face:</p><p><a href="https://huggingface.co/spaces/Qwen/Qwen2.5-Coder-demo">Qwen2.5 Coder Demo - a Hugging Face Space by Qwen</a></p><h3><strong>Code Generation</strong></h3><p>Many people have already covered how well it performs in web and design:</p><iframe src="https://cdn.embedly.com/widgets/media.html?type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=reddit&amp;url=https%3A//www.reddit.com/r/LocalLLaMA/comments/1gpkm63/try_this_prompt_on_qwen25coder32binstructq8_0/&amp;image=" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/602f568bbb5f25e2ad036aba04406bc8/href">https://medium.com/media/602f568bbb5f25e2ad036aba04406bc8/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FKYvVl0UT1Sk%3Fstart%3D473%26feature%3Doembed%26start%3D473&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DKYvVl0UT1Sk&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FKYvVl0UT1Sk%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/22874386f27d386ddba9300b7ede94e3/href">https://medium.com/media/22874386f27d386ddba9300b7ede94e3/href</a></iframe><p>So, we will focus on testing it with some Python challenges. Let’s start with a medium-level LeetCode problem:</p><h4>Prompt</h4><p>The problem description: <a href="https://leetcode.com/problems/longest-substring-without-repeating-characters/">Longest Substring Without Repeating Characters</a></p><h4>Answer</h4><pre>class Solution(object):<br>    def lengthOfLongestSubstring(self, s):<br>        &quot;&quot;&quot;<br>        :type s: str<br>        :rtype: int<br>        &quot;&quot;&quot;<br>        # Dictionary to store the last seen index of each character<br>        char_index_map = {}<br>        # Initialize the start of the current window and the maximum length<br>        start = 0<br>        max_length = 0<br>        <br>        for end in range(len(s)):<br>            # If the character is already in the map and its index is within the current window<br>            if s[end] in char_index_map and char_index_map[s[end]] &gt;= start:<br>                # Move the start to the right of the last occurrence of the current character<br>                start = char_index_map[s[end]] + 1<br>            <br>            # Update the last seen index of the current character<br>            char_index_map[s[end]] = end<br>            <br>            # Update the maximum length of the substring found so far<br>            max_length = max(max_length, end - start + 1)<br>        <br>        return max_length</pre><h4>Results</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/738/1*dC_JN5KPGyvVL8DHPkaIWw.png" /><figcaption>Image from the author</figcaption></figure><p>Not the best, but it gets things done and passes all the tests. Can it solve a hard problem? (Note that the model could have been trained on these problems already, but it’s still impressive.)</p><h4>Prompt</h4><p>Problem description: <a href="https://leetcode.com/problems/regular-expression-matching/">Regular Expression Matching</a></p><h4>Answer</h4><pre>class Solution(object):<br>    def isMatch(self, s, p):<br>        &quot;&quot;&quot;<br>        :type s: str<br>        :type p: str<br>        :rtype: bool<br>        &quot;&quot;&quot;<br>        m, n = len(s), len(p)<br>        <br>        # Create a 2D array to store the results of subproblems<br>        dp = [[False] * (n + 1) for _ in range(m + 1)]<br>        <br>        # Base case: empty string matches empty pattern<br>        dp[0][0] = True<br>        <br>        # Handle patterns like a*, a*b*, etc., which can match an empty string<br>        for j in range(1, n + 1):<br>            if p[j - 1] == &#39;*&#39;:<br>                dp[0][j] = dp[0][j - 2]<br>        <br>        # Fill the dp table<br>        for i in range(1, m + 1):<br>            for j in range(1, n + 1):<br>                if p[j - 1] == &#39;.&#39; or p[j - 1] == s[i - 1]:<br>                    dp[i][j] = dp[i - 1][j - 1]<br>                elif p[j - 1] == &#39;*&#39;:<br>                    dp[i][j] = dp[i][j - 2]  # &#39;*&#39; matches zero occurrences<br>                    if p[j - 2] == &#39;.&#39; or p[j - 2] == s[i - 1]:<br>                        dp[i][j] = dp[i][j] or dp[i - 1][j]  # &#39;*&#39; matches one or more occurrences<br>        <br>        # The result is in dp[m][n]<br>        return dp[m][n]</pre><h4>Results</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/738/1*EAVdPYg7iD9u7P7E5vyk_g.png" /><figcaption>Image from the author</figcaption></figure><p>After testing it on 10–20 problems on LeetCode, I have the impression that it was trained on all problems, so it’s not the best way to evaluate it. However, it’s still worth sharing. Additionally, it always chooses to provide a Python solution, even when not specifically asked for one. But let’s try something different. <strong>I asked the model to optimize the code to minimize resource consumption as much as possible.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*OlyL-ylYp2wKGJKDvp5BWA.png" /><figcaption>Image from the author</figcaption></figure><p><strong><em>I didn’t expect that, but when I asked the model to improve the performance, it even fails in the simplest cases.</em></strong></p><p>Let’s now move to the next test, <strong>Code Repair</strong>. I will be providing the model with some code containing errors generated by Claude. I asked the model to generate some hard cases to fix, and let’s see how it performs.</p><h3><strong>Code Repair</strong></h3><h4>Prompt</h4><pre>The following code contains several bugs. Please identify and fix them, <br>and provide an explanation for each bug you find.<br>class AsyncTaskQueue:<br>    def __init__(self):<br>        self.tasks = []<br>        self.running = False<br>        self.lock = threading.Lock()<br>        self.workers = []<br><br>    async def add_task(self, task):<br>        async with self.lock:  <br>            self.tasks.append(task)<br>            if not self.running:<br>                self.start_processing()<br><br>    async def start_processing(self):<br>        self.running = True<br>        while self.tasks:<br>            task = self.tasks.pop(0)<br>            worker = asyncio.create_task(self.process_task(task))<br>            self.workers.append(worker)<br>            if len(self.workers) &gt;= 3:<br>                <br>                done, pending = await asyncio.wait(self.workers)<br>                self.workers = list(pending)<br>        self.running = False<br><br>    async def process_task(self, task):<br>        result = await task()<br>        return result  </pre><h4>Answer</h4><pre>Certainly! Let&#39;s go through the provided code and identify the issues, then correct them. Here are the main problems and their fixes:<br><br>Issues Identified<br>Threading Lock Usage with Asyncio:<br>The threading.Lock is not suitable for use with asyncio. Instead, you should use asyncio.Lock.<br>Async Context Manager for Lock:<br>The async with statement is used incorrectly with threading.Lock. It should be used with asyncio.Lock.<br>Starting Processing:<br>The start_processing method should be called in a non-blocking manner. Since start_processing is an async method, it should be awaited properly.<br>Task Management:<br>The start_processing method should handle task processing more efficiently. The current implementation might not handle task completion correctly.<br>Worker Management:<br>The workers list should be managed more carefully to ensure that tasks are completed before marking the queue as not running.<br>Corrected Code<br>Here&#39;s the corrected version of the code:<br><br><br>import asyncio<br>import threading<br><br>class AsyncTaskQueue:<br>    def __init__(self):<br>        self.tasks = []<br>        self.running = False<br>        self.lock = asyncio.Lock()<br>        self.workers = []<br><br>    async def add_task(self, task):<br>        async with self.lock:<br>            self.tasks.append(task)<br>            if not self.running:<br>                self.running = True<br>                asyncio.create_task(self.start_processing())<br><br>    async def start_processing(self):<br>        while True:<br>            async with self.lock:<br>                if not self.tasks:<br>                    self.running = False<br>                    break<br>                task = self.tasks.pop(0)<br>            <br>            worker = asyncio.create_task(self.process_task(task))<br>            self.workers.append(worker)<br>            <br>            if len(self.workers) &gt;= 3:<br>                done, pending = await asyncio.wait(self.workers, return_when=asyncio.FIRST_COMPLETED)<br>                self.workers = list(pending)<br><br>    async def process_task(self, task):<br>        result = await task()<br>        return result<br><br># Example usage<br>async def example_task():<br>    await asyncio.sleep(1)<br>    print(&quot;Task completed&quot;)<br>    return &quot;Result&quot;<br><br>async def main():<br>    queue = AsyncTaskQueue()<br>    await queue.add_task(example_task)<br>    await queue.add_task(example_task)<br>    await queue.add_task(example_task)<br>    await queue.add_task(example_task)<br>    await queue.add_task(example_task)<br>    await queue.add_task(example_task)<br><br>asyncio.run(main())<br>Explanation of Fixes<br>Asyncio Lock:<br>Replaced threading.Lock with asyncio.Lock to ensure compatibility with asynchronous operations.<br>Async Context Manager for Lock:<br>Used async with self.lock: to properly manage the lock in an asynchronous context.<br>Starting Processing:<br>Changed the logic to start processing in a non-blocking manner by using asyncio.create_task(self.start_processing()) inside add_task.<br>Task Management:<br>Modified start_processing to continuously check for tasks and process them until no tasks are left. It breaks out of the loop when there are no more tasks and sets self.running to False.<br>Worker Management:<br>Ensured that workers are managed correctly by using asyncio.wait with return_when=asyncio.FIRST_COMPLETED to handle task completion efficiently.<br>Example Usage<br>The example usage demonstrates how to add tasks to the AsyncTaskQueue and run them asynchronously. The main function adds several tasks to the queue, and they are processed concurrently with a maximum of 3 workers at a time.<br><br>This corrected and optimized code should perform better and be more reliable.</pre><h4>Results and feedback</h4><p><em>Claude evaluates the model’s response as 7.5/10. with this feedback:</em></p><blockquote>While the model provided a functionally correct solution, it delivered a “tutorial-grade” fix rather than a “production-grade” implementation. This indicates that for complex concurrent programming tasks, human expertise is still crucial for robust system design.</blockquote><p>After experimenting with the model, <strong>it gets the job done</strong>, but often requires follow-up prompts to improve the response. While it doesn’t struggle with understanding the task at hand and can correct most critical bugs, it still lacks some of the strengths seen in models like ChatGPT and Claude, particularly in areas such as error handling, resource management, and optimization. I believe these may be the model’s key weaknesses.</p><h3>Specialized LLMs: A New Era in AI</h3><p>It’s fascinating to witness the emergence of relatively small, domain-specific language models that can run locally. I believe we’re entering an exciting new era of specialized LLMs, and this is just the beginning. While the concept isn’t new, we’re finally seeing models that truly excel in specific domains.</p><p>The combination of RAG (Retrieval-Augmented Generation) and specialist LLMs could define the AI landscape in the coming months/years. We’re likely to see more powerful coding-focused models from industry leaders like OpenAI and Anthropic. Programming is perhaps one of the most natural domains for specialized AI, and we might soon see even more focused models, imagine LLMs specifically optimized for DevOps or front-end development!</p><blockquote>Don’t feel overwhelmed by these rapid advances. Yes, it can be somewhat daunting to see LLMs mastering skills that traditionally took years to develop. Coding, which has challenged humanity for decades, is being transformed before our eyes. But rather than seeing this as an endpoint, we should view it as an opportunity for growth and innovation.</blockquote><p>Whether the current wave of LLM advances slows down in the coming years or this is merely the beginning of a longer journey, our response should remain the same: stay curious, keep learning, and never stop innovating. The future of technology is being written right now, and we all have a part to play in shaping it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9d9cba7d25fa" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/qwen-2-5-coder-32b-is-this-best-open-weight-model-better-than-gpt-4o-and-claude-3-5-sonnet-9d9cba7d25fa">Qwen 2.5 Coder 32B: Is This Best Open Weight Model Better than GPT-4o and Claude 3.5 Sonnet</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Llama 3.2 Vision Review]]></title>
            <link>https://pub.towardsai.net/llama-3-2-vision-review-0ded9c11d5f6?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/0ded9c11d5f6</guid>
            <category><![CDATA[llama-3]]></category>
            <category><![CDATA[ollama]]></category>
            <category><![CDATA[gpt-4]]></category>
            <category><![CDATA[vision]]></category>
            <category><![CDATA[gpt]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Fri, 08 Nov 2024 16:02:25 GMT</pubDate>
            <atom:updated>2024-11-08T22:28:49.175Z</atom:updated>
            <content:encoded><![CDATA[<h3>Ollama multi-modal</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9iqYYSvmbMLoybdUBD6RcQ.jpeg" /></figure><p>Ollama has just announced its official support for the Llama 3.2 Vision models. The Llama 3.2 Vision models come in two sizes: 11 billion and 90 billion parameters. In this article, I will provide an overview of their performance in different cases, along with my personal thoughts on them.</p><blockquote>The Llama 3.2-Vision instruction-tuned models are optimized for v<strong>isual recognition, image reasoning, captioning, and answering general questions about an image</strong>. The models outperform many of the available open source and closed multimodal models on common industry benchmarks.</blockquote><p>Also the model supports many languages:</p><blockquote>For text only tasks, English, German, French, Italian, Portuguese, Hindi, Spanish, and Thai are officially supported. Llama 3.2 has been trained on a broader collection of languages than these 8 supported languages.<strong> <em>Note for image+text applications, English is the only language supported.</em></strong></blockquote><h3>Evaluation</h3><p>I will use the approach from this paper for evaluation, which actually argues that vision-language models are ‘blind.’ It tests models on several tasks:</p><p><a href="https://vlmsareblind.github.io/">VLMs are Blind</a></p><ul><li>Task 1: Line Intersections</li><li>Task 2: Two Circles</li><li>Task 3: Circled Letter</li><li>Task 4: Overlapping Shapes</li><li>Task 5: Nested Squares</li><li>Task 6: Counting Grid</li><li>Task 7: Subway Map</li></ul><p>I will choose the most challenging parts from each task and see if the model can get any of them right. Additionally, I will run the code around 10–20 times to calculate the average of accurate responses and identify any false results.</p><h3>Task 1: Line Intersections</h3><p><strong>Prompts:</strong></p><ol><li><em>“How many times do the blue and red lines touch each other? Answer with a number in curly brackets, e.g., {5}.”</em></li><li><em>“Count the intersection points where the blue and red lines meet. Put your answer in curly brackets, e.g., {2}.”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4qYcCQ3S8bfstT1S9UVqjg.png" /></figure><pre>The blue and red lines intersect at 2 points. Therefore, they touch each <br>other twice. {2}</pre><pre>The blue and red lines touch each other at three points. Therefore, <br>the answer is {3}.</pre><p><strong>Success rate &gt; 60%</strong></p><h3>Task 2: Two Circles</h3><p><strong>Prompts:</strong></p><ol><li><em>“Are the two circles touching each other? Answer with Yes/No.”</em></li><li><em>“Are the two circles overlapping? Answer with Yes/No.”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/341/1*5Wf_CKx98JxNP_S6OpTVaw.png" /></figure><pre>**Step 1: Identify the Circles**<br><br>The image contains a blue circle and a red circle.<br><br>**Step 2: Determine if the Circles are Touching Each Other**<br><br>To determine if the circles are touching each other, we need to check if they intersect at exactly one point or not. If they do not intersect at all, then they are not touching. If they intersect at more than one point, then they are overlapping but not necessarily touching.<br><br>**Step 3: Check for Intersection Points**<br><br>Upon examining the image closely, it appears that the two circles intersect at exactly one point. This means that the circles are indeed touching each other.<br><br>**Conclusion:**<br><br>Yes</pre><pre>The image depicts a diagram with two circles, one red and one blue. The red circle is positioned on the left side of the diagram, while the blue circle is located on the right side.<br><br>To determine whether the two circles are touching each other, we need to analyze their positions and sizes. Upon closer inspection, it becomes apparent that the two circles do not overlap or touch at any point. Instead, they appear to be separated by a small gap between them.<br><br>Therefore, based on this analysis, **No**, the two circles are not touching each other.</pre><p><strong>Success rate &gt; 80%</strong></p><h3>Task 3: The circled letter</h3><p><strong>Prompts:</strong></p><ol><li><em>“Which letter is being circled?”</em></li><li><em>“Which character is being highlighted with a red oval?”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*C3EumimMH1XYceAuRpYqqA.png" /></figure><pre>**Answer:** The letter &quot;n&quot; is highlighted in red and encircled.</pre><p><strong>Success rate: 100%</strong></p><h3>Task 4: Counting overlapping shapes</h3><p><strong>Prompts:</strong></p><ol><li><em>“How many {shapes} are in the image? Answer with only the number in numerical format.”</em></li><li><em>“Count the {shapes} in the image. Answer with a number in curly brackets e.g. {3}.”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_mAInNN61mfeYwzvCQBt-w.png" /></figure><p>The model answered with either 6, 7, or 8 but never gave the correct number, which is 9. And guess what? Even GPT-4 can’t do it!</p><p><strong>Success rate: 0%</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/659/1*HDUvuJbhHvLDtnNzhIzxHQ.png" /></figure><h3>Task 5: Following single-colored paths</h3><p><strong>Prompts:</strong></p><ol><li><em>“How many single-colored paths go from A to C? Answer with a number in curly brackets, e.g., {3}”</em></li><li><em>“Count the one-colored routes that go from A to C. Answer with a number in curly brackets, e.g., {3}.”</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4ZS-26gPvhUeYRFl1E-KAg.png" /></figure><pre>To find the number of single-colored paths from point A to point C, we need to count the distinct paths that only use one color throughout their entire length.<br><br>**Step 1: Identify the colors used on the graph**<br><br>Looking at the graph provided, we can see that there are four different colors used:<br><br>*   Red<br>*   Blue<br>*   Green<br>*   Purple<br><br>However, upon closer inspection, it becomes apparent that not all these colors are utilized in creating paths from A to C. We focus only on those colors that lead directly or indirectly from A to C without interruption.<br><br>**Step 2: Determine the relevant paths**<br><br>Upon examining the graph closely for paths using a single color from A to C:<br><br>*   There is one path going directly from A to B (using red) and then continuing in another segment.<br>*   Another path leads from A to D and then to C, but this involves two colors.<br><br>Given this analysis, only one path utilizes a single color continuously from A to C.<br><br>**Conclusion**<br><br>Therefore, the number of single-colored paths from point A to point C is {1}.<br><br>Answer: {1}.</pre><pre>To find the number of single-colored paths from point A to point C, we need to analyze the given graph and count the distinct paths that meet this criterion.<br><br>**Step 1: Identify Single-Colored Paths**<br><br>Single-colored paths are those where all edges belong to a single color. In this context, a path is considered single-colored if it consists entirely of red edges.<br><br>**Step 2: Count Distinct Red Edges from A to C**<br><br>From point A to point C, there are two distinct red edges that form a direct path:<br><br>- One edge connects A directly to C.<br>- Another set of edges forms a longer path through intermediate nodes but ultimately leads back to the same conclusion regarding single-color paths.<br><br>**Step 3: Consideration of Alternative Paths**<br><br>Upon closer inspection, it becomes apparent that while there are multiple paths from A to C, only two of these paths consist entirely of red edges. This is because any path involving more than one color would not be considered &quot;single-colored.&quot;<br><br>**Conclusion**<br><br>Given the analysis above, the correct answer reflects the count of single-colored paths (all red) from point A to point C.<br><br>Answer: {2}</pre><p><strong>Success rate &gt; 60%</strong></p><blockquote>Both GPT-4o and Claude 3.5 Sonnet failed in this task.</blockquote><p>After playing with this model for a while, I don’t see a significant difference; it can be compared to <strong>GPT-4o</strong> and <strong>Sonnet-3</strong>. However, it’s still not as good as <strong>Gemini-1.5 Pro</strong>, which I believe might be the best VLM right now. Keep in mind that this is just the 11B version of the model. If you have enough resources to test the 90B version, simply replace “11B” with “90B” in the following code.</p><h3>Try it yourself</h3><h4>Install Ollama</h4><pre>!curl -fsSL https://ollama.com/install.sh | sh</pre><h4>Start ollama</h4><pre>import os<br>get_ipython().system = os.system<br>!ollama serve &amp;</pre><h4>Pull the model</h4><pre>!ollama pull llama3.2-vision </pre><h4>Try it</h4><pre>import ollama<br>def extract_document_info(image_path):<br>    response = ollama.chat(<br>        model=&#39;llama3.2-vision&#39;,<br>        messages=[{<br>            &#39;role&#39;: &#39;user&#39;,<br>            &#39;content&#39;: &quot;your question about the image&quot;<br>            ),<br>            &#39;images&#39;: [image_path]<br>        }]<br>    )<br>    return response<br>#example<br>image_path =&quot;/kaggle/input/image.jpg&quot;<br>result = extract_document_info(image_path)<br>print(result[&quot;message&quot;][&quot;content&quot;])</pre><p>That’s it! This was a quick review of LLaMA 3.2 Vision (11B version). It’s actually good at OCR too, I tested it on some really challenging images. The 90B version is better, of course, but it requires substantial resources to run. Once I find a good resource, I’ll attach it!</p><ul><li><a href="https://ollama.com/library/llama3.2-vision:90b">llama3.2-vision:90b</a></li><li><a href="https://vlmsareblind.github.io/#task1">VLMs are Blind</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0ded9c11d5f6" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/llama-3-2-vision-review-0ded9c11d5f6">Llama 3.2 Vision Review</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stop Losing Context! How Late Chunking Can Enhance Your Retrieval Systems]]></title>
            <link>https://pub.towardsai.net/late-chunking-in-long-context-embedding-models-caf1c1209042?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/caf1c1209042</guid>
            <category><![CDATA[gpt]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[open-source]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Thu, 07 Nov 2024 23:02:00 GMT</pubDate>
            <atom:updated>2024-11-18T08:30:07.273Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*OG3PaxRn4epFYVv7ijtDbA.jpeg" /><figcaption><a href="https://img.youtube.com/vi/Hj7PuK1bMZU/0.jpg">source</a></figcaption></figure><p>In a previous article, we looked at <a href="https://medium.com/towards-artificial-intelligence/anthropics-new-rag-approach-e0c24a68893b">contextual retrieval from Anthropic</a>, which is their context enhancement technique for improving RAG systems. But there’s another technique called <strong>late chunking in long-context embedding models</strong>, which I think is a lot more interesting and can be significant.<br>Embeddings are one of the most critical components of any retrieval system but are often ignored or misused. When you are selecting an embedding model, you need to consider two very important parameters. One is the <strong>max tokens</strong>, which is basically the context window, and the second one is the <strong>embedding dimension</strong>, which is the output size of the embedding vector.<br>You have probably seen this huge max token size for some of the newest embedding models, but there is one major issue with these. In a standard RAG pipeline, irrespective of the size of the chunk, the output size of your embedding vector is going to remain the same. So, whether you are embedding five tokens or 5,000 tokens, the output is going to be exactly the same. That means these embedding models are going to be compressing a lot of information for long input chunks.<br>In most cases, you want to use smaller chunks, but that has its own problems. To understand that, let’s look at this example: here is a small paragraph regarding Tunisia:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RlU0EGQqGMDHy0KcvUkFug.png" /><figcaption>Image from the author</figcaption></figure><p>If you use a sentence-level chunking strategy, essentially each sentence is going to become its own different chunk. You can see that if you embed these different chunks separately, you will lose the contextual information. For example, “the country” is referring to Tunisia, but if this chunk is in isolation, it’s going to lose that context.<br><em>The contextual retrieval approach tries to summarize the documents and add contextual information to each chunk</em>, but there is a better approach, and that is late chunking.</p><p>Let’s first look at how “normal” chunking works.</p><h3><strong>Normal Chunking and Embedding Process</strong></h3><p>In the traditional chunking approach, the text is first divided into smaller chunks, and then each chunk is passed through a neural network, which is a Transformer model. The output of this process is embeddings for each of the individual tokens within the chunks. The contextual information in these tokens is limited to the chunk that they belong to. After generating the token embeddings, mean pooling is performed to compute the final output. This preserves the contextual information, but it is only within the individual chunks and is independent of the other chunks in the same document.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*t7c8Snx9kZCozP75r7Zqgw.png" /><figcaption><a href="https://jina.ai/news/late-chunking-in-long-context-embedding-models/">source</a></figcaption></figure><h3><strong>Late Chunking Approach</strong></h3><p>The late chunking approach reverses this process. Instead of dividing the document into chunks and then computing the embeddings, the whole text of the document is first passed through a Transformer model. This generates an embedding representation for each token, and these tokens now contain contextual information not only limited to a single chunk, but encompassing the entire document. After this step, the chunking process is performed, where the original text is divided into chunks, and the corresponding tokens are used to compute the mean pooling, resulting in the final representation.</p><blockquote>Since the chunking process is done at a later stage, this approach is called “late chunking”.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/429/1*KPnWT-lCdQxgqoGjPrOc9g.png" /><figcaption><a href="https://jina.ai/news/late-chunking-in-long-context-embedding-models/">source</a></figcaption></figure><h3>The best approach for retrieval</h3><p>The<strong> late chunking</strong> approach is directly related to another approach called <strong>late interaction</strong>, which is a <strong>COBERT-based approach, </strong>This is probably the best approach for retrieval, but it comes with a cost of storage needs. In this case, in the final step, you don’t do the pooling step, but you take individual token embeddings and store those token embeddings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*28wHCGf3ELO8iJ4mHNN63Q.png" /><figcaption><a href="https://weaviate.io/blog/late-chunking">source</a></figcaption></figure><p>A blog post from the <em>weaviate</em> team shows that if you embed about 100,000 documents with the same number of embeddings, you will need about 1.6 million vectors for a naive chunking approach, which is about 5 GB. However, if you were to do the late interaction or COBERT-based multi-vector representation, you will need about 2.5 terabytes, which is pretty huge. The reason is that you’re storing these embeddings for each token individually.</p><p>The late chunking approach, on the other hand, gives you the best of both worlds. Not only does it preserve the context in your final chunking process, but it also gives you about the same storage needs as the naive chunking approach. This makes the late chunking approach a more efficient and practical solution compared to the late interaction or COBERT-based approaches, which require significantly more storage.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/911/1*UR-A1IoXM1ZU_2Qmigwrww.png" /><figcaption><a href="https://weaviate.io/blog/late-chunking">source</a></figcaption></figure><h3>Results</h3><p>Late chunking is introduced by <a href="https://jina.ai/">Jina</a>, and they have their own <a href="https://huggingface.co/jinaai">embedding models</a>. According to the results presented in the table, the late chunking approach, when combined with other methods, demonstrates promising performance across various benchmarks.</p><blockquote>The choice of embedding model plays a critical role, and the results presented here may require further validation from independent sources.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1yff7HcY2bdOfGw7gpMxZA.png" /></figure><h3>Practical Implementation Guide</h3><p>The folks behind this new idea have put together a really <a href="https://github.com/jina-ai/late-chunking/tree/main">simple notebook</a> that walks through how you can implement this late chunking approach in your own applications and pipelines. Even though we’re not going to dive into the notebook itself, let me provide you an idea about the results.</p><p>In the notebook they have computed the similarity of “Berlin” as a single individual token to some embeddings. If you look at the first sentence, which talks about Berlin directly and mentions “Berlin,” both the traditional and late chunking outputs are going to give you very similar similarities.</p><blockquote>similarity_new → Late chunking gives → 0.849546</blockquote><blockquote>similarity_trad → Normal Chunking → 0.84862185</blockquote><pre>similarity_new(&quot;Berlin&quot;, &quot;Berlin is the capital and largest city of Germany, both by area and by population.&quot;): 0.849546<br>similarity_trad(&quot;Berlin&quot;, &quot;Berlin is the capital and largest city of Germany, both by area and by population.&quot;): 0.84862185</pre><p>However, in the second sentence, “its more than 3.85 million inhabitants … ” refers to Berlin indirectly without directly mentioning it. In this case, with the late chunking approach, the similarity is ~82, whereas for the traditional chunking approach, the similarity drops to ~ 70.</p><pre>similarity_new(&quot;Berlin&quot;, &quot; Its more than 3.85 million inhabitants make it the European Union&#39;s most populous city, as measured by population within city limits.&quot;): 0.82489026<br>similarity_trad(&quot;Berlin&quot;, &quot; Its more than 3.85 million inhabitants make it the European Union&#39;s most populous city, as measured by population within city limits.&quot;): 0.7084338</pre><p>Similarly, in the third sentence, which refers to Berlin as “this city,” the similarity is high for the late chunking approach (0.84) but substantially lower for the traditional chunking approach (0.75).</p><pre>similarity_new(&quot;Berlin&quot;, &quot; The city is also one of the states of Germany, and is the third smallest state in the country in terms of area.&quot;): 0.84980094<br>similarity_trad(&quot;Berlin&quot;, &quot; The city is also one of the states of Germany, and is the third smallest state in the country in terms of area.&quot;): 0.7534553</pre><p>Now, this is a simple example, but if the chunks are much larger, there will be a significant loss of information in a naive chunking approach compared to the late chunking approach they propose. Another point to mention is that late chunking is bidirectional. If certain information precedes a specific chunk, it can still preserve that information. Since it’s bidirectional, looking at the entire document during embedding, a chunk will still retain information related to it, regardless of whether it’s before or after that chunk.</p><p>This bidirectionality makes it even more powerful, showing that long-context models are essential for both LLMs and these embeddings.</p><h3>Conclusion</h3><p>You know, after walking through all the details and examples in this article, I have to say that the late chunking approach for long-context embedding models is really fascinating and seems to hold a lot of promise.</p><p>The key insight here is that the traditional way of chunking up documents and then separately embedding each chunk can lead to a significant loss of context and important information. By instead taking the whole document, embedding it first to capture that broad context, and then chunking it up, you’re able to preserve so much more of the relevant details.</p><p>As the examples showed, when you’re dealing with references to entities like “Berlin” that might be made both directly and indirectly, the late chunking method is able to maintain a much stronger understanding of the meaning, compared to the traditional chunking and embedding pipeline. And the fact that it’s bidirectional, able to pull in context from before and after each chunk, just makes it even more powerful.</p><h3>Links</h3><ul><li><a href="https://colab.research.google.com/drive/15vNZb6AsU7byjYoaEtXuNu567JWNzXOz?usp=sharing#scrollTo=da0cec59a3ece76">Google Colab</a></li><li><a href="https://jina.ai/news/late-chunking-in-long-context-embedding-models/">Late Chunking in Long-Context Embedding Models</a></li><li><a href="https://jina.ai/news/what-late-chunking-really-is-and-what-its-not-part-ii/">What Late Chunking Really Is &amp; What It&#39;s Not: Part II</a></li><li><a href="https://weaviate.io/blog/late-chunking">Late Chunking: Balancing Precision and Cost in Long Context Retrieval | Weaviate</a></li><li><a href="https://www.anthropic.com/news/contextual-retrieval">Contextual Retrieval in AI Systems</a></li><li><a href="https://github.com/jina-ai/late-chunking?tab=readme-ov-file">GitHub - jina-ai/late-chunking: Code for explaining and evaluating late chunking (chunked pooling)</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=caf1c1209042" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/late-chunking-in-long-context-embedding-models-caf1c1209042">Stop Losing Context! How Late Chunking Can Enhance Your Retrieval Systems</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GraphRAG: Microsoft’s Open-Source Solution for Enhanced Document Understanding]]></title>
            <link>https://pub.towardsai.net/graphrag-microsofts-open-source-solution-for-enhanced-document-understanding-b42d05f5fec5?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/b42d05f5fec5</guid>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[graph]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Fri, 01 Nov 2024 20:02:18 GMT</pubDate>
            <atom:updated>2024-11-22T12:30:48.715Z</atom:updated>
            <content:encoded><![CDATA[<h3>Stop Losing Context! How Late Chunking Can Enhance Your Retrieval Systems</h3><p><a href="https://pub.towardsai.net/late-chunking-in-long-context-embedding-models-caf1c1209042">Stop Losing Context! How Late Chunking Can Enhance Your Retrieval Systems</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ocprwBCYr-Vt9AHAhMaZuA.png" /><figcaption><a href="https://www.microsoft.com/en-us/research/blog/graphrag-new-tool-for-complex-data-discovery-now-on-github/">source</a></figcaption></figure><p>I kept seeing posts on Reddit about GraphRAG, but it wasn’t until about a month ago that I finally decided to try it out. After spending some time experimenting with it, I can say it’s impressive but also pretty costly if you’re using the OpenAI API. Running tests on the sample book they provide in the documentation ran me about $7, so while the performance and organization it offers are solid, it’s not exactly budget-friendly.</p><p>If you’re new to RAG systems, I’d recommend checking out some introductory articles</p><ul><li><a href="https://pub.towardsai.net/anthropics-new-rag-approach-e0c24a68893b">Anthropic’s New RAG Approach</a></li><li><a href="https://pub.towardsai.net/rag-from-scratch-66c5eff02482">RAG From Scratch</a></li></ul><p>Anyway, this an overview of how traditional rag system works</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*aBKnYfX6VPWxtGvw5vVXIw.png" /><figcaption>Image from the author</figcaption></figure><p>For those already familiar with RAG, you’ve probably run into the same headaches I have:</p><ul><li>Context gets lost between chunks of text</li><li>Performance tanks as your document collection grows</li><li>Integrating external knowledge feels like trying to solve a Rubik’s cube blindfolded</li></ul><h3><strong>How GraphRAG Works</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*1r3_zcQg9ypH68E9uHkTPw.png" /><figcaption>Imag from the author</figcaption></figure><p>GraphRAG is an enhanced version of traditional RAG that operates in two main phases:</p><h4>Indexing Phase:</h4><ul><li>Starts with source documents that are <strong>chunked</strong> into smaller sub-documents (similar to traditional RAG)</li><li>Performs two parallel extractions</li></ul><ol><li><strong>Entity extraction</strong>: Identifies entities like people, places, companies</li><li><strong>Relationship extraction</strong>: Finds connections between entities across different chunks</li></ol><ul><li>Creates a<strong> knowledge graph</strong> where nodes represent entities and edges represent their relationships</li><li>Builds <strong>communities</strong> by identifying closely related entities</li><li>Generates <strong>hierarchical summaries</strong> across different community levels (three levels)</li><li>Uses a reduce-map approach to create summaries by combining chunks progressively until achieving a holistic overview</li></ul><h4>Query Phase:</h4><ul><li>Takes in the user <strong>query</strong></li><li>Selects the appropriate <strong>community level</strong> based on desired detail</li><li>Performs <strong>retrieval</strong> at the <strong>community level </strong>(instead of chunk level like in traditional RAG)</li><li>Examines community summaries to <strong>generate partial responses</strong></li><li><strong>Combines</strong> <strong>partial responses</strong> from multiple relevant communities into a final comprehensive answer</li></ul><p>The key innovation of GraphRAG is that it structures information into a graph-based format and uses community detection to create more contextually aware responses. However, <strong>traditional RAG systems still have their place, particularly when considering the computational cost of running GraphRAG</strong>.</p><h3>Setting Up GraphRAG</h3><blockquote>⚠️ Quick heads-up: This experiment runs on GPT-4’s API, which isn’t cheap. My test run cost around $7 using the GPT-4 model.</blockquote><p><strong>If you prefer test it on local LLMs using ollama check this video:</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fg21royNJ4fw%3Fstart%3D371%26feature%3Doembed%26start%3D371&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dg21royNJ4fw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fg21royNJ4fw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/1b70f06f8606325ad9476dc04f5b6870/href">https://medium.com/media/1b70f06f8606325ad9476dc04f5b6870/href</a></iframe><p>Let’s now walk through the setup process:</p><h4>Environment Setup</h4><p>First, create a virtual environment:</p><pre>conda create -n GraphRAG<br>conda activate GraphRAG</pre><p>Install the GraphRAG package:</p><pre>pip install graphrag</pre><h4>Directory Structure</h4><p>GraphRAG requires a specific directory structure for optimal operation:<br>- Create a working directory<br>- Inside it, create a <em>ragtest/input</em> folder structure<br>- Place your source documents in the input folder in the folder input</p><p>In this artciel we will work on the provided book, download it in the input folder using this command:</p><pre>% curl https://www.gutenberg.org/cache/epub/24022/pg24022.txt &gt; ./ragtest/input/book.txt</pre><h4>Configuration</h4><p>Initialize your workspace with:</p><pre>python -m graphrag.index --init --root ./target</pre><p>This creates necessary configuration files, including <strong>settings.yml</strong> where you’ll need to:<br>- Set your OpenAI API key<br>- Configure model settings (defaults include GPT-4 for processing and OpenAI embeddings)<br>- Adjust chunk size (default: 300 tokens) and overlap (default: 100 tokens) if needed</p><h4>Building the Knowledge Graph</h4><p>Run the indexing process:</p><pre>python -m graphrag.index --init --root ./target</pre><h4>Querying Your Graph</h4><p>GraphRAG offers two primary query methods:</p><p><strong>Global Queries</strong></p><pre>python -m graphrag.query --root ./target --method global &quot;what are the top themes in this story&quot;</pre><p>Ideal for broad questions about themes and overall content understanding.</p><p><strong>Local Queries</strong></p><pre>python -m graphrag.query --root ./target --method local &quot;what are the top themes in this story&quot;</pre><p>Perfect for specific questions about entities or relationships within the document.</p><h3>The Cost Factor: Is It Worth It?</h3><p>Let’s talk numbers. In my testing with the sample book, GraphRAG made:</p><ul><li>~570 GPT-4 API calls</li><li>About 25 embedding requests</li><li>Processed over 1M tokens</li></ul><p>Total damage: About $7 per book.</p><h3>Ressources</h3><p><a href="https://www.microsoft.com/en-us/research/blog/graphrag-new-tool-for-complex-data-discovery-now-on-github/">https://www.microsoft.com/en-us/research/blog/graphrag-new-tool-for-complex-data-discovery-now-on-github/</a></p><p><a href="https://github.com/microsoft/graphrag">GitHub - microsoft/graphrag: A modular graph-based Retrieval-Augmented Generation (RAG) system</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fg21royNJ4fw%3Fstart%3D371%26feature%3Doembed%26start%3D371&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dg21royNJ4fw&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fg21royNJ4fw%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/1b70f06f8606325ad9476dc04f5b6870/href">https://medium.com/media/1b70f06f8606325ad9476dc04f5b6870/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b42d05f5fec5" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/graphrag-microsofts-open-source-solution-for-enhanced-document-understanding-b42d05f5fec5">GraphRAG: Microsoft’s Open-Source Solution for Enhanced Document Understanding</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fine-Tune LLMs with Unsloth]]></title>
            <link>https://pub.towardsai.net/easiest-way-to-fine-tune-a-llm-3a62e5646c2d?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a62e5646c2d</guid>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[unsloth]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Mon, 28 Oct 2024 16:02:15 GMT</pubDate>
            <atom:updated>2024-10-28T19:53:35.543Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jVA-qAM7rWi14NHUqFgvFA.png" /><figcaption><a href="https://unsloth.ai/">unsloth</a></figcaption></figure><h3>Why Fine-Tune When We Have RAG?</h3><p>It’s a question I see a lot — with RAG (Retrieval-Augmented Generation) becoming increasingly popular, why bother with fine-tuning at all? While RAG is fantastic for many use cases, fine-tuning still has its place in the ML toolkit.</p><p>Here’s why: Fine-tuning allows you to fundamentally alter how your model “thinks” about specific domains. While RAG provides context at inference time, fine-tuning builds domain expertise directly into the model’s weights. This is particularly powerful when you need:</p><ul><li>Consistent domain-specific behavior</li><li>Faster inference (no need to search through external documents)</li><li>Specialized knowledge that’s difficult to capture in reference documents</li></ul><p>Plus, there’s a compelling cost argument: You can fine-tune smaller models for specific tasks and achieve performance comparable to much larger models at a fraction of the hosting cost.</p><p>I found this discussion on Reddit great. Have a look!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/778/1*MB5MCDWRfjwowOrmDlvpfA.png" /><figcaption><a href="https://www.reddit.com/r/MachineLearning/comments/1b2vtc9/d_who_still_uses_finetuning/">reddit</a></figcaption></figure><h3>Enter Unsloth: Making Fine-Tuning Accessible</h3><p>Training times have always been one of the biggest barriers to fine-tuning. That’s where Unsloth comes in — a new optimization framework that claims to make LLM training up to 30x faster.</p><p>The secret to Unsloth’s efficiency lies in deep optimization. While PyTorch and Transformers are built for flexibility across different architectures, Unsloth takes a more focused approach. It combines techniques like QLoRA and Triton with architecture-specific optimizations to squeeze maximum performance out of the training process.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CoRfezRlq7yfRn37SzU2aA.png" /><figcaption><a href="https://unsloth.ai/">unsloth</a></figcaption></figure><h3>Hands-on: Fine-Tuning for SQL Generation</h3><p>Let’s put this into practice by fine-tuning a model to generate SQL queries. We’ll use Llama-3.2–3B, a 3-billion parameter model that strikes a good balance between capability and resource requirements.</p><p>First, it’s important to find a good dataset to fine-tune the model, and the reason why finding the right dataset is so crucial is that when you train a small language model with data relevant to the task at hand, it can actually outperform larger models. What we aim to do is create a small, fast LLM that generates SQL queries based on table data.</p><p>One of the most significant datasets for this purpose is called Synthetic Text to SQL, which contains over 105,000 records divided into columns of prompt SQL content, complexity, and more.<br>Here is the link to the dataset:<br><a href="https://huggingface.co/datasets/gretelai/synthetic_text_to_sql">Synthetic Text to SQL</a></p><h4>Setting Up the Environment</h4><p>First, let’s install the necessary packages. We’ll need to manage our PyTorch installation carefully:</p><pre>%%capture<br>!pip install pip3-autoremove<br>!pip-autoremove torch torchvision torchaudio -y<br>!pip install &quot;torch==2.4.0&quot; &quot;xformers==0.0.27.post2&quot; triton torchvision torchaudio<br>!pip install &quot;unsloth[kaggle-new] @ git+https://github.com/unslothai/unsloth.git&quot;<br>!pip install datasets</pre><h4>Loading the Model</h4><p>Now we’ll load our base model using Unsloth’s optimized loader:</p><pre>from unsloth import FastLanguageModel<br>import torch<br>max_seq_length = 2048 # Choose any! We auto support RoPE Scaling internally!<br>dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+<br>load_in_4bit = True # Use 4bit quantization to reduce memory usage. Can be False.<br><br><br>model, tokenizer = FastLanguageModel.from_pretrained(<br>    model_name = &quot;unsloth/Llama-3.2-3B-bnb-4bit&quot;,<br>    max_seq_length = max_seq_length,<br>    dtype = dtype,<br>    load_in_4bit = load_in_4bit,<br>)</pre><h4>Setting Up PEFT</h4><p>We’ll load the PEFT (Parameter-Efficient Fine-Tuning) model, which uses LoRA (Low-Rank Adaptation) adapters. If you’re not familiar with these terms, don’t worry. LoRA adapters allow us to update only 1–10% of the model’s parameters during fine-tuning. Without them, we’d need to retrain the entire model, which would be significantly more time-consuming, computationally intensive, and expensive. Unsloth provides these recommended settings for optimal performance. While we’ll use their default configuration for this tutorial, feel free to explore and adjust these parameters based on your needs.</p><pre>model = FastLanguageModel.get_peft_model(<br>    model,<br>    r = 16, # Choose any number &gt; 0 ! Suggested 8, 16, 32, 64, 128<br>    target_modules = [&quot;q_proj&quot;, &quot;k_proj&quot;, &quot;v_proj&quot;, &quot;o_proj&quot;,<br>                      &quot;gate_proj&quot;, &quot;up_proj&quot;, &quot;down_proj&quot;,],<br>    lora_alpha = 16,<br>    lora_dropout = 0, # Supports any, but = 0 is optimized<br>    bias = &quot;none&quot;,    # Supports any, but = &quot;none&quot; is optimized<br>    use_gradient_checkpointing = &quot;unsloth&quot;, # 4x longer contexts auto supported!<br>    random_state = 3407,<br>    use_rslora = False,  # We support rank stabilized LoRA<br>    loftq_config = None, # And LoftQ<br>)</pre><h4>Data</h4><p>Now, this is where things can get a little bit tricky depending on what data set you’re using. The each data set comes different from each other, but they’re each formatted in the same way such that the large language model can understand it. Llama3.2 uses alpaca prompts, which look like this.</p><pre>Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.<br><br>### Instruction:<br>[The task or question you want the model to perform/answer]<br><br>### Input:<br>[Additional context or information needed to complete the task. This can be empty if the instruction is self-contained]<br><br>### Response:<br>[The expected output or answer you want the model to learn]</pre><p>For our SQL database project, we’re specifically interested in three components:</p><ol><li>The SQL query prompt</li><li>The generated SQL code</li><li>The explanation of the code</li></ol><pre>from datasets import Dataset, load_dataset<br><br># Define the prompt template with variables matching the loop content<br>alpaca_prompt = &quot;&quot;&quot;Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.<br>### Instruction:<br>{instruction}<br>### Input:<br>{input}<br>### Response:<br>{response}&quot;&quot;&quot;<br><br># Set the EOS token (assuming the tokenizer is already defined)<br>EOS_TOKEN = tokenizer.eos_token<br><br># Formatting function to apply the prompt template to the dataset<br>def formatting_prompts_func(examples):<br>    company_databases = examples[&quot;sql_context&quot;]<br>    prompts = examples[&quot;sql_prompt&quot;]<br>    sqls = examples[&quot;sql&quot;]<br>    explanations = examples[&quot;sql_explanation&quot;]<br>    texts = []<br>    for company_database, prompt, sql, explanation in zip(company_databases, prompts, sqls, explanations):<br>        # Substitute the correct placeholders<br>        text = alpaca_prompt.format(<br>            instruction=prompt,<br>            input=company_database,<br>            response=sql + &quot; &quot; + explanation<br>        ) + EOS_TOKEN<br>        texts.append(text)<br>    return {&quot;text&quot;: texts}  # Ensure the formatted text is returned as a &quot;text&quot; field<br><br># Load dataset and map formatting function to add prompts<br>ds = load_dataset(&quot;gretelai/synthetic_text_to_sql&quot;)<br>formatted_ds = ds.map(formatting_prompts_func, batched=True)  # Apply formatting<br><br># Select the &#39;train&#39; split from the formatted dataset<br>train_dataset = formatted_ds[&#39;train&#39;]</pre><h3>Training Configuration</h3><p>There are a lot of parameters to use, and all that can be described. For example, have the maximum number of steps, which tells us how many training steps to perform. Seed is a random number generator. We used to be able to reproduce results, and warmup steps gradually increased the learning rate over time.</p><pre>from transformers import TrainingArguments<br>from unsloth import is_bfloat16_supported<br>from trl import SFTTrainer<br><br># Trainer setup<br>trainer = SFTTrainer(<br>    model=model,  # Ensure model is defined<br>    tokenizer=tokenizer,  # Ensure tokenizer is defined<br>    train_dataset=train_dataset,  # Use the &#39;train&#39; split from formatted_ds<br>    dataset_text_field=&quot;text&quot;,  # This is the field we created with formatted prompts<br>    max_seq_length=max_seq_length,  # Ensure max_seq_length is defined<br>    dataset_num_proc=2,<br>    packing=False,  # Can make training 5x faster for short sequences.<br>    args=TrainingArguments(<br>        per_device_train_batch_size=2,<br>        gradient_accumulation_steps=4,<br>        warmup_steps=5,<br>        max_steps=60,<br>        learning_rate=2e-4,<br>        fp16=not is_bfloat16_supported(),<br>        bf16=is_bfloat16_supported(),<br>        logging_steps=1,<br>        optim=&quot;adamw_8bit&quot;,<br>        weight_decay=0.01,<br>        lr_scheduler_type=&quot;linear&quot;,<br>        seed=3407,<br>        output_dir=&quot;outputs&quot;,<br>        report_to=&quot;none&quot;,  # Disable WANDB logging<br>    )<br>)</pre><p>So now that we have everything set up, let’s run it. And that’s it.</p><pre>trainer_stats = trainer.train()</pre><h3>Resources</h3><p>Code on colab: <a href="https://colab.research.google.com/drive/1BHuj-8mA8lvxJQyQsCyp-7vlGkXuRxKY?usp=sharing">https://colab.research.google.com/drive/1BHuj-8mA8lvxJQyQsCyp-7vlGkXuRxKY?usp=sharing</a></p><p><a href="https://huggingface.co/unsloth">unsloth (Unsloth AI)</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=reddit&amp;url=https%3A//www.reddit.com/r/LocalLLaMA/comments/1ar7e4m/unsloth_whats_the_catch_seems_too_good_to_be_true/&amp;image=" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/fd5b109e93ea5e0224ebbe09f1c2712d/href">https://medium.com/media/fd5b109e93ea5e0224ebbe09f1c2712d/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a62e5646c2d" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/easiest-way-to-fine-tune-a-llm-3a62e5646c2d">Fine-Tune LLMs with Unsloth</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[RAG From Scratch]]></title>
            <link>https://pub.towardsai.net/rag-from-scratch-66c5eff02482?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/66c5eff02482</guid>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[chatgpt]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Tue, 01 Oct 2024 07:57:01 GMT</pubDate>
            <atom:updated>2024-10-03T12:55:29.763Z</atom:updated>
            <content:encoded><![CDATA[<p>I’m working as a machine learning engineer, and I frequently use Claude or ChatGPT to help me write code. However, in some cases, the model starts to repeat itself or hallucinate, especially during complex or lengthy tasks. This can happen due to limitations in the model’s context window or the nature of the prompt. When this occurs, I typically write pseudo-code to guide the model along with the prompt, and it works well in most cases. The “context window” refers to the maximum amount of text (measured in tokens) that the model can process in a single input. Exceeding this limit can lead to issues like information loss or confusion in longer tasks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/1*4YDRVRe29Jq8T_Xm_H3gEg.jpeg" /><figcaption><a href="https://www.youtube.com/watch?v=sVcwVQRHIc8&amp;t=6692s">Youtube</a></figcaption></figure><p>In some cases, when I feel the model starts to “forget” the information I provided, I use a simple trick: I give it the necessary information in chunks to avoid exceeding the context window. This strategy helps the model retain important details throughout the interaction. This is actually the core idea behind Retrieval-Augmented Generation (RAG) systems, with some adjustments, which will be covered in the upcoming sections.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*VrUCrOF-E2o-3-e23ah-EQ.png" /><figcaption>Image from the author</figcaption></figure><h3>Indexing</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*9OFXTyjXJwAOeqpe87ubwA.png" /><figcaption>Image from the author</figcaption></figure><ul><li><strong>Documents</strong>: This is where we start with our collection of information sources, such as books, articles, or any other text-based knowledge.</li><li><strong>Chunking</strong>: In this step, we break down the large documents into smaller, manageable pieces. This makes it easier to process and retrieve specific information later.</li><li><strong>Embedding</strong>: Here, we convert each chunk of text into a numerical representation that captures its meaning. This allows computers to understand and compare the content efficiently.</li><li><strong>Index</strong>: Finally, we store these numerical representations in a special structure that allows for quick and efficient searching.</li></ul><h4>Chunking</h4><p>I believe all stages are clear except for the chunking part. How do we split documents?</p><p>Many methods have been introduced for this purpose. Some of them are static, such as Fixed-Length Splitting, which involves dividing the text into chunks of a predetermined number of tokens or characters. Others are more semantic.</p><p>For a more detailed explanation, please visit this article: <a href="https://medium.com/@anuragmishra_27746/five-levels-of-chunking-strategies-in-rag-notes-from-gregs-video-7b735895694d">Five Levels of Chunking Strategies in RAG</a>.</p><h3>Retrival</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*obMLL8QITHJN08rM8x5kYA.png" /><figcaption>Image from the author</figcaption></figure><p>After splitting our document into chunks, embedding, and indexing them, we won’t feed all chunks to the LLMs alongside the query. Instead, we will select the top k most relevant chunks based on the user’s question. To elaborate, we will embed the query or question and compare it with our embedded chunks to identify the k most relevant ones.</p><h3>Generation</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*9hjZE36dvTivbbaXFWP_IA.png" /><figcaption>Image from the author</figcaption></figure><p>This is nearly the final part of our RAG pipeline. We will now take the query with the most relevant documents and pass them as a prompt to the LLM, which will return the final answer.</p><p>This was the most basic RAG pipeline, but it comes with what is basically mentioned in the tweet image: RAG is used to answer user queries about private data when the query itself isn’t ambiguous. I mean, it can be phrased in a very different way than the documents. So the problem might be that the model can’t understand our task or question, which means we need to translate the query.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/592/1*ZEp6lhl9y2ozwxLPv2bEAg.png" /><figcaption><a href="https://x.com/abacaj/status/1652011519863926786?s=20">twitter</a></figcaption></figure><h3>Query translation</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*dmC--BjDnUEkrSsXQ62MWw.png" /><figcaption><a href="https://www.langchain.com/">LangChain</a></figcaption></figure><h4>Multi-Query Prompt</h4><p>We start with an original question and rephrase it into several different queries. Next, we look at the relevant pieces of information for each query. Finally, we can use different methods to combine these queries and their results before sending them, along with the original question, to the model.</p><h4>‫‪RAG-fusion‬‬</h4><p>The RAG-fusion technique utilizes a method known as Reciprocal Rank Fusion (RRF). Understanding RRF is crucial, especially since we’ll revisit it when discussing Re-ranking later on.</p><p>When we employ Multi-Query strategies, we generate multiple queries and collect the top relevant chunks of information for each. After gathering these results, we review them to eliminate any duplicates, ensuring we only work with unique entries.</p><p>Now, let’s consider a situation where two queries return chunks with the same score. For instance, if both queries produce a chunk rated at 0.55, we face the challenge of determining their order when we combine them. This is where RRF becomes beneficial.</p><p>RRF helps us rank these chunks based on their relevance from each query, giving us a way to decide which chunk should take precedence in our final list. By applying RRF, we can effectively merge the results while prioritizing the most relevant chunks, leading to a more efficient and accurate representation of the information we need.</p><p>To explore the formula and see some examples, check these articles:</p><ul><li><a href="https://medium.com/@kiran.phd.0102/rag-fusion-revolution-a-paradigm-shift-in-generative-ai-2349b9f81c66">RAG Fusion Revolution — A Paradigm Shift in Generative AI</a></li><li><a href="https://medium.com/@devalshah1619/mathematical-intuition-behind-reciprocal-rank-fusion-rrf-explained-in-2-mins-002df0cc5e2a">Reciprocal Rank Fusion (RRF) explained in 4 mins.</a></li></ul><h4>Decomposition</h4><p>Decomposition Query is a method where we break down a complex task in a query into smaller, simpler, and easier-to-solve subtasks or parts. Afterward, we merge these answers, either by solving them recursively or addressing them individually.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*jJuH6VzgkYykuMp2rCfG9g.png" /><figcaption>Image from the author</figcaption></figure><h4><strong>Recursively Answer</strong></h4><p>This method involves breaking down a complex query into a series of simpler, smaller questions. When an LLM (Large Language Model) answers the first question, we take both the question and its answer as the context for the next question. We continue this process with the second, third, and so on until all the smaller questions are answered. (In some cases, we can stop here.) In other cases, we take all these questions and their answers as the context to address the original main query. If we do this final step, it becomes the <strong>Answer Individually</strong> method.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*1yrEZDx9PxchbhBgXh3uKg.png" /><figcaption>Image from the author</figcaption></figure><h3>Routing</h3><p>Building a large RAG application often won’t just focus on a single fixed task or work with only one uploaded file. For example, if you have a high school student studying for exams, you might create an RAG application that helps them across all subjects, not just one. However, the application needs a <strong>router</strong> to determine the subject of each query. For example, if the student asks a physics question, the router would direct the RAG to search in the physics textbooks the student has uploaded, ignoring other subjects. Based on the user’s query, the application will choose the most suitable route or chain to get the best result.</p><p>Now, let’s talk about the methods we can use for routing:</p><h4>Using a Custom Function:</h4><p>Simply create custom chains for each subject. For example, if the subject is mathematics, you can design a chain that tells the model it’s a math teacher and should answer the question based on its knowledge of math. Similarly, you’d have another chain for physics, and so on. A simple function would check the query for specific words (e.g., “math”) and select the corresponding chain for that subject.</p><h4>Machine Learning Classifier:</h4><p>If you have a lot of questions from different subjects like physics, math, etc., and you want the system to determine which subject is being asked about, you can train a classifier. This classifier will categorize the query into the correct subject, and once classified, the system can route the query to the relevant textbooks or chain associated with that subject.</p><h4>Semantic Similarity:</h4><p>More advanced functions can be used beyond simple keyword matching. For example, you could create an embedding (a numerical representation) for each chain. When a query comes in, its embedding is compared to the embeddings of each chain, and the chain with the closest match is selected.</p><h4>Hybrid Approach:</h4><p>As the name suggests, you can use a hybrid approach that combines multiple methods mentioned above to achieve better and more accurate routing.</p><p>The importance of <strong>routing</strong> lies in ensuring that the context provided to the LLM is truly relevant to the question asked. This prevents the model from using unrelated contexts from a different subject. Effective routing also improves the indexing process by ensuring that we are searching in the correct chunks, saving time and leading to better results.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*X7mhcx48fH1OWGbqVMo0mQ.png" /><figcaption>Image from the author</figcaption></figure><h3>Query‬‬ ‫‪Construction‬‬‫‪</h3><p>When constructing a query, most of the files in the data we’re using likely have <strong>metadata</strong>, right? So what is metadata? <strong>Metadata</strong> is simply <strong>data about data</strong>.</p><p>For example, if we have a video, the <strong>data</strong> would be the content of the video itself. However the <strong>metadata</strong> could be various things like the <strong>source</strong> of the video, its production date, duration, or other details.</p><p>Now, if we have a query like:</p><p><strong>Which video is longer, A or B?</strong></p><p>The first solution might be that the model looks at the number of words in the transcript of the first video, then compares it to the number of words in the second video’s transcript. The one with more words would be longer, right?</p><p>Not exactly. One video could have more silence than the other, so even if it has fewer words, it could still be longer. But, even if the video with more words is longer, what’s the faster way to get the answer? Is it for the model to analyze the entire video content, or just to grab the duration from the <strong>metadata</strong> and compare the lengths?</p><p>So, what do you think about using <strong>metadata</strong> to improve <strong>chunking</strong>? It’s possible that the query written by the user could be answered directly through the <strong>metadata</strong>, and from that, we can provide an answer much more easily.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*nxDX29VDXUrjADN3TMpd1g.png" /><figcaption>Image from the author</figcaption></figure><p>That’s it for this article I may share another one about more advanced concepts in the upcoming days!</p><h3>Resources:</h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FsVcwVQRHIc8%3Fstart%3D6692&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DsVcwVQRHIc8&amp;image=http%3A%2F%2Fi.ytimg.com%2Fvi%2FsVcwVQRHIc8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/2c1023cdc3919167c7684c19481f321f/href">https://medium.com/media/2c1023cdc3919167c7684c19481f321f/href</a></iframe><ul><li><a href="https://medium.com/@tejpal.abhyuday/retrieval-augmented-generation-rag-from-basics-to-advanced-a2b068fd576c">Retrieval-Augmented Generation (RAG) from basics to advanced</a></li><li><a href="https://www.langchain.com/">LangChain: Observe, Evaluate, and Deploy Reliable AI Agents</a></li><li><a href="https://www.freecodecamp.org/">freeCodeCamp.org</a></li><li><a href="https://medium.com/@krtarunsingh/advanced-rag-techniques-unlocking-the-next-level-040c205b95bc">Advanced RAG Techniques: Unlocking the Next Level</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66c5eff02482" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/rag-from-scratch-66c5eff02482">RAG From Scratch</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Anthropic’s New RAG Approach]]></title>
            <link>https://pub.towardsai.net/anthropics-new-rag-approach-e0c24a68893b?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/e0c24a68893b</guid>
            <category><![CDATA[claude]]></category>
            <category><![CDATA[langchain]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[gpt]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Sun, 29 Sep 2024 13:43:47 GMT</pubDate>
            <atom:updated>2024-11-03T13:14:36.732Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>If you want a more detailed article about RAG from scratch or if you are new to RAG, feel free to check this article first:</strong></p><p><a href="https://pub.towardsai.net/rag-from-scratch-66c5eff02482">RAG From Scratch</a></p><h3>The Rise of LLMs</h3><p>LLMs are super-powerful tools. I remembered the first time ChatGPT was released, I was saying hell no, I will lose my job (before even getting one), but… then I saw it struggling to pick the right CUDA version for Ubuntu just like the rest of us :)</p><p>Anyway, if you ask someone who doesn’t know much about AI about ChatGPT, they might say it’s just retrieving answers from the internet like a semantic search. Well, almost, but it’s a bit more complex. These models aren’t retrieving the next word from a database you can instantly point to; they’ve compressed vast amounts of information into their weights, and they literally predict every single word (sub-word).</p><p>Even though these LLMs are very powerful in chatting and answering questions, such as writing APIs using Flask or preparing unit tests for us, they struggle in specific domains.</p><h3>What About Fine-Tuning Your Own LLM?</h3><p>While Large Language Models (LLMs) excel at general knowledge tasks, they often underperform in specialized domains. Their broad capabilities come at the cost of domain-specific expertise, akin to being generalists rather than specialists.</p><p>This limitation is where fine-tuning becomes relevant. Fine-tuning adapts an LLM to a specific domain or task, enhancing its performance in targeted areas. However, the process is considerably more complex than simply exposing the model to domain-specific data.</p><h3>The Challenges of Fine-Tuning</h3><p>Implementing LLM fine-tuning presents significant challenges. Organizations typically have two options:</p><ol><li>Fine-tuning an open-source model</li><li>Utilizing APIs from providers offering fine-tuning services for proprietary models</li></ol><p>Regardless of the chosen path, financial considerations are paramount. Costs may include API usage fees or expenses related to cloud GPU resources for training. Even with adequate financial resources, organizations may face a shortage of high-quality, relevant data necessary for effective fine-tuning.</p><p><strong>Data sensitivity introduces additional complexities.</strong> Organizations must ensure proper attribution and traceability of data sources, citing an LLM in a research paper might raise a few eyebrows. Moreover, protecting proprietary information from potential exposure to LLM providers is a critical concern.</p><p>While fine-tuning LLMs is a trending topic in the AI community, it’s not a decision to be made lightly. The process requires careful consideration of resources, data quality, and potential risks much like adopting a high-maintenance technology stack.</p><h3>Retrieval-Augmented Generation (RAG)</h3><p>Retrieval-Augmented Generation (RAG) offers a potential solution to these challenges. RAG connects an LLM directly to an organization’s knowledge base, enabling relevant data retrieval without the need for model retraining. This approach enhances performance in specific domains while maintaining data security and reducing the complexities associated with fine-tuning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*v4S_C6p1X3z61Gq7Muq1IA.png" /><figcaption><a href="https://www.youtube.com/watch?v=tmiBae2goJM">Prompt Engineering</a></figcaption></figure><h3>How RAG Systems Work</h3><p>Retrieval-Augmented Generation (RAG) systems consist of two main components:</p><h4>1. Knowledge Base Creation</h4><p>This is the preparation phase where your documents are processed and stored:</p><ul><li><strong>Document Chunking:</strong> You take your documents and break them down into smaller, manageable sub-documents or chunks.</li><li><strong>Embedding Computation:</strong> For each of these chunks, you compute embeddings. These are numerical representations that capture the semantic meaning of the text.</li><li><strong>Vector Store:</strong> The computed embeddings are then stored in a vector store, which allows for efficient similarity searches later on.</li></ul><h4>2. Generation Part</h4><p>This is the runtime or inference phase, where the system responds to user queries:</p><ul><li><strong>Query Processing:</strong> When a user asks a question, the system computes an embedding for that query.</li><li><strong>Retrieval:</strong> The system then retrieves the most relevant chunks from the vector store based on the similarity between the query embedding and the stored chunk embeddings.</li><li><strong>LLM Integration:</strong> The retrieved chunks, along with the original query, are fed into a Large Language Model (LLM).</li><li><strong>Response Generation: </strong>The LLM generates a response based on the query and the context provided by the retrieved chunks.</li></ul><h3>Enhancing Retrieval Accuracy</h3><p>While this technique is great for semantic similarity, it can still have failure points. To improve accuracy, many systems combine this semantic search with traditional keyword-based search mechanisms:</p><ul><li><strong>BM25 Integration:</strong> One such technique is BM25 (Best Matching 25), which plays a critical role when the user query and the database involve specific keywords.</li><li><strong>Hybrid Approach:</strong> By combining semantic search with keyword-based methods, RAG systems can provide more robust and accurate results, especially in scenarios where exact term matching is important.</li></ul><p>This hybrid approach allows RAG systems to leverage the strengths of both semantic understanding and traditional information retrieval techniques, resulting in more reliable and context-aware responses. As reported by Anthropic, this method improves results by ~ 1%.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/539/1*TZVm0ZFOu6fG-yO-QAIMWQ.png" /><figcaption><a href="https://www.anthropic.com/news/contextual-retrieval">source</a></figcaption></figure><h4>BM25:</h4><p>Sometimes, the smart part misses important exact matches. That’s where BM25 comes in. It’s like a super-powered “Ctrl+F” (find function) that looks for exact words or phrases.</p><p><em>Examples Where BM25 Shines</em></p><ol><li>Error Codes: Finding “Error XYZ-123” exactly.</li><li>Product Numbers: Locating “Model AB-9000” precisely.</li><li>Specific Terms: Finding “mitochondria” in biology texts.</li></ol><h3>RECAP BEFORE MOVING ON</h3><p>A standard RAG system works by first breaking a large collection of documents into smaller pieces. These pieces are transformed into numbers (called embeddings) to capture their meaning, and they are stored in a special database for fast searching. When you ask a question, the system looks through these stored pieces and picks the ones that seem most relevant using two methods: one based on word importance (TF-IDF) and another based on the embeddings. It then combines the best pieces and uses a smart model to generate a clear answer based on them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vzxuanXgVFkQZ_owExBJyA.png" /><figcaption><a href="https://www.anthropic.com/news/contextual-retrieval">source</a></figcaption></figure><h3>What’s wrong with that approach</h3><p>Here is a quick example of where a standard RAG system might fail:</p><blockquote><em>What were the long-term effects of Drug X in the 2023 clinical trial?</em></blockquote><p>A relevant chunk retrieved by the system might contain the text:</p><blockquote><em>Participants showed significant improvements after treatment.</em></blockquote><p>However, this chunk doesn’t specify which drug was used, whether it refers to the 2023 trial, or if the improvements were long-term. Without this additional context, the system cannot accurately answer the question, leading to a potentially misleading or incomplete response.</p><h3>Introducing Contextual Retrieval</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xAK-KwUVo1Dsm5uZ1d-SVg.png" /></figure><p>In practice, this is how it’s going to look like. You will take a single PDF file or a single document from your corpus, then convert that into chunks. After that, you take one chunk at a time, and run that chunk through a prompt like the one below, along with the original document.</p><pre>&lt;document&gt; <br>{{WHOLE_DOCUMENT}} <br>&lt;/document&gt; <br>Here is the chunk we want to situate within the whole document <br>&lt;chunk&gt; <br>{{CHUNK_CONTENT}} <br>&lt;/chunk&gt; <br>Please give a short succinct context to situate this chunk within the overall document for the purposes of improving search retrieval of the chunk. Answer only with the succinct context and nothing else</pre><p>This will generate contextual information for each chunk. You combine the given chunk with the relevant contextual information, and then you pass it through an embedding model. Those embeddings are going to be stored in a standard vector database. On the other hand, we also update the BM25 indexing. In this case, we’re using TF-IDF, which stands for Term Frequency Inverse Document Frequency. This is basically the keyword-based search mechanism. As a result, in each of the chunks, you are adding 50 to 100 tokens. I think you can already see some potential issues with this approach. One of them is that it’s going to add a lot of overhead, not only from the number of tokens you’re adding to each chunk, but also because each chunk goes through an LLM, which adds up to a lot of different tokens.</p><h4>Performance improvements</h4><blockquote>Contextual Embeddings reduced the top-20-chunk retrieval failure rate by 35% (5.7% → 3.7%).</blockquote><blockquote>Combining Contextual Embeddings and Contextual BM25 reduced the top-20-chunk retrieval failure rate by 49% (5.7% → 2.9%).</blockquote><h3>Reranking</h3><p>Retriever models, which are designed to extract chunks of information, are compact and efficient. However, they rely on basic extraction techniques, such as Euclidean distance or cosine similarity between vectors. This approach can lead to suboptimal results, as it prioritizes speed and volume of extractions over accuracy.</p><p>In contrast, reranker models are more substantial and slower, making them unsuitable for processing large extractions directly. Instead, they can be employed to rerank a smaller selection of chunks identified by the retriever.</p><p>The key distinction lies in the rerankers’ ability to perform cross-attention between the user query and each chunk. This enables them to uncover important relationships between the two texts that simpler similarity measures may overlook.</p><p>Learn more about rerankers here:</p><ul><li><a href="https://cohere.com/rerank">Rerank | Boost Enterprise Search and Retrieval | Cohere</a></li><li><a href="https://docs.voyageai.com/docs/reranker">Rerankers</a></li></ul><h3>Ressources</h3><ul><li><a href="https://www.anthropic.com/news/contextual-retrieval">Contextual Retrieval in AI Systems</a></li><li><a href="https://docs.voyageai.com/docs/reranker">Rerankers</a></li><li><a href="https://cohere.com/rerank">Rerank | Boost Enterprise Search and Retrieval | Cohere</a></li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FtmiBae2goJM%3Fstart%3D168&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DtmiBae2goJM&amp;image=http%3A%2F%2Fi.ytimg.com%2Fvi%2FtmiBae2goJM%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a5a53a3c4e196cd1077df0632ab1ae03/href">https://medium.com/media/a5a53a3c4e196cd1077df0632ab1ae03/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FsVcwVQRHIc8%3Fstart%3D6671%26feature%3Doembed%26start%3D6671&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DsVcwVQRHIc8&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FsVcwVQRHIc8%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/674ed4e966e2cf35f48cfb17169831a1/href">https://medium.com/media/674ed4e966e2cf35f48cfb17169831a1/href</a></iframe><h4>If you enjoyed this article, you might find these pieces valuable:</h4><ul><li><a href="https://pub.towardsai.net/rag-from-scratch-66c5eff02482">RAG From Scratch</a></li><li><a href="https://pub.towardsai.net/easiest-way-to-fine-tune-a-llm-3a62e5646c2d">Fine-Tune LLMs with Unsloth</a></li><li><a href="https://pub.towardsai.net/omniparser-explained-15da15d77fd7">How Can GPTs Interact with Computers? OmniParser Explained</a></li><li><a href="https://pub.towardsai.net/graphrag-microsofts-open-source-solution-for-enhanced-document-understanding-b42d05f5fec5">GraphRAG: Microsoft’s Open-Source Solution for Enhanced Document Understanding</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e0c24a68893b" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/anthropics-new-rag-approach-e0c24a68893b">Anthropic’s New RAG Approach</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forward-Forward Algorithm]]></title>
            <link>https://pub.towardsai.net/forward-forward-algorithm-ac24d0d9ffd?source=rss-541d7f6904a2------2</link>
            <guid isPermaLink="false">https://medium.com/p/ac24d0d9ffd</guid>
            <category><![CDATA[backpropagation]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[forward-forward-algorithm]]></category>
            <dc:creator><![CDATA[Barhoumi Mosbeh]]></dc:creator>
            <pubDate>Thu, 26 Jan 2023 16:38:50 GMT</pubDate>
            <atom:updated>2024-10-03T12:54:41.333Z</atom:updated>
            <content:encoded><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Geoffrey_Hinton">Geoffrey Hinton</a>, a renowned researcher in the field of artificial intelligence, recently published a <a href="https://www.cs.toronto.edu/~hinton/FFA13.pdf">paper</a> detailing a new method for training neural networks. This new approach, known as the Forward-Forward algorithm, is inspired by our understanding of neural activations in the brain. Instead of relying on the traditional forward and backward passes of backpropagation, this method utilizes two forward passes — one with positive, real data and the other with negative data. Each layer in the network has its own objective function, which is to have high “goodness” for positive data and low “goodness” for negative data. The paper aims to demonstrate that this method can be effective on small problems, and is worth further investigation.</p><h3>Introduction:</h3><p>Backpropagation is a widely-used algorithm for training neural networks. It uses the gradient descent optimization method to adjust the weights of the network in order to minimize a loss function. The algorithm works by computing the gradient of the loss function with respect to the weights of the network and then updating the weights in the opposite direction of the gradient. This process is repeated until the loss function reaches a minimum.</p><p>In this article, I will delve into the concept of backpropagation and its role in training artificial neural networks. I will then introduce you to Geoffrey Hinton’s latest contribution to the field, the Forward-Forward algorithm, and provide an in-depth understanding of its concept and implementation.</p><p><strong>What is backpropagation and what makes Geoffrey Hinton think about a new method to train neural networks?</strong></p><blockquote>1. I want to clarify that the content of this article is based on my own understanding and the idea of this new concept is not yet fully established.</blockquote><blockquote>2. I have to assume that you have at least an idea of how deep learning models work. If not please visit this <a href="http://introtodeeplearning.com/">link</a>.</blockquote><h3>What is backpropagation and what’s wrong with it?</h3><p>Backpropagation is a training algorithm used to train deep learning models. The basic idea behind backpropagation is to adjust the weights of the neurons in the network in such a way that the output of the network is closer to the desired output.</p><p>The backpropagation algorithm starts by feeding the input data into the network and then propagating the input forward through the layers of the network. As the input data moves through the layers of the network, it is transformed by the weights of the neurons in each layer, producing an output. Once the output is produced, the algorithm compares the output to the desired output and calculates the error between the two. This error is then propagated backward through the network, starting from the output layer and working backward through the hidden layers.</p><p>As the error is propagated backward, the weights of the neurons are adjusted in order to minimize the error. This process is repeated for many iterations until the error reaches an acceptable level. The backpropagation algorithm uses a technique called gradient descent to adjust the weights of the neurons in the network. Gradient descent is a mathematical method that helps to find the optimal weights of the neurons that minimize the error between the output and the desired output.</p><p>For more details, I highly recommend this great video:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FIlg3gGewQ5U%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIlg3gGewQ5U&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FIlg3gGewQ5U%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/fe5f90802ee53c2680a2531068e77dbe/href">https://medium.com/media/fe5f90802ee53c2680a2531068e77dbe/href</a></iframe><p><strong><em>It’s great, right! so what’s wrong with it?</em></strong></p><p>The main disadvantages of backpropagation include its implausibility as a model for how the brain learns, its lack of support from evidence in the visual system, and its inefficiency in handling sequences and real-time learning. It also requires a perfect model of the forward computation in order to compute the correct derivatives. Additionally, backpropagation can suffer from high variance when using reinforcement learning techniques, making it less efficient for large networks with many parameters. These limitations of backpropagation led to the development of alternative methods, such as the Forward-Forward Algorithm, which aims to overcome these limitations and can be used in cases where the precise details of the forward computation are unknown.</p><p><em>If you don’t understand that just ignore the last part and let’s move to the next step!</em></p><h3>Forward-forward algorithm:</h3><p>The concept of the Forward-Forward algorithm is easy to understand, especially if you have knowledge of GANs or reinforcement learning.</p><p>The Forward-Forward (FF) algorithm is a method for training neural networks that are inspired by the way the brain processes information. It replaces the traditional backpropagation method by using two forward passes, one with positive (real) data and the other with negative data, which can be generated by the network itself. The layers of the network have their own objective function, which is to have high goodness for positive data and low goodness for negative data. The FF algorithm is particularly useful in situations where the precise details of the forward computation are unknown, or when the network needs to process sequential data in real-time without stopping to propagate error derivatives. However, it is currently less efficient and generalizes less well compared to traditional backpropagation on some tasks.</p><h4>What do you mean by positive and negative data?</h4><p>In the context of the paper, positive data refers to real data, while negative data refers to fake or generated data. This negative data can be added manually or generated by the model itself. To provide clarity, I will provide an example of a <strong><em>supervised learning problem</em></strong>.</p><h4>The traditional method to train a neural network:</h4><p>The traditional method of training a 2 layer-dense neural network for image classification is by using backpropagation. This involves feeding data through the network, comparing the output to the desired label, calculating a loss function, taking the derivative of the loss with respect to the model’s parameters, and updating the weights to reduce the loss.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4NDYSAlQi-qwvSqGfH79yQ.jpeg" /><figcaption><strong><em>The traditional method to train a neural network</em></strong></figcaption></figure><h4>Good and Bad data:</h4><p>In FF, we take a different approach to training a 2 layer-dense neural network for image classification. Instead of using the traditional method of pushing data through the network, comparing the outcome to labels, and then using backpropagation to update the weights, we merge the labels and data into one vector, referred to as “good data”. We then generate “bad data” by combining the input images with incorrect labels. This method is demonstrated using the MNIST dataset of handwritten digits. To make things easy, we replace the first 10 pixels with a one-of-N representation of the label.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/680/1*zVmOT60WNqVsDhObePG6KA.jpeg" /><figcaption><strong>Good and bad data</strong></figcaption></figure><h4>Goodness term:</h4><p>The process of training a forward-forward algorithm is straightforward. To maximize the performance of the model on “good data” while minimizing it on “bad data”, the sum of squared activations in a layer is calculated. This is done within a single layer, so there is no need for backpropagation, just the use of the derivative of the function performed by the layer itself which is relatively simple.</p><h4>What are neural activities?</h4><p>In the context of neural networks, “<em>neural activities</em>” refers to the output or response of the neurons in a network. This can include things like the activation values of neurons, the output of a particular layer, or the overall output of the network. The term “neural activities” is used to describe the overall behavior or output of the network, and can be used to evaluate and optimize the performance of the network.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0t7Un85FSJPD24bUBQl5BA.png" /><figcaption><strong>Goodness</strong></figcaption></figure><h4>Positive response for positive data and negative for negative data:</h4><p>And now, we want each network layer to respond positively to the good data, meaning it will have high neural activity, and respond negatively to the bad data, resulting in low neural activity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b6cwWZjebvTEk8VYC37YUQ.jpeg" /><figcaption>Negative and positive data</figcaption></figure><h4>Normalization between layers:</h4><p>When chaining multiple layers, you want to avoid seeing high activations just because you pumped in high inputs from a very excited previous layer. So layer activations are normalized (divided by the norm of the activation vector) between layers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5PYnKfnqWEbbWFrlHGX9aQ.jpeg" /><figcaption>Data normalization</figcaption></figure><blockquote><em>I hope that by reading this article, you have gained a solid understanding of the forward-forward algorithm and its potential benefits for training neural networks. The Forward-Forward algorithm is a new learning procedure for neural networks that replaces the forward and backward passes of backpropagation with two forward passes, one with positive data and the other with negative data, which can be generated by the network itself. The main idea is to train the model with positive and negative data and to have high goodness for positive data and low goodness for negative data. I believe that this new algorithm will open new doors in the field of deep learning and that it will be worth considering for future projects.</em></blockquote><h3>Keras implementation of the Forward forward algorithm for image classification:</h3><h4>Library importation:</h4><pre>import tensorflow as tf<br>from tensorflow import keras<br>import numpy as np<br>import matplotlib.pyplot as plt<br>from sklearn.metrics import accuracy_score<br>import random<br>from tensorflow.compiler.tf2xla.python import xla</pre><h4>Loading the data:</h4><pre>(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()</pre><h4>FFDense custom layer:</h4><p>This code defines a custom dense layer for a forward-forward (FF) neural network. The layer inherits from the Keras Dense layer and applies a rectified linear unit (ReLU) activation function to the output. The layer also includes an implementation of the forward-forward algorithm, which is used to train the network. The forward-forward algorithm uses a custom loss function that compares the mean square value of the activations for positive and negative samples. The network optimizes this loss function by performing gradient calculations and optimization steps on the trainable weights of the dense layer. The loss and optimizer are passed as arguments to the layer. The code also applies normalization to the input before it is passed through the dense layer. This is done by dividing the input by its L2 norm. The number of training epochs and the threshold value for the loss function are also set as hyperparameters. The forward_forward() function takes the positive and negative inputs and performs the forward-forward algorithm to train the network.</p><pre>class FFDense(keras.layers.Layer):<br><br>    def __init__(<br>        self,<br>        units,<br>        optimizer,<br>        loss_metric,<br>        num_epochs=50,<br>        use_bias=True,<br>        kernel_initializer=&quot;glorot_uniform&quot;,<br>        bias_initializer=&quot;zeros&quot;,<br>        kernel_regularizer=None,<br>        bias_regularizer=None,<br>        **kwargs,<br>    ):<br>        super().__init__(**kwargs)<br>        self.dense = keras.layers.Dense(<br>            units=units,<br>            use_bias=use_bias,<br>            kernel_initializer=kernel_initializer,<br>            bias_initializer=bias_initializer,<br>            kernel_regularizer=kernel_regularizer,<br>            bias_regularizer=bias_regularizer,<br>        )<br>        self.relu = keras.layers.ReLU()<br>        self.optimizer = optimizer<br>        self.loss_metric = loss_metric<br>        self.threshold = 1.5<br>        self.num_epochs = num_epochs<br><br><br>    def call(self, x):<br>        x_norm = tf.norm(x, ord=2, axis=1, keepdims=True)<br>        x_norm = x_norm + 1e-4<br>        x_dir = x / x_norm<br>        res = self.dense(x_dir)<br>        return self.relu(res)<br><br><br>    def forward_forward(self, x_pos, x_neg):<br>        for i in range(self.num_epochs):<br>            with tf.GradientTape() as tape:<br>                g_pos = tf.math.reduce_mean(tf.math.pow(self.call(x_pos), 2), 1)<br>                g_neg = tf.math.reduce_mean(tf.math.pow(self.call(x_neg), 2), 1)<br><br>                loss = tf.math.log(<br>                    1<br>                    + tf.math.exp(<br>                        tf.concat([-g_pos + self.threshold, g_neg - self.threshold], 0)<br>                    )<br>                )<br>                mean_loss = tf.cast(tf.math.reduce_mean(loss), tf.float32)<br>                self.loss_metric.update_state([mean_loss])<br>            gradients = tape.gradient(mean_loss, self.dense.trainable_weights)<br>            self.optimizer.apply_gradients(zip(gradients, self.dense.trainable_weights))<br>        return (<br>            tf.stop_gradient(self.call(x_pos)),<br>            tf.stop_gradient(self.call(x_neg)),<br>            self.loss_metric.result(),<br>        )</pre><h4>FFNetwork Custom Model:</h4><p>The next code defines two classes, FFDense and FFNetwork, that are used to create a Forward-Forward (FF) neural network. The FFDense class is a custom layer that inherits from the Keras layer class and overrides the call method to include the Forward-Forward algorithm. This algorithm maximizes the sum of squared neural activities on positive data while minimizing it on negative data, and it does not use backpropagation. The FFNetwork class is a custom model that inherits from the Keras model class and allows the creation of FFDense layers. The predict_one_sample method in the FFNetwork class is used to make predictions on one sample by passing the image through the network, measuring the results produced by each layer, and then finding the label with the highest values by measuring the ‘goodness’ of the images for all labels.</p><pre>class FFNetwork(keras.Model):<br><br>    def __init__(<br>        self, dims, layer_optimizer=keras.optimizers.Adam(learning_rate=0.03), **kwargs<br>    ):<br>        super().__init__(**kwargs)<br>        self.layer_optimizer = layer_optimizer<br>        self.loss_var = tf.Variable(0.0, trainable=False, dtype=tf.float32)<br>        self.loss_count = tf.Variable(0.0, trainable=False, dtype=tf.float32)<br>        self.layer_list = [keras.Input(shape=(dims[0],))]<br>        for d in range(len(dims) - 1):<br>            self.layer_list += [<br>                FFDense(<br>                    dims[d + 1],<br>                    optimizer=self.layer_optimizer,<br>                    loss_metric=keras.metrics.Mean(),<br>                )<br>            ]<br><br><br>    @tf.function(reduce_retracing=True)<br>    def overlay_y_on_x(self, data):<br>        X_sample, y_sample = data<br>        max_sample = tf.reduce_max(X_sample, axis=0, keepdims=True)<br>        max_sample = tf.cast(max_sample, dtype=tf.float64)<br>        X_zeros = tf.zeros([10], dtype=tf.float64)<br>        X_update = xla.dynamic_update_slice(X_zeros, max_sample, [y_sample])<br>        X_sample = xla.dynamic_update_slice(X_sample, X_update, [0])<br>        return X_sample, y_sample<br><br>    @tf.function(reduce_retracing=True)<br>    def predict_one_sample(self, x):<br>        goodness_per_label = []<br>        x = tf.reshape(x, [tf.shape(x)[0] * tf.shape(x)[1]])<br>        for label in range(10):<br>            h, label = self.overlay_y_on_x(data=(x, label))<br>            h = tf.reshape(h, [-1, tf.shape(h)[0]])<br>            goodness = []<br>            for layer_idx in range(1, len(self.layer_list)):<br>                layer = self.layer_list[layer_idx]<br>                h = layer(h)<br>                goodness += [tf.math.reduce_mean(tf.math.pow(h, 2), 1)]<br>            goodness_per_label += [<br>                tf.expand_dims(tf.reduce_sum(goodness, keepdims=True), 1)<br>            ]<br>        goodness_per_label = tf.concat(goodness_per_label, 1)<br>        return tf.cast(tf.argmax(goodness_per_label, 1), tf.float64)<br><br>    def predict(self, data):<br>        x = data<br>        preds = list()<br>        preds = tf.map_fn(fn=self.predict_one_sample, elems=x)<br>        return np.asarray(preds, dtype=int)<br><br><br><br>    @tf.function(jit_compile=True)<br>    def train_step(self, data):<br>        x, y = data<br><br>        x = tf.reshape(x, [-1, tf.shape(x)[1] * tf.shape(x)[2]])<br><br>        x_pos, y = tf.map_fn(fn=self.overlay_y_on_x, elems=(x, y))<br><br>        random_y = tf.random.shuffle(y)<br>        x_neg, y = tf.map_fn(fn=self.overlay_y_on_x, elems=(x, random_y))<br><br>        h_pos, h_neg = x_pos, x_neg<br><br>        for idx, layer in enumerate(self.layers):<br>            if isinstance(layer, FFDense):<br>                print(f&quot;Training layer {idx+1} now : &quot;)<br>                h_pos, h_neg, loss = layer.forward_forward(h_pos, h_neg)<br>                self.loss_var.assign_add(loss)<br>                self.loss_count.assign_add(1.0)<br>            else:<br>                print(f&quot;Passing layer {idx+1} now : &quot;)<br>                x = layer(x)<br>        mean_res = tf.math.divide(self.loss_var, self.loss_count)<br>        return {&quot;FinalLoss&quot;: mean_res}<br><br></pre><h4>Data pre-processing:</h4><pre>x_train = x_train.astype(float) / 255<br>x_test = x_test.astype(float) / 255<br>y_train = y_train.astype(int)<br>y_test = y_test.astype(int)<br><br>train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))<br>test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))<br><br>train_dataset = train_dataset.batch(60000)<br>test_dataset = test_dataset.batch(10000)</pre><h4>Training the model:</h4><pre>model = FFNetwork(dims=[784, 500, 500])<br><br>model.compile(<br>    optimizer=keras.optimizers.Adam(learning_rate=0.03),<br>    loss=&quot;mse&quot;,<br>    jit_compile=True,<br>    metrics=[keras.metrics.Mean()],<br>)<br><br>epochs = 250<br>history = model.fit(train_dataset, epochs=epochs)</pre><h4>Testing the model performance:</h4><pre>preds = model.predict(tf.convert_to_tensor(x_test))<br><br>preds = preds.reshape((preds.shape[0], preds.shape[1]))<br><br>results = accuracy_score(preds, y_test)<br><br>print(f&quot;Test Accuracy score : {results*100}%&quot;)</pre><p>Test Accuracy score : 97.64%</p><h4>Summary:</h4><p>This example has demonstrated the implementation of the Forward-Forward algorithm using TensorFlow and Keras. The results reported in the paper by Prof. Hinton are currently limited to smaller models and datasets like MNIST and Fashion-MNIST. However, it is expected that future research will explore the use of this algorithm on larger models such as LLMs.</p><p>As demonstrated in the paper, a fully-connected network with 4 hidden layers, 2000 units, and trained over 60 epochs using the Forward-Forward algorithm, can achieve a test accuracy error rate of 1.36%. However, by increasing the learning rate and training for 40 epochs, the error rate slightly increases to 1.46%.</p><h3>Conclusion:</h3><p>In this article, I have attempted to summarize and understand the Forward-Forward algorithm using the TensorFlow and Keras packages, as of January 25, 2022. While the results presented by Prof. Hinton in their paper are currently limited to smaller models and datasets like MNIST and Fashion-MNIST, I am confident that this new model will be successful in the future with proper tuning of the learning rate, model architecture, and other parameters. I hope that you have found this information interesting and informative.</p><h4>Resources:</h4><ul><li><em>The link to the official paper: </em><a href="https://www.cs.toronto.edu/~hinton/FFA13.pdf">https://www.cs.toronto.edu/~hinton/FFA13.pdf</a></li><li>Very simple and informative tweets from <a href="https://twitter.com/martin_gorner"><strong>Martin Görner</strong></a></li><li>Geoff Hinton interview: <a href="https://www.youtube.com/watch?v=NWqy_b1OvwQ&amp;t=2009s">https://www.youtube.com/watch?v=NWqy_b1OvwQ&amp;t=2009s</a></li><li>Keras official implementation: <a href="https://www.youtube.com/watch?v=NWqy_b1OvwQ&amp;t=2009s">https://www.youtube.com/watch?v=NWqy_b1OvwQ&amp;t=2009s</a></li><li>Pytorch implementation: <a href="https://github.com/nebuly-ai/nebullvm/tree/main/apps/accelerate/forward_forward">https://github.com/nebuly-ai/nebullvm/tree/main/apps/accelerate/forward_forward</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ac24d0d9ffd" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/forward-forward-algorithm-ac24d0d9ffd">Forward-Forward Algorithm</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>