<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Arthur Habicht</title>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
    <link>https://habichta.com/</link>
    <description>Arthur Habicht, co-founder and CTO of Helpany. Expert in software engineering, production-grade machine learning and Physical AI, based in Zurich.</description>
    <pubDate>Wed, 04 Nov 2026 22:53:36 +0000</pubDate>
    
      <item>
        <title>Python Multiprocessing: Having a Pickle with Pickling</title>
        <link>/python-pickle-with-pickling.html</link>
        <guid isPermaLink="true">/python-pickle-with-pickling.html</guid>
        <description>&lt;img src=&quot;/assets/img/blog/python-pickle-with-pickling/pickled_python-1.webp&quot; alt=&quot;Python Multiprocessing: Having a Pickle with Pickling&quot;&gt;&lt;p&gt;&lt;em&gt;Pickling&lt;/em&gt; is one of the most used serialization protocols specific to Python. It is popular due to its ease ouf use, as virtually all Python objects can be serialized to a bytestream and written on disk or sent over a network.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card&quot;&gt;&lt;img src=&quot;/assets/img/blog/python-pickle-with-pickling/written_by_human-2-1.png&quot; class=&quot;kg-image&quot; alt=&quot;Python Multiprocessing: Having a Pickle with Pickling&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;150&quot;&gt;&lt;/figure&gt;&lt;p&gt;Originally, the term is derived from the process of pickling food for preservation. Similarly, we want to &amp;quot;Python&amp;quot; objects, usually in a &lt;code&gt;.pickle&lt;/code&gt; file for later use. For many, that&amp;apos;s the only place where they directly encounter pickling. However, it happens in many places under the hood. Without realizing, we may use it and since our program seems to run just fine, why bother? In somewhat typical Python fashion: &lt;em&gt;Out of mind, out of sight&lt;/em&gt;. Python is supposed to be an easy language right?&lt;/p&gt;&lt;p&gt;Not so. If you care about speed and efficiency, it is important to understand what happens beyond the single line of Python code that does so much. I know I mentioned speed and Python in a single sentence (how dare you?). We need to keep in mind, that at the time of writing, large parts of the world are running on Python. Especially since the meteoric rise of modern machine learning and AI&lt;a href=&quot;#fn1&quot; rel=&quot;noreferrer&quot;&gt;&lt;sup&gt;[1]&lt;/sup&gt;&lt;/a&gt;. So we should pay attention.&lt;/p&gt;&lt;h2 id=&quot;a-pickle-stuck-in-a-pipe&quot;&gt;A Pickle stuck in a Pipe&lt;/h2&gt;
&lt;p&gt;There are physical limitations when trying to increase the clock speed of CPUs (Central Processing Units). Therefore, chip manufacturers have resorted to increasing the number of cores in CPUs, allowing for parallel processing of instructions (rather than processing them faster). The most widely used implementation of Python (CPython) is not well suited for this kind of programming paradigm due to the Global Interpreter Lock (GIL)&lt;a href=&quot;#fn2&quot; rel=&quot;noreferrer&quot;&gt;&lt;sup&gt;[2]&lt;/sup&gt;&lt;/a&gt; that prevents Python programs (or threads) from ending up in race conditions.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/python-pickle-with-pickling/python_racecondition-1-1.webp&quot; class=&quot;kg-image&quot; alt=&quot;Python Multiprocessing: Having a Pickle with Pickling&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Without the GIL, Python might get tangled up...&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;This is a major issue since Python is used for many applications in scientific computing that rely on parallel computations to crunch enormous amount of numbers (most notably applications in AI and high-performance computing). &lt;/p&gt;&lt;p&gt;For this reason, many programmers resort to spinning up multiple processes (with their independent Python instances) and employing inter-process communication (IPC) techniques (e.g, Pipes or Networking Sockets) to coordinate those processes to work together on a computation. This paradigm has multiple downsides. Here is a quote:&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;In PyTorch, Python is commonly used to orchestrate ~8 GPUs and ~64 CPU threads, growing to 4k GPUs and 32k CPU threads for big models. While the heavy lifting is done outside of Python, the speed of GPUs makes even just the orchestration in Python not scalable. We often end up with 72 processes in place of one because of the GIL. Logging, debugging, and performance tuning are orders-of-magnitude more difficult in this regime, continuously causing lower developer productivity.&lt;br&gt;
-- Zachary DeVito, PyTorch core developer and researcher at FAIR (Meta AI)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Processes are not nimble entities and come with a lot of overhead. Also, making those processes communicate over IPC can be slow. This is where pickling enters the scene.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/python-pickle-with-pickling/python_process-1-1.webp&quot; class=&quot;kg-image&quot; alt=&quot;Python Multiprocessing: Having a Pickle with Pickling&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Python processes are heavy-weight...&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;Unbeknownst to many, popular methods for IPC (of the &amp;quot;message-passing&amp;quot; variant) such as &lt;code&gt;multiprocessing.Queue&lt;/code&gt; use pickling in the background. As data gets sent from one process to another, it needs to be serialized into a bytestream and then deserialized again&lt;a href=&quot;#fn3&quot; rel=&quot;noreferrer&quot;&gt;&lt;sup&gt;[3]&lt;/sup&gt;&lt;/a&gt;. It is well known, that this is not exactly efficient&lt;a href=&quot;#fn4&quot; rel=&quot;noreferrer&quot;&gt;&lt;sup&gt;[4]&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;&lt;h2 id=&quot;shared-memory-to-the-rescue&quot;&gt;Shared Memory to the Rescue&lt;/h2&gt;
&lt;p&gt;I would like to offer an interesting alternative. We won&amp;apos;t get rid of processes (in favor of light-weight threads, this will take a couple of years until Python is capable of doing that. Note that C API Extension for Python can release the GIL for long running processes. However, this does not fully replace &amp;quot;true&amp;quot; multi-threading) for our CPU-bound computations. However, we can get rid of that pickle. Below I present a simplified solution of using &lt;em&gt;shared memory&lt;/em&gt; for IPC. Shared Memory allows processes to access the same memory region rather than sending each other messages. &lt;/p&gt;&lt;p&gt;The example we will look at aims to do the following: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create a custom &lt;code&gt;SharedMemoryProcessPool&lt;/code&gt; class that can accept workloads (tasks) and assign them to a pool of worker processes. We want to minimize the pickling overhead though &lt;code&gt;SharedMemory&lt;/code&gt; as much as possible.&lt;/li&gt;&lt;li&gt;Make sure that the dispatched workloads (&amp;quot;futures&amp;quot;) remain in order. I do this by using a normal &lt;code&gt;queue&lt;/code&gt; (not a multi-processing queue!). These to not use any pickling.&lt;/li&gt;&lt;li&gt;We restrict our workload to &lt;code&gt;numpy&lt;/code&gt; arrays. But this is not a hard requirement.&lt;/li&gt;&lt;li&gt;Both input array and output array are shared via &lt;code&gt;SharedMemory&lt;/code&gt;. Note that the &lt;code&gt;future&lt;/code&gt; only returns a &lt;code&gt;bool&lt;/code&gt;, not the result of the computation. Futures use pickling in the background and we want to avoid transmitting potentially large amounts of data (the result of the tasks). We settle for returning a single &lt;code&gt;bool&lt;/code&gt; (which will be pickled) and use it as a sentinel.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The snippet below shows a custom class &lt;code&gt;SharedMemoryProcessPool&lt;/code&gt;. It accepts workloads through its &lt;code&gt;put&lt;/code&gt; function. I assumed that work will happen on a &lt;code&gt;numpy&lt;/code&gt; array &lt;code&gt;arr&lt;/code&gt; for which the function creates a Shared Memory region using the &lt;code&gt;multiprocessing.shared_memory&lt;/code&gt; module. The memory for the result of the task is pre-allocated as well. The reason for this is that we cannot easily allocate it dynamically in the worker process because we will get a segmentation fault as the memory region seems to be de-allocated as soon as the worker process finishes the task.&lt;/p&gt;&lt;p&gt;There is no free lunch. Pickling offers you more flexibility at the cost of efficiency. However, if you can specify your workloads (in terms of memory requirements) then using shared memory is a good option. With the implementation below I achieved a speed up of almost 50% compared to a simple implementation using futures (without shared memory).&lt;/p&gt;&lt;figure class=&quot;kg-card kg-code-card&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class SharedMemoryProcessPool:
    def __init__(self) -&amp;gt; None:
        self.executor = ProcessPoolExecutor(max_workers=4)
        self.task_queue = queue.Queue()

    def put(self, func, arr, task_type):

        shm = SharedMemory(create=True, size=arr.nbytes)
        shm_result = SharedMemory(create=True, size=task_type.result_bytes)
        copy_array_to_shared_memory(arr, shm.name, arr.shape, arr.dtype)
        self.task_queue.put(
            (
                shm,
                shm_result,
                task_type,
                self.executor.submit(
                    func,
                    shm.name,
                    arr.shape,
                    arr.dtype,
                    shm_result.name,
                    task_type.result_shape,
                    task_type.result_dtype,
                ),
            )
        )

    def get(self):
        input_shm: SharedMemory
        f: Future
        input_shm, result_shm, task_type, f = self.task_queue.get()

        result, success = None, False
        try:
            success = f.result()

            if success:
                result = np.array(
                      np.ndarray(shape=task_type.result_shape, dtype=task_type.result_dtype, buffer=result_shm.buf)
                )

            return result, success

        finally:
            deallocate_shared_memory(input_shm)
            deallocate_shared_memory(result_shm)

    def empty(self):
        return self.task_queue.empty()

    def _clear_task_queue(self):
        while not self.task_queue.empty():
            input_shm, result_shm, _, future = self.task_queue.get()
            future.cancel()
            deallocate_shared_memory(input_shm)
            deallocate_shared_memory(result_shm)

    def shutdown(self):
        self._clear_task_queue()
        self.executor.shutdown()&lt;/code&gt;&lt;/pre&gt;&lt;figcaption&gt;&lt;p&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;See &lt;/span&gt;&lt;a href=&quot;https://gist.github.com/habichta/9adccab9cbcf0ae7c0b136e2866e5dd2&quot; rel=&quot;noreferrer&quot;&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;GitHub&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt; for full code&lt;/span&gt;&lt;/p&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;!--kg-card-begin: html--&gt;
&lt;p&gt;
  &lt;a name=&quot;fn1&quot; class=&quot;text-like-link&quot; style=&quot;color: inherit; text-decoration: none;&quot; href=&quot;https://www.statista.com/statistics/793628/worldwide-developer-survey-most-used-languages/&quot;&gt;[1] See Statista 2023.&lt;/a&gt;
  &lt;br&gt;
  &lt;a name=&quot;fn2&quot; class=&quot;text-like-link&quot; style=&quot;color: inherit; text-decoration: none;&quot; href=&quot;https://peps.python.org/pep-0703/&quot;&gt;[2] There seems to be recent work going on trying to remove the GIL from CPython (PEP 0703). The rollout of such can only happen gradually, because many important Python libraries implicitly depend on the GIL. Simply removing it would break a lot of stuff.&lt;/a&gt;
&lt;br&gt;
  &lt;a name=&quot;fn3&quot; class=&quot;text-like-link&quot; style=&quot;color: inherit; text-decoration: none;&quot; href=&quot;https://docs.python.org/3/library/multiprocessing.html#pipes-and-queues&quot;&gt;[3] Documentation for Pipes and Queues in the multiprocessing library&lt;/a&gt;
&lt;br&gt;
 &lt;a name=&quot;fn4&quot; class=&quot;text-like-link&quot; style=&quot;color: inherit; text-decoration: none;&quot; href=&quot;https://www.benfrederickson.com/dont-pickle-your-data/&quot;&gt;[4] Don&amp;apos;t pickle your data&lt;/a&gt;
&lt;/p&gt;

&lt;!--kg-card-end: html--&gt;

</description>
        <pubDate>Wed, 27 Mar 2024 21:25:36 +0000</pubDate>
      </item>
    
      <item>
        <title>AI Chronicles I: Generative Inflation</title>
        <link>/generative-inflation.html</link>
        <guid isPermaLink="true">/generative-inflation.html</guid>
        <description>&lt;img src=&quot;/assets/img/blog/generative-inflation/DALL-E-2023-11-05-18.59.38---A-cat-standing-in-front-of-a-box-which-says-_GAR_-on-it.-In-pixel-art-1.png&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot;&gt;&lt;p&gt;GAR, RAG, EBR or GWARGL!? We are approaching the Singularity of AI jargon. This is a futile attempt to explain some of them.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/written_by_human-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;150&quot;&gt;&lt;/figure&gt;&lt;p&gt;On one of my recent expeditions through the vast ocean of GitHub projects in search for interesting projects to contribute to, I inevitably entered the shallow waters of LLM (Large Language Models) toolings, toolkits and ChatGPT wrappers. Nautical protocols strictly advise to steer clear of these shoal depths as one&amp;apos;s vessel may meet an untimely embrace with perilous and unnecessary code formations.&lt;/p&gt;&lt;p&gt;But here we are. Tacking around reefs of a dysfunctional ecosystem that grew to fast for its own liking, I came across a project called tiger. Now, there is nothing special about this project. It&amp;apos;s as close to the waterline as most of them (at least at the time of writing &lt;sup&gt;1&lt;/sup&gt;).&lt;/p&gt;
&lt;p&gt;Why did I bother looking at this? For sure, the initial spark came from the Python package called TigerRag that immediately and irrevocably imprinted a picture in my mind (illustration provided). A split second later, I asked myself what the motivation might have been to choose such a name. Granted, the world of generative AI is littered with absurd, animalistic associations&lt;sup&gt;2&lt;/sup&gt;. So I should not have been surprised.&lt;/p&gt;
&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/tigerrag-e1699215381647-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;189&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Meh... Another ChatGPT Wrapper&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;h2 id=&quot;a-treatment-for-pathological-liars&quot;&gt;A treatment for pathological liars&lt;/h2&gt;&lt;p&gt;Still, why? Tiger and Rag. Let&amp;apos;s find out. As you might have guessed, a dirty piece of cloth was not the inspiration here. Of course we are talking about Retrieval Augmented Generation (RAG). Just another frond of duckweed that is the world of generative AI-jargon. But what does it do? It is quite simple&lt;sup&gt;3&lt;/sup&gt;:&lt;/p&gt;
&lt;figure class=&quot;kg-card kg-image-card&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/math-1-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;100&quot; height=&quot;80&quot;&gt;&lt;/figure&gt;&lt;p&gt;\[p_{RAG-Sequence}(y|x)\approx \sum_{z\in top-k(p(\cdot |x))} p_{\eta}(z|x) p_{\theta}(y|x,z)\]&lt;br&gt;\[p_{\eta}(z|x) \propto exp(\mathbf{d}(z)^{\top}\mathbf{q}(x))\quad \mathbf{d}(z)= BERT_{d}(z), \mathbf{q}(x)= BERT_{q}(x)\]&lt;/p&gt;&lt;p&gt;Now if that confuses you, worry not. The reason for this is that we are dealing with math, the arch nemesis of normal people. I know this escalated rather quickly. We began with rag-wearing tigers and ended up here. Also, how does &lt;strong&gt;Bert&lt;/strong&gt; from the Muppet show factor in here? Welcome to the strange world of AI.&lt;/p&gt;&lt;p&gt;Let&amp;apos;s take a step back and not get ahead of ourselves. Maybe let me give you some context first. As mentioned before we are dealing with Large Language Models (LLM). If you have not been living under a rag, you may be familiar with ChatGPT. A LLM-powered Chatterbox, which was launched by &lt;a href=&quot;https://openai.com/&quot;&gt;ClosedAI&lt;/a&gt; last year.&lt;/p&gt;&lt;p&gt;It is certainly a very powerful and useful tool&lt;sup&gt;4&lt;/sup&gt;. However, like any LLM, it is also a pathological liar (who went through quite a bit of therapy already, to be fair). It suffers from what the AI community euphemistically calls &amp;quot;hallucinations&amp;quot; (a.k.a. lies). If a LLM were a person, it could easily be a sleazy car salesman trying to sell you a tricycle as a Porsche without batting an eye. So be careful. That piece of math up there is an attempt to remedy the LLM&amp;apos;s ingrained tendency to brazenly lie about things.&lt;/p&gt;
&lt;h2 id=&quot;crawling-through-a-dense-passage&quot;&gt;Crawling through a dense passage...&lt;/h2&gt;&lt;p&gt;There are a couple of actors that need to be introduced to understand these scary symbols up there. Lets start with a system called Dense Passage Retriever (DPR)&lt;sup&gt;5&lt;/sup&gt;. I know it sounds a bit wrong... a dense passage. But that is how the inventors of DPR chose to call it (hallucinated it into existence, so to speak).&lt;/p&gt;
&lt;p&gt;And there is Bert. Bert as in &lt;strong&gt;Bidirectional Encoder Representations from Transformers&lt;/strong&gt; &lt;strong&gt;(BERT)&lt;/strong&gt;. It really does not have to make sense. Just know that BERT is an artificial neural network and not a Muppet show character. The point of BERT is to take a text which humans can understand and condense (encode) it into a set of numbers that are useful. Useful means, that texts which have something in common get &amp;quot;similar&amp;quot; numbers. For example, the text &amp;quot;AI hallucinations&amp;quot; should end up having similar numbers as &amp;quot;lying&amp;quot;.&lt;/p&gt;&lt;p&gt;In nerd-speak we would say that we create &amp;quot;&lt;strong&gt;vector embeddings&lt;/strong&gt;&amp;quot; that live in a &amp;quot;&lt;strong&gt;vector space&lt;/strong&gt;&amp;quot;. These vectors are like arrows pointing somewhere and vectors of two words that semantically belong to each other point to a similar location. This is useful, because we can search things with that.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/vector-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;208&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;A vector you know from school. Maybe you finally accept why they are useful!&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;If I want to look for &amp;quot;&lt;em&gt;sci-fi movies&lt;/em&gt;&amp;quot; (Query), then my query would be &amp;quot;embedded&amp;quot; close to e.g., &amp;quot;&lt;em&gt;Starwars&lt;/em&gt;&amp;quot; (Retrieval). Sounds like a search engine right? That&amp;apos;s because it kind of is one. You can think of an archer shooting arrows. Your query is an arrow and a well trained archer (in this case he is called Bert) will hit the correct area on a target (vector space, or where your arrows live).&lt;/p&gt;&lt;p&gt;This is essentially the definition of &lt;strong&gt;Embedding-based retrieval (EBR)&lt;/strong&gt;. Take anything you like, transform it into a mathematical arrow (vector embedding) and retrieve arrows that are in close proximity to it in a specially crafted vector space. Our &lt;strong&gt;DPR&lt;/strong&gt; introduced earlier is a special way of doing this. It uses two BERTs that encode query and documents (called passages, hence the name of the system) into a vector space. Since there are two, it is called a bi-encoder architecture.&lt;/p&gt;&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/bert_arrow-e1700324792244-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;199&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;Illustration of a Bert Archer&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;To take our archery example: You have two archers (by sheer coincidence they are both called Bert). You ask one to shoot an arrow on the target (e.g., an arrow that has a label &amp;quot;Starwars&amp;quot; on it) and ask the other to shoot one very close to a group arrows (e.g., those that have labels that relate to &amp;quot;sci-fi movies&amp;quot;; your query).&lt;/p&gt;&lt;p&gt;If you are interested, you can return to the formulas above. DPR is the second line (with the 2 BERTs). In normal speak it says: &amp;quot;Calculate the probability of retrieving a passage/document z given a query x. But first encode those into a vector space using 2 different BERT Neural Networks&amp;quot;&lt;sup&gt;6&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;to-see-the-light-at-the-end-of-the-tunnel&quot;&gt;... to see the light at the end of the tunnel&lt;/h2&gt;&lt;p&gt;So how does that have to to with RAG? Remember that it is about generation (Retrieval Augmented &lt;em&gt;Generation&lt;/em&gt;). In this context, about generating text. Let&amp;apos;s introduce our generator: a pre-trained &lt;strong&gt;Large Language Model (LLM)&lt;/strong&gt;. If we have a look at the first equation above. Specifically:&lt;br&gt;&lt;br&gt;\[p_{\theta}(y|x,z)\]&lt;/p&gt;&lt;p&gt;This is the LLM. It calculates the probability of the next token &lt;strong&gt;y&lt;/strong&gt;, given a query &lt;strong&gt;x&lt;/strong&gt; and a retrieved document &lt;strong&gt;z&lt;/strong&gt;. A token might be any number of characters (words, whole texts, etc.). If you want to describe a LLM in the most boring way, you would describe it as a generator of the most probable words given some input. Like people who just speak what comes to their minds, given what they just heard. Sadly, this describes most humans as well.&lt;/p&gt;&lt;p&gt;Now you can also see what RAG is about. It&amp;apos;s the &lt;strong&gt;z&lt;/strong&gt; from our DPR System that is added to the input of the LLM to nudge it towards a direction such that it is more likely to choose words that are hopefully more meaningful to you.&lt;/p&gt;&lt;p&gt;It can also help the LLM to produce more truthful answers, since it was given more substantial context. The z gives it additional guardrails&lt;sup&gt;7&lt;/sup&gt;, so it does not go on a tangent. It has a smaller probability of lying bout things (sorry... hallucinating). You could see it like a mind trick for LLMs. It is like me telling you &amp;quot;not to think about a blue elephant&amp;quot;. Of course you will do it.&lt;/p&gt;
&lt;figure class=&quot;kg-card kg-image-card kg-card-hascaption&quot;&gt;&lt;img src=&quot;/assets/img/blog/generative-inflation/blue_elefant-e1700327361278-1.png&quot; class=&quot;kg-image&quot; alt=&quot;AI Chronicles I: Generative Inflation&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;173&quot;&gt;&lt;figcaption&gt;&lt;span style=&quot;white-space: pre-wrap;&quot;&gt;A blue elephant&lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Summary: &lt;/strong&gt;Let&amp;apos;s take the example of trying to generate text about sci-fi movies. You can ask DPR to retrieve additional context about sci-fi movies using those BERTs. Maybe this particular DPR was built on data from the &lt;a href=&quot;http://www.imdb.com/&quot;&gt;International Movie Database (IMDb)&lt;/a&gt;. You ask about &amp;quot;sci-fi movies&amp;quot; and it may retrieve &amp;quot;Starwars, Interstellar, etc.&amp;quot;. You can use that to enrich your question to the LLM. Instead of asking it to &amp;quot;generate text about sci-fi movies&amp;quot; you can use the output of this DPR to improve your question: &amp;quot;generate text about sci-fi movies such as Starwars, Interstellar, etc&amp;quot;. This will steer and augment the text generation of the LLM to generate better and more accurate texts&lt;/p&gt;&lt;h2 id=&quot;ok-nice-but-this-went-on-for-far-too-long-please-stop&quot;&gt;Ok nice, but this went on for far too long. Please stop...&lt;/h2&gt;&lt;p&gt;You are spot on. Luckily, the last concept &amp;quot;&lt;strong&gt;Generation Augmented Retrieval (GAR)&lt;/strong&gt;&amp;quot; is quickly explained now. It is the reverse operation to RAG. You ask a LLM to improve a query which you can ask to e.g., the DPR system. If you want to find sci-fi movies, you can ask the LLM to provide a richer query which will help you find a better selection of sci-fi movies.&lt;/p&gt;&lt;p&gt;What about GWARGL? It does not exist. But given the generative capacity of modern generative AI, it might very well pop into existence tomorrow!&lt;/p&gt;&lt;p&gt;[1]: &lt;em&gt;This disclaimer is necessary for any AI-related project due to &lt;/em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Roko&amp;apos;s_basilisk&quot;&gt;&lt;em&gt;Roko&amp;apos;s Basilisk&lt;/em&gt;&lt;/a&gt;&lt;br&gt;[2]:&lt;em&gt; In this dimension of the universe, true super-intelligence may manifest itself as a Llama, Alpaca or Vicuna.&lt;/em&gt;&lt;br&gt;[3]:&lt;em&gt; &lt;/em&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2005.11401&quot;&gt;https://doi.org/10.48550/arXiv.2005.11401&lt;/a&gt;&lt;br&gt;[4]: A &lt;em&gt;tool. It is a powerful tool. Not anything sentient or so.&lt;/em&gt;&lt;br&gt;[5]:&lt;em&gt; &lt;/em&gt;&lt;a href=&quot;https://doi.org/10.48550/arXiv.2004.04906&quot;&gt;https://doi.org/10.48550/arXiv.2004.04906&lt;/a&gt;&lt;br&gt;[6]: &lt;em&gt;We have skipped an important aspect here. It is not trivial to efficiently find all arrows that are close to another one (the computational complexity can be high). This is generally called the &lt;strong&gt;Maximum Inner Product Search (MIPS) &lt;/strong&gt;problem. One go-to solution for this is the &lt;/em&gt;&lt;a href=&quot;https://ai.meta.com/tools/faiss/&quot;&gt;&lt;strong&gt;&lt;em&gt;Facebook AI Similarity Search (FAISS)&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;em&gt; library that allows to efficiently find documents embedded in a vector space which are close to the query vector. We have also not touched upon how these BERTs are actually trained to be good archers.&lt;/em&gt;&lt;br&gt;[7]:&lt;em&gt; You could say it is &amp;quot;retrieval-augmented prompt engineering&amp;quot;&lt;/em&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 25 Mar 2024 20:59:06 +0000</pubDate>
      </item>
    
  </channel>
</rss>
