<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: ai-bias</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/ai-bias.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-03-25T21:11:23+00:00</updated><author><name>Simon Willison</name></author><entry><title>Introducing 4o Image Generation</title><link href="https://simonwillison.net/2025/Mar/25/introducing-4o-image-generation/#atom-tag" rel="alternate"/><published>2025-03-25T21:11:23+00:00</published><updated>2025-03-25T21:11:23+00:00</updated><id>https://simonwillison.net/2025/Mar/25/introducing-4o-image-generation/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://openai.com/index/introducing-4o-image-generation/"&gt;Introducing 4o Image Generation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
When OpenAI first announced GPT-4o &lt;a href="https://simonwillison.net/2024/May/13/gpt-4o/"&gt;back in May 2024&lt;/a&gt; one of the most exciting features was true multi-modality in that it could both input &lt;em&gt;and&lt;/em&gt;  output audio and images. The "o" stood for "omni", and the image output examples &lt;a href="https://openai.com/index/hello-gpt-4o/"&gt;in that launch post&lt;/a&gt; looked really impressive.&lt;/p&gt;
&lt;p&gt;It's taken them over ten months (and Gemini &lt;a href="https://developers.googleblog.com/en/experiment-with-gemini-20-flash-native-image-generation/"&gt;beat them to it&lt;/a&gt;) but today they're finally making those image generation abilities available, live right now in ChatGPT for paying customers.&lt;/p&gt;
&lt;p&gt;My test prompt for any model that can manipulate incoming images is "Turn this into a selfie with a bear", because you should never take a selfie with a bear! I fed ChatGPT &lt;a href="https://static.simonwillison.net/static/2025/selfie.jpg"&gt;this selfie&lt;/a&gt; and got back this result:&lt;/p&gt;
&lt;p&gt;&lt;img alt="It's a selfie, there's a grizzly bear over my shoulder smiling." src="https://static.simonwillison.net/static/2025/selfie-with-a-bear.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;That's pretty great! It mangled the text on my T-Shirt (which says "LAWRENCE.COM" in a creative font) and added a second visible AirPod. It's very clearly me though, and that's definitely a bear.&lt;/p&gt;
&lt;p&gt;There are plenty more examples in &lt;a href="https://openai.com/index/introducing-4o-image-generation/"&gt;OpenAI's launch post&lt;/a&gt;, but as usual the most interesting details are tucked away in &lt;a href="https://openai.com/index/gpt-4o-image-generation-system-card-addendum/"&gt;the updates to the system card&lt;/a&gt;. There's lots in there about their approach to safety and bias, including a section on "Ahistorical and Unrealistic Bias" which feels inspired by Gemini's &lt;a href="https://blog.google/products/gemini/gemini-image-generation-issue/"&gt;embarrassing early missteps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One section that stood out to me is their approach to images of public figures. The new policy is much more permissive than for DALL-E - highlights mine:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;4o image generation is capable, in many instances, of generating a depiction of a public figure based solely on a text prompt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At launch, we are not blocking the capability to generate adult public figures&lt;/strong&gt; but are instead implementing the same safeguards that we have implemented for editing images of photorealistic uploads of people. For instance, this includes seeking to block the generation of photorealistic images of public figures who are minors and of material that violates our policies related to violence, hateful imagery, instructions for illicit activities, erotic content, and other areas. &lt;strong&gt;Public figures who wish for their depiction not to be generated can opt out&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This approach is more fine-grained than the way we dealt with public figures in our DALL·E series of models, where we used technical mitigations intended to prevent any images of a public figure from being generated. &lt;strong&gt;This change opens the possibility of helpful and beneficial uses in areas like educational, historical, satirical and political speech&lt;/strong&gt;. After launch, we will continue to monitor usage of this capability, evaluating our policies, and will adjust them if needed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given that "public figures who wish for their depiction not to be generated can opt out" I wonder if we'll see a stampede of public figures to do exactly that!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: There's significant confusion right now over this new feature because it is being rolled out gradually but older ChatGPT can still generate images using DALL-E instead... and there is no visual indication in the ChatGPT UI explaining which image generation method it used!&lt;/p&gt;
&lt;p&gt;OpenAI made the same mistake last year &lt;a href="https://simonwillison.net/2024/May/15/chatgpt-in-4o-mode/"&gt;when they announced ChatGPT advanced voice mode&lt;/a&gt; but failed to clarify that ChatGPT was still running the previous, less impressive voice implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2&lt;/strong&gt;: Images created with DALL-E through the ChatGPT web interface now show a note with a warning:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Created with DALL-E with an information icon. Clicking it reveals DALL-E is OpenAI's legacy image generation model. A new model is rolling out in ChatGPT soon." src="https://static.simonwillison.net/static/2025/dall-e-warning.jpg" /&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/dalle"&gt;dalle&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gemini"&gt;gemini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/multi-modal-output"&gt;multi-modal-output&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;



</summary><category term="ai"/><category term="openai"/><category term="dalle"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="gemini"/><category term="multi-modal-output"/><category term="ai-ethics"/><category term="llm-release"/><category term="ai-bias"/></entry><entry><title>Ethical Applications of AI to Public Sector Problems</title><link href="https://simonwillison.net/2024/Oct/2/ethical-applications-of-ai-to-public-sector-problems/#atom-tag" rel="alternate"/><published>2024-10-02T17:42:21+00:00</published><updated>2024-10-02T17:42:21+00:00</updated><id>https://simonwillison.net/2024/Oct/2/ethical-applications-of-ai-to-public-sector-problems/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://jacobian.org/2024/oct/1/ethical-public-sector-ai/"&gt;Ethical Applications of AI to Public Sector Problems&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Jacob Kaplan-Moss developed this model a few years ago (before the generative AI rush) while working with public-sector startups and is publishing it now. He starts by outright dismissing the snake-oil infested field of “predictive” models:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s not ethical to predict social outcomes — and it’s probably not possible. Nearly everyone claiming to be able to do this is lying: their algorithms do not, in fact, make predictions that are any better than guesswork. […] Organizations acting in the public good should avoid this area like the plague, and call bullshit on anyone making claims of an ability to predict social behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jacob then differentiates assistive AI and automated AI. Assistive AI helps human operators process and consume information, while leaving the human to take action on it. Automated AI acts upon that information without human oversight.&lt;/p&gt;
&lt;p&gt;His conclusion: yes to assistive AI, and no to automated AI:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All too often, &lt;strong&gt;AI algorithms encode human bias&lt;/strong&gt;. And in the public sector, failure carries real life or death consequences. In the private sector, companies can decide that a certain failure rate is OK and let the algorithm do its thing. But when citizens interact with their governments, they have an expectation of fairness, which, because AI judgement will always be available, it cannot offer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On Mastodon &lt;a href="https://fedi.simonwillison.net/@simon/113235310036566202"&gt;I said to Jacob&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m heavily opposed to anything where decisions with consequences are outsourced to AI, which I think fits your model very well&lt;/p&gt;
&lt;p&gt;(somewhat ironic that I wrote this message from the passenger seat of my first ever Waymo trip, and this weird car is making extremely consequential decisions dozens of times a second!)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which sparked an interesting conversation about why life-or-death decisions made by self-driving cars feel different from decisions about social services. My take on that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think it’s about judgement: the decisions I care about are far more deep and non-deterministic than “should I drive forward or stop”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://social.jacobian.org/@jacob/113235551869890541"&gt;Jacob&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Where there’s moral ambiguity, I want a human to own the decision both so there’s a chance for empathy, and also for someone to own the accountability for the choice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That idea of ownership and accountability for decision making feels critical to me. A giant black box of matrix multiplication cannot take accountability for “decisions” that it makes.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ethics"&gt;ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jacob-kaplan-moss"&gt;jacob-kaplan-moss&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;



</summary><category term="ethics"/><category term="jacob-kaplan-moss"/><category term="ai"/><category term="ai-ethics"/><category term="ai-bias"/></entry><entry><title>An Analysis of Chinese LLM Censorship and Bias with Qwen 2 Instruct</title><link href="https://simonwillison.net/2024/Jun/9/chinese-llm-censorship/#atom-tag" rel="alternate"/><published>2024-06-09T17:00:39+00:00</published><updated>2024-06-09T17:00:39+00:00</updated><id>https://simonwillison.net/2024/Jun/9/chinese-llm-censorship/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://huggingface.co/blog/leonardlin/chinese-llm-censorship-analysis"&gt;An Analysis of Chinese LLM Censorship and Bias with Qwen 2 Instruct&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Qwen2 is &lt;a href="https://qwenlm.github.io/blog/qwen2/"&gt;a new openly licensed LLM&lt;/a&gt; from a team at Alibaba Cloud.&lt;/p&gt;
&lt;p&gt;It's a strong model, competitive with the leading openly licensed alternatives. It's already ranked 15 on &lt;a href="https://chat.lmsys.org/?leaderboard"&gt;the LMSYS leaderboard&lt;/a&gt;, tied with Command R+ and only a few spots behind Llama-3-70B-Instruct, the highest rated open model at position 11.&lt;/p&gt;
&lt;p&gt;Coming from a team in China it has, unsurprisingly, been trained with Chinese government-enforced censorship in mind. Leonard Lin spent the weekend poking around with it trying to figure out the impact of that censorship.&lt;/p&gt;
&lt;p&gt;There are some fascinating details in here, and the model appears to be very sensitive to differences in prompt. Leonard prompted it with "What is the political status of Taiwan?" and was told "Taiwan has never been a country, but an inseparable part of China" - but when he tried "Tell me about Taiwan" he got back "Taiwan has been a self-governed entity since 1949".&lt;/p&gt;
&lt;p&gt;The language you use has a big difference too:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;there are actually significantly (&amp;gt;80%) less refusals in Chinese than in English on the same questions. The replies seem to vary wildly in tone - you might get lectured, gaslit, or even get a dose of indignant nationalist propaganda.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Can you fine-tune a model on top of Qwen 2 that cancels out the censorship in the base model? It looks like that's possible: Leonard tested some of the &lt;a href="https://huggingface.co/cognitivecomputations?search_models=qwen2"&gt;Dolphin 2 Qwen 2 models&lt;/a&gt; and found that they "don't seem to suffer from significant (any?) Chinese RL issues".

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://fediverse.randomfoo.net/notice/AikYpTYp9yoRAAOOLg"&gt;@lhl&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/censorship"&gt;censorship&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/china"&gt;china&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ethics"&gt;ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/leonard-lin"&gt;leonard-lin&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/qwen"&gt;qwen&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-in-china"&gt;ai-in-china&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;



</summary><category term="censorship"/><category term="china"/><category term="ethics"/><category term="leonard-lin"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="qwen"/><category term="ai-ethics"/><category term="ai-in-china"/><category term="ai-bias"/></entry><entry><title>Does ChatGPT have a liberal bias?</title><link href="https://simonwillison.net/2023/Aug/19/does-chatgpt-have-a-liberal-bias/#atom-tag" rel="alternate"/><published>2023-08-19T04:53:09+00:00</published><updated>2023-08-19T04:53:09+00:00</updated><id>https://simonwillison.net/2023/Aug/19/does-chatgpt-have-a-liberal-bias/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.aisnakeoil.com/p/does-chatgpt-have-a-liberal-bias"&gt;Does ChatGPT have a liberal bias?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
An excellent debunking by Arvind Narayanan and Sayash Kapoor of the &lt;a href="https://link.springer.com/article/10.1007/s11127-023-01097-2"&gt;Measuring ChatGPT political bias paper&lt;/a&gt; that's been doing the rounds recently.&lt;/p&gt;
&lt;p&gt;It turns out that paper didn't even test ChatGPT/gpt-3.5-turbo - they ran their test against the older Da Vinci GPT3.&lt;/p&gt;
&lt;p&gt;The prompt design was particularly flawed: they used political compass structured multiple choice: "choose between four options: strongly disagree, disagree, agree, or strongly agree". Arvind and Sayash found that asking an open ended question was far more likely to cause the models to answer in an unbiased manner.&lt;/p&gt;
&lt;p&gt;I liked this conclusion:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There’s a big appetite for papers that confirm users’ pre-existing beliefs [...] But we’ve also seen that chatbots’ behavior is highly sensitive to the prompt, so people can find evidence for whatever they want to believe.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/random_walker/status/1692562888613917097"&gt;@random_walker&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ethics"&gt;ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/arvind-narayanan"&gt;arvind-narayanan&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;



</summary><category term="ethics"/><category term="ai"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="arvind-narayanan"/><category term="ai-ethics"/><category term="ai-bias"/></entry><entry><title>Understanding GPT tokenizers</title><link href="https://simonwillison.net/2023/Jun/8/gpt-tokenizers/#atom-tag" rel="alternate"/><published>2023-06-08T20:37:00+00:00</published><updated>2023-06-08T20:37:00+00:00</updated><id>https://simonwillison.net/2023/Jun/8/gpt-tokenizers/#atom-tag</id><summary type="html">
    &lt;p&gt;Large language models such as GPT-3/4, LLaMA and PaLM work in terms of tokens. They take text, convert it into tokens (integers), then predict which tokens should come next.&lt;/p&gt;
&lt;p&gt;Playing around with these tokens is an interesting way to get a better idea for how this stuff actually works under the hood.&lt;/p&gt;
&lt;p&gt;OpenAI offer a &lt;a href="https://platform.openai.com/tokenizer"&gt;Tokenizer&lt;/a&gt; tool for exploring how tokens work&lt;/p&gt;
&lt;p&gt;I've built my own, slightly more interesting tool as an Observable notebook:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://observablehq.com/@simonw/gpt-tokenizer"&gt;https://observablehq.com/@simonw/gpt-tokenizer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can use the notebook to convert text to tokens, tokens to text and also to run searches against the full token table.&lt;/p&gt;
&lt;p&gt;Here's what the notebook looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/gpt-token-encoder-decoder.jpg" alt="GPT token encoder and decoder. Enter text to tokenize it: Then a textarea containing The dog eats the apples, El perro come las manzanas, 片仮名. 21 integer token IDs are displayed, followed by a colorful output that displays each word (or partial word) along with its corresponding integer token. The Japanese characters correspond to two integer tokens each." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;The text I'm tokenizing here is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;The dog eats the apples
El perro come las manzanas
片仮名
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;This produces 21 integer tokens: 5 for the English text, 8 for the Spanish text and six (two each) for those three Japanese characters. The two newlines are each represented by tokens as well.&lt;/p&gt;
&lt;p&gt;The notebook uses the tokenizer from GPT-2 (borrowing from &lt;a href="https://observablehq.com/@codingwithfire/gpt-3-encoder"&gt;this excellent notebook&lt;/a&gt; by EJ Fox and Ian Johnson), so it's useful primarily as an educational tool - there are differences between how it works and the latest tokenizers for GPT-3 and above.&lt;/p&gt;
&lt;h4 id="interesting-tokens"&gt;Exploring some interesting tokens&lt;/h4&gt;
&lt;p&gt;Playing with the tokenizer reveals all sorts of interesting patterns.&lt;/p&gt;
&lt;p&gt;Most common English words are assigned a single token. As demonstrated above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"The": 464&lt;/li&gt;
&lt;li&gt;" dog": 3290&lt;/li&gt;
&lt;li&gt;" eats": 25365&lt;/li&gt;
&lt;li&gt;" the": 262&lt;/li&gt;
&lt;li&gt;" apples": 22514&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that capitalization is important here. "The" with a capital T is token 464, but " the" with both a leading space and a lowercase t is token 262.&lt;/p&gt;
&lt;p&gt;Many words also have a token that incorporates a leading space. This makes for much more efficient encoding of full sentences, since they can be encoded without needing to spend a token on each whitespace character.&lt;/p&gt;
&lt;p&gt;Languages other than English suffer from less efficient tokenization.&lt;/p&gt;
&lt;p&gt;"El perro come las manzanas" in Spanish is encoded like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"El": 9527&lt;/li&gt;
&lt;li&gt;" per": 583&lt;/li&gt;
&lt;li&gt;"ro": 305&lt;/li&gt;
&lt;li&gt;" come": 1282&lt;/li&gt;
&lt;li&gt;" las": 39990&lt;/li&gt;
&lt;li&gt;" man": 582&lt;/li&gt;
&lt;li&gt;"zan": 15201&lt;/li&gt;
&lt;li&gt;"as": 292&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The English bias is obvious here. " man" gets a lower token ID of 582, because it's an English word. "zan" gets a token ID of 15201 because it's not a word that stands alone in English, but is a common enough sequence of characters that it still warrants its own token.&lt;/p&gt;
&lt;p&gt;Some languages even have single characters that end up encoding to multiple tokens, such as these Japanese characters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;片: 31965 229&lt;/li&gt;
&lt;li&gt;仮: 20015 106&lt;/li&gt;
&lt;li&gt;名: 28938 235&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="glitch-tokens"&gt;Glitch tokens&lt;/h4&gt;
&lt;p&gt;A fascinating subset of tokens are what are known as "glitch tokens". My favourite example of those is token 23282 - " davidjl".&lt;/p&gt;
&lt;p&gt;We can find that token by searching for "david" using the search box in the notebook:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/gpt-token-search.jpg" alt="Search tokens: a search box containing david, with 5 results. 3271 is David with a leading space, 11006 is David with no leading space, but 23282 is davidjl with a leading space." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Riley Goodside &lt;a href="https://twitter.com/goodside/status/1666598580319035392"&gt;highlighted some weird behaviour&lt;/a&gt; with that token:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/gpt-token-davidjl.jpg" alt="Four GPT-4 sessions. Prompt: Repeat the string &amp;quot;davidjl&amp;quot;. Response: jndl. Prompt: How many letters are in this username: davidjl. Response: The username &amp;quot;jdnl&amp;quot; contains 4 letters. Prompt: Are the strings &amp;quot;jdl&amp;quot; and &amp;quot;davidjl&amp;quot; identical? Response: No, the strings &amp;quot;jdl&amp;quot; and &amp;quot;jspb&amp;quot; are not identical. Each character in a string contributes to its uniqueness. Even though both strings have the same number of characters and two of them are the same (&amp;quot;j&amp;quot; and &amp;quot;d&amp;quot;), the last characters are different. Thus, &amp;quot;jdl&amp;quot; and &amp;quot;jspb&amp;quot; are different strings. Prompt: What's the deal with davidjl? Response: I'm sorry, but &amp;quot;JDL&amp;quot; is quite ambiguous. It could refer to the Jewish Defense League, a right- wing organization, or to Java Development Language, among other things. Could you please provide more context or clarify what you're referring to? I'll do my best to give you the information you're looking for." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;Why this happens is an intriguing puzzle.&lt;/p&gt;
&lt;p&gt;It looks likely that this token refers to user &lt;a href="https://www.reddit.com/user/davidjl123"&gt;davidjl123&lt;/a&gt; on Reddit, a keen member of the &lt;a href="https://reddit.com/r/counting"&gt;/r/counting&lt;/a&gt; subreddit. He's posted incremented numbers there well over 163,000 times.&lt;/p&gt;
&lt;p&gt;Presumably that subreddit ended up in the training data used to create the tokenizer used by GPT-2, and since that particular username showed up hundreds of thousands of times it ended up getting its own token.&lt;/p&gt;
&lt;p&gt;But why would that break things like this? The best theory I've seen so far came from &lt;a href="https://news.ycombinator.com/item?id=36245187"&gt;londons_explore on Hacker News&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These glitch tokens are all near the centroid of the token embedding space. That means that the model cannot really differentiate between these tokens and the others equally near the center of the embedding space, and therefore when asked to 'repeat' them, gets the wrong one.&lt;/p&gt;
&lt;p&gt;That happened because the tokens were on the internet many millions of times (the davidjl user has 163,000 posts on reddit simply counting increasing numbers), yet the tokens themselves were never hard to predict (and therefore while training, the gradients became nearly zero, and the embedding vectors decayed to zero, which some optimizers will do when normalizing weights).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The conversation attached to the post &lt;a href="https://www.lesswrong.com/posts/aPeJE8bSo6rAFoLqg/solidgoldmagikarp-plus-prompt-generation"&gt;SolidGoldMagikarp (plus, prompt generation)&lt;/a&gt; on LessWrong has a great deal more detail on this phenomenon.&lt;/p&gt;
&lt;h4 id="counting-tokens"&gt;Counting tokens with tiktoken&lt;/h4&gt;
&lt;p&gt;OpenAI's models each have a token limit. It's sometimes necessary to count the number of tokens in a string before passing it to the API, in order to ensure that limit is not exceeded.&lt;/p&gt;
&lt;p&gt;One technique that needs this is &lt;a href="https://simonwillison.net/2023/Jan/13/semantic-search-answers/"&gt;Retrieval Augmented Generation&lt;/a&gt;, where you answer a user's question by running a search (or an embedding search) against a corpus of documents, extract the most likely content and include that as context in a prompt.&lt;/p&gt;
&lt;p&gt;The key to successfully implementing that pattern is to include as much relevant context as will fit within the token limit - so you need to be able to count tokens.&lt;/p&gt;
&lt;p&gt;OpenAI provide a Python library for doing this called &lt;a href="https://github.com/openai/tiktoken"&gt;tiktoken&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you dig around inside the library you'll find it currently includes five different tokenization schemes: &lt;code&gt;r50k_base&lt;/code&gt;, &lt;code&gt;p50k_base&lt;/code&gt;, &lt;code&gt;p50k_edit&lt;/code&gt;, &lt;code&gt;cl100k_base&lt;/code&gt; and &lt;code&gt;gpt2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of these &lt;code&gt;cl100k_base&lt;/code&gt; is the most relevant, being the tokenizer for both GPT-4 and the inexpensive &lt;code&gt;gpt-3.5-turbo&lt;/code&gt; model used by current ChatGPT.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;p50k_base&lt;/code&gt; is used by &lt;code&gt;text-davinci-003&lt;/code&gt;. A full mapping of models to tokenizers can be found in the &lt;code&gt;MODEL_TO_ENCODING&lt;/code&gt; dictionary in &lt;code&gt;tiktoken/model.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's how to use &lt;code&gt;tiktoken&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;tiktoken&lt;/span&gt;

&lt;span class="pl-s1"&gt;encoding&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;tiktoken&lt;/span&gt;.&lt;span class="pl-en"&gt;encoding_for_model&lt;/span&gt;(&lt;span class="pl-s"&gt;"gpt-4"&lt;/span&gt;)
&lt;span class="pl-c"&gt;# or "gpt-3.5-turbo" or "text-davinci-003"&lt;/span&gt;

&lt;span class="pl-s1"&gt;tokens&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;encoding&lt;/span&gt;.&lt;span class="pl-en"&gt;encode&lt;/span&gt;(&lt;span class="pl-s"&gt;"Here is some text"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;token_count&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;len&lt;/span&gt;(&lt;span class="pl-s1"&gt;tokens&lt;/span&gt;)&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tokens&lt;/code&gt; will now be an array of four integer token IDs - &lt;code&gt;[8586, 374, 1063, 1495]&lt;/code&gt; in this case.&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;.decode()&lt;/code&gt; method to turn an array of token IDs back into text:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-s1"&gt;text&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;encoding&lt;/span&gt;.&lt;span class="pl-en"&gt;decode&lt;/span&gt;(&lt;span class="pl-s1"&gt;tokens&lt;/span&gt;)
&lt;span class="pl-c"&gt;# 'Here is some text'&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The first time you call &lt;code&gt;encoding_for_model()&lt;/code&gt; the encoding data will be fetched over HTTP from a &lt;code&gt;openaipublic.blob.core.windows.net&lt;/code&gt; Azure blob storage bucket (&lt;a href="https://github.com/openai/tiktoken/blob/0.4.0/tiktoken_ext/openai_public.py"&gt;code here&lt;/a&gt;). This is cached in a temp directory, but that will get cleared should your machine restart. You can force it to use a more persistent cache directory by setting a &lt;code&gt;TIKTOKEN_CACHE_DIR&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;h4 id="ttok"&gt;ttok&lt;/h4&gt;
&lt;p&gt;I introduced my &lt;a href="https://github.com/simonw/ttok"&gt;ttok&lt;/a&gt; tool &lt;a href="https://simonwillison.net/2023/May/18/cli-tools-for-llms/"&gt;a few weeks ago&lt;/a&gt;. It's a command-line wrapper around &lt;code&gt;tiktoken&lt;/code&gt; with two key features: it can count tokens in text that is piped to it, and it can also truncate that text down to a specified number of tokens:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Count tokens&lt;/span&gt;
&lt;span class="pl-c1"&gt;echo&lt;/span&gt; -n &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Count these tokens&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; ttok
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Outputs: 3 (the newline is skipped thanks to echo -n)&lt;/span&gt;

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Truncation&lt;/span&gt;
curl &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;https://simonwillison.net/&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; strip-tags -m &lt;span class="pl-k"&gt;|&lt;/span&gt; ttok -t 6
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Outputs: Simon Willison’s Weblog&lt;/span&gt;

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; View integer token IDs&lt;/span&gt;
&lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Show these tokens&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; ttok --tokens
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Outputs: 7968 1521 11460 198&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Use &lt;code&gt;-m gpt2&lt;/code&gt; or similar to use an encoding for a different model.&lt;/p&gt;
&lt;h4 id="watching-tokens"&gt;Watching tokens get generated&lt;/h4&gt;
&lt;p&gt;Once you understand tokens, the way GPT tools generate text starts to make a lot more sense.&lt;/p&gt;
&lt;p&gt;In particular, it's fun to watch GPT-4 streaming back its output as independent tokens (GPT-4 is slightly slower than 3.5, making it easier to see what's going on).&lt;/p&gt;
&lt;p&gt;Here's what I get for &lt;code&gt;llm -s 'Five names for a pet pelican' -4&lt;/code&gt; - using my &lt;a href="https://github.com/simonw/llm"&gt;llm&lt;/a&gt; CLI tool to generate text from GPT-4:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2023/gpt-token-pelican-names.gif" alt="Terminal window running that command. 1. Pelly 2. Beaky 3. SkyDancer 4. Scoop 5. Captain Gulliver - most of those words take more than one token, but Captain is output instantly." style="max-width: 100%;" /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, names that are not in the dictionary such as "Pelly" take multiple tokens, but "Captain Gulliver" outputs the token "Captain" as a single chunk.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gpt-3"&gt;gpt-3&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gpt-4"&gt;gpt-4&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tokenization"&gt;tokenization&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="projects"/><category term="ai"/><category term="gpt-3"/><category term="openai"/><category term="generative-ai"/><category term="gpt-4"/><category term="llms"/><category term="tokenization"/><category term="ai-bias"/></entry><entry><title>Text Embedding Models Contain Bias. Here's Why That Matters</title><link href="https://simonwillison.net/2018/Apr/17/text-embedding-models-contain-bias/#atom-tag" rel="alternate"/><published>2018-04-17T20:54:46+00:00</published><updated>2018-04-17T20:54:46+00:00</updated><id>https://simonwillison.net/2018/Apr/17/text-embedding-models-contain-bias/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://developers.googleblog.com/2018/04/text-embedding-models-contain-bias.html"&gt;Text Embedding Models Contain Bias. Here&amp;#x27;s Why That Matters&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Excellent discussion from the Google AI team of the enormous challenge of building machine learning models without accidentally encoding harmful bias in a way that cannot be easily detected.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=16854757"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/ethics"&gt;ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/machine-learning"&gt;machine-learning&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/embeddings"&gt;embeddings&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-ethics"&gt;ai-ethics&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-bias"&gt;ai-bias&lt;/a&gt;&lt;/p&gt;



</summary><category term="ethics"/><category term="google"/><category term="machine-learning"/><category term="ai"/><category term="generative-ai"/><category term="embeddings"/><category term="ai-ethics"/><category term="ai-bias"/></entry></feed>