<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bryanyzhu.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bryanyzhu.github.io/" rel="alternate" type="text/html" /><updated>2026-04-09T22:58:53-07:00</updated><id>https://bryanyzhu.github.io/feed.xml</id><title type="html">Yi Zhu</title><subtitle>Cofounder at Boson AI</subtitle><author><name>Yi Zhu</name><email>yizhu59@gmail.com</email></author><entry><title type="html">Chatbot Arena and the Elo rating system - Part 2</title><link href="https://bryanyzhu.github.io/posts/2024-08-16-elo-part2/" rel="alternate" type="text/html" title="Chatbot Arena and the Elo rating system - Part 2" /><published>2024-08-16T00:00:00-07:00</published><updated>2024-08-16T00:00:00-07:00</updated><id>https://bryanyzhu.github.io/posts/elo-part2</id><content type="html" xml:base="https://bryanyzhu.github.io/posts/2024-08-16-elo-part2/"><![CDATA[<p>In our <a href="https://bryanyzhu.github.io/posts/2024-06-20-elo-part1/">previous blog post on Elo rating system</a>, we introduced the basics of the Elo rating system and its online linear update algorithm, hereafter referred to as “online Elo”. However, we identified a significant concern with online Elo: its instability and tendency to bias toward recent results. For example, a demonstration from Chatbot Arena showed substantial shifts in model ratings when Elo was recalculated using the reverse order of matches.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/reverse_order_online_elo.png" alt="reverse_online_elo" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">Online Elo ranking is not stable. Image source: <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH#scrollTo=c0KvFVr-nR2Q" target="_blank">notebook from Chatbot Arena</a></figcaption>
</figure>

<p>This instability is, of course, undesirable. While it’s true that player can learn from feedback and improve their skills (which means their ratings are changing), the assumption is that player’s improvements occur slowly. Therefore, in the short term, their ranks should stay relatively stable. In other words, no matter how we compute the score, we hope to get the same ranking despite the order of matches. So, how can we generate a stable and unique Elo ranking?</p>

<h2 id="why-does-this-happen">Why does this happen?</h2>

<p>We touched on this issue briefly in our previous post, the online Elo algorithm adjusts a player’s rating incrementally after each match, considering the match outcome and the current ratings of the opponents. Each update subsequently influences future ratings. Therefore, the sequence in which matches are processed significantly impacts the final ratings. When we reverse the order of matches, what were initially earlier matches (now processed later) are updated based on different initial conditions, which can lead to significantly altered final ratings.</p>

<p>So if the problem lies in the sequential update, why not update the ratings all at once?</p>

<h2 id="maximum-likelihood-estimation-with-bradley-terry-model">Maximum Likelihood Estimation with Bradley-Terry model</h2>

<h3 id="basics">Basics</h3>

<p>If we think about SGD again, we know that a good practice for stable optimization is to use mini-batch instead of feeding a single data sample during each model update. In the context of LLM evaluation, we often assume that the model’s capability remains static over the period being analyzed. This assumption thus allows us to utilize Maximum Likelihood Estimation (MLE) to directly fit the ratings globally.</p>

<p>But before we dive deeper, let’s clarify some fundamental concepts.</p>

<ul>
  <li>MLE might be familiar, it is a statistical method used to estimate the parameters of a model. In simpler terms, it identifies the set of parameters under which the observed data is most probable.</li>
  <li>The Bradley-Terry model is a probability model used for predicting the outcomes of pairwise comparisons. In rating systems, it’s used to estimate the relative strengths of players based on the outcomes of their matches against each other. You can find out its math formulas in this <a href="https://en.wikipedia.org/wiki/Bradley%E2%80%93Terry_model">wiki</a>, not hard to understand (very similar to the online Elo formula we have introduced in previous post).</li>
</ul>

<p>The connection between MLE and the Bradley-Terry model in the context of rating systems is quite direct. MLE is used to estimate the strength parameters of the Bradley-Terry model from the data of match results. By applying MLE, we can maximize the likelihood that the predicted outcomes under the Bradley-Terry model align with the actual observed outcomes of matches. But how exactly this is done? How is this different from online Elo?</p>

<h3 id="dive-deep-into-mle-elo">Dive deep into MLE Elo</h3>

<p>Let’s look at a python implementation below, which is borrowed from <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH">this notebook</a> from Chatbot Arena.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">compute_mle_elo</span><span class="p">(</span>
    <span class="n">df</span><span class="p">,</span> <span class="n">SCALE</span><span class="o">=</span><span class="mi">400</span><span class="p">,</span> <span class="n">BASE</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">INIT_RATING</span><span class="o">=</span><span class="mi">1000</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="bp">None</span>
<span class="p">):</span>
    <span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LogisticRegression</span>
    <span class="n">ptbl_a_win</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">pivot_table</span><span class="p">(</span>
        <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s">"winner"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"model_a"</span><span class="p">],</span>
        <span class="n">index</span><span class="o">=</span><span class="s">"model_a"</span><span class="p">,</span>
        <span class="n">columns</span><span class="o">=</span><span class="s">"model_b"</span><span class="p">,</span>
        <span class="n">aggfunc</span><span class="o">=</span><span class="s">"size"</span><span class="p">,</span>
        <span class="n">fill_value</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="c1"># if no tie, create a zero matrix
</span>    <span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s">"winner"</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="s">"tie"</span><span class="p">,</span> <span class="s">"tie (bothbad)"</span><span class="p">]))</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">ptbl_tie</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="n">ptbl_a_win</span><span class="p">.</span><span class="n">index</span><span class="p">,</span> <span class="n">columns</span><span class="o">=</span><span class="n">ptbl_a_win</span><span class="p">.</span><span class="n">columns</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">ptbl_tie</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">pivot_table</span><span class="p">(</span>
            <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s">"winner"</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="s">"tie"</span><span class="p">,</span> <span class="s">"tie (bothbad)"</span><span class="p">])],</span>
            <span class="n">index</span><span class="o">=</span><span class="s">"model_a"</span><span class="p">,</span>
            <span class="n">columns</span><span class="o">=</span><span class="s">"model_b"</span><span class="p">,</span>
            <span class="n">aggfunc</span><span class="o">=</span><span class="s">"size"</span><span class="p">,</span>
            <span class="n">fill_value</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
        <span class="p">)</span>
        <span class="n">ptbl_tie</span> <span class="o">=</span> <span class="n">ptbl_tie</span> <span class="o">+</span> <span class="n">ptbl_tie</span><span class="p">.</span><span class="n">T</span>

    <span class="n">ptbl_b_win</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">pivot_table</span><span class="p">(</span>
        <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s">"winner"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"model_b"</span><span class="p">],</span>
        <span class="n">index</span><span class="o">=</span><span class="s">"model_a"</span><span class="p">,</span>
        <span class="n">columns</span><span class="o">=</span><span class="s">"model_b"</span><span class="p">,</span>
        <span class="n">aggfunc</span><span class="o">=</span><span class="s">"size"</span><span class="p">,</span>
        <span class="n">fill_value</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
    <span class="p">)</span>
    <span class="n">ptbl_win</span> <span class="o">=</span> <span class="n">ptbl_a_win</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">ptbl_b_win</span><span class="p">.</span><span class="n">T</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">ptbl_tie</span>

    <span class="n">models</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">Series</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">index</span><span class="p">)),</span> <span class="n">index</span><span class="o">=</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">index</span><span class="p">)</span>

    <span class="n">p</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">models</span><span class="p">)</span>
    <span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">([</span><span class="n">p</span> <span class="o">*</span> <span class="p">(</span><span class="n">p</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="p">,</span> <span class="n">p</span><span class="p">])</span>
    <span class="n">Y</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">p</span> <span class="o">*</span> <span class="p">(</span><span class="n">p</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span>

    <span class="n">cur_row</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">sample_weights</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">m_a</span> <span class="ow">in</span> <span class="n">ptbl_win</span><span class="p">.</span><span class="n">index</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">m_b</span> <span class="ow">in</span> <span class="n">ptbl_win</span><span class="p">.</span><span class="n">columns</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">m_a</span> <span class="o">==</span> <span class="n">m_b</span><span class="p">:</span>
                <span class="k">continue</span>
            <span class="c1"># if nan skip
</span>            <span class="k">if</span> <span class="n">math</span><span class="p">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">m_a</span><span class="p">,</span> <span class="n">m_b</span><span class="p">])</span> <span class="ow">or</span> <span class="n">math</span><span class="p">.</span><span class="n">isnan</span><span class="p">(</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">m_b</span><span class="p">,</span> <span class="n">m_a</span><span class="p">]):</span>
                <span class="k">continue</span>
            <span class="n">X</span><span class="p">[</span><span class="n">cur_row</span><span class="p">,</span> <span class="n">models</span><span class="p">[</span><span class="n">m_a</span><span class="p">]]</span> <span class="o">=</span> <span class="o">+</span><span class="n">math</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">BASE</span><span class="p">)</span>
            <span class="n">X</span><span class="p">[</span><span class="n">cur_row</span><span class="p">,</span> <span class="n">models</span><span class="p">[</span><span class="n">m_b</span><span class="p">]]</span> <span class="o">=</span> <span class="o">-</span><span class="n">math</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">BASE</span><span class="p">)</span>
            <span class="n">Y</span><span class="p">[</span><span class="n">cur_row</span><span class="p">]</span> <span class="o">=</span> <span class="mf">1.0</span>
            <span class="n">sample_weights</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">m_a</span><span class="p">,</span> <span class="n">m_b</span><span class="p">])</span>

            <span class="n">X</span><span class="p">[</span><span class="n">cur_row</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">models</span><span class="p">[</span><span class="n">m_a</span><span class="p">]]</span> <span class="o">=</span> <span class="n">math</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">BASE</span><span class="p">)</span>
            <span class="n">X</span><span class="p">[</span><span class="n">cur_row</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">models</span><span class="p">[</span><span class="n">m_b</span><span class="p">]]</span> <span class="o">=</span> <span class="o">-</span><span class="n">math</span><span class="p">.</span><span class="n">log</span><span class="p">(</span><span class="n">BASE</span><span class="p">)</span>
            <span class="n">Y</span><span class="p">[</span><span class="n">cur_row</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mf">0.0</span>
            <span class="n">sample_weights</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">ptbl_win</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">m_b</span><span class="p">,</span> <span class="n">m_a</span><span class="p">])</span>
            <span class="n">cur_row</span> <span class="o">+=</span> <span class="mi">2</span>
    <span class="n">X</span> <span class="o">=</span> <span class="n">X</span><span class="p">[:</span><span class="n">cur_row</span><span class="p">]</span>
    <span class="n">Y</span> <span class="o">=</span> <span class="n">Y</span><span class="p">[:</span><span class="n">cur_row</span><span class="p">]</span>

    <span class="n">lr</span> <span class="o">=</span> <span class="n">LogisticRegression</span><span class="p">(</span><span class="n">fit_intercept</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">penalty</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">tol</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span>
    <span class="n">lr</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="n">sample_weights</span><span class="p">)</span>
    <span class="n">elo_scores</span> <span class="o">=</span> <span class="n">SCALE</span> <span class="o">*</span> <span class="n">lr</span><span class="p">.</span><span class="n">coef_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">INIT_RATING</span>
    <span class="k">return</span> <span class="n">pd</span><span class="p">.</span><span class="n">Series</span><span class="p">(</span><span class="n">elo_scores</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="n">models</span><span class="p">.</span><span class="n">index</span><span class="p">).</span><span class="n">sort_values</span><span class="p">(</span><span class="n">ascending</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</code></pre></div></div>

<p>This function include 3 stages. For the first stage until <code class="language-plaintext highlighter-rouge">ptbl_win = ptbl_a_win * 2 + ptbl_b_win.T * 2 + ptbl_tie</code>, we are preparing data tables from the match outcomes. <code class="language-plaintext highlighter-rouge">ptbl_win</code> basically combines wins and ties into a single table that effectively represents the interaction matrix between all pairs of models. The reason for doubling the count of wins in both <code class="language-plaintext highlighter-rouge">ptbl_a_win</code> and <code class="language-plaintext highlighter-rouge">ptbl_b_win.T</code> is to emphasize the importance of each win equally for both model_a and model_b, ensuring that no single win is underrepresented.</p>

<p>For the second stage until <code class="language-plaintext highlighter-rouge">Y = Y[:cur_row]</code>, we are setting up logistic regression inputs. <code class="language-plaintext highlighter-rouge">X</code> is filled with the logarithm of the base, encoding who is competing against whom by setting corresponding model indices to positive or negative values. <code class="language-plaintext highlighter-rouge">Y</code> is set to 1 or 0, representing the outcome of the match (1 if the row corresponds to a win by model_a, 0 for model_b). Here, <code class="language-plaintext highlighter-rouge">sample_weights</code> is an array that collects the weight of each sample based on the number of times a particular match-up occurs.</p>

<p>For the last stage, we simply use logistic regression to fit the data. the final <code class="language-plaintext highlighter-rouge">lr.coef_</code> contains the estimated skill levels of the players on the log-odds scale. These coefficients are the result of the optimization process that maximizes the likelihood of the observed match outcomes given the skill levels of the players. The final output is a series of Elo scores indexed by model names, sorted in descending order to show the strongest model at the top.</p>

<p>Unlike the sequential update in the online Elo system, MLE with the Bradley-Terry model considers all match outcomes simultaneously. This global optimization approach reduces the dependency on the order of matches, leading to more stable and consistent estimates of player strengths. In fact, if we reverse the order of matches or shuffle the order, the MLE Elo ranking will mostly stay the same.</p>

<h2 id="compute-bootstrap-confidence-intervals">Compute bootstrap confidence intervals</h2>

<p>Although MLE Elo is simple and stable, in order to add robustness to analysis, people often use bootstrapping to compute confidence internals to understand the statistical significance. But hold on, what is confidence interval and what does bootstrap mean?</p>

<p>A confidence interval (CI) is a range of values, derived from the data, that is likely to contain the value of an unknown population parameter. For instance, in the context of Elo scores, a 95% confidence interval around a score indicates that, if the procedure were repeated many times, 95% of the confidence intervals calculated would contain the true Elo score. It gives an idea of the uncertainty around the estimated value.</p>

<p>Bootstrap is a powerful statistical technique used to estimate the uncertainty of a statistic (like a mean, median, or, in this case, Elo scores) by resampling the data. In essence, it involves repeatedly drawing samples, with replacement, from the observed data set and recalculating the statistic for each sample. This generates an empirical distribution of the statistic which can then be used to compute confidence intervals or test hypotheses. By using bootstrap, it assesses how stable the Elo scores are: if the matches (data points) had come out differently, would we get a similar ranking and score?</p>

<p>Let’s look at a python implementation below, which is borrowed from <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH">this notebook</a> from Chatbot Arena.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_bootstrap_result</span><span class="p">(</span><span class="n">battles</span><span class="p">,</span> <span class="n">func_compute_elo</span><span class="p">,</span> <span class="n">num_round</span><span class="p">):</span>
    <span class="n">rows</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">tqdm</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="n">num_round</span><span class="p">),</span> <span class="n">desc</span><span class="o">=</span><span class="s">"bootstrap"</span><span class="p">):</span>
        <span class="n">rows</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">func_compute_elo</span><span class="p">(</span><span class="n">battles</span><span class="p">.</span><span class="n">sample</span><span class="p">(</span><span class="n">frac</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">replace</span><span class="o">=</span><span class="bp">True</span><span class="p">)))</span>
    <span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">rows</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">.</span><span class="n">median</span><span class="p">().</span><span class="n">sort_values</span><span class="p">(</span><span class="n">ascending</span><span class="o">=</span><span class="bp">False</span><span class="p">).</span><span class="n">index</span><span class="p">]</span>
    
<span class="n">BOOTSTRAP_ROUNDS</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">bootstrap_elo_lu</span> <span class="o">=</span> <span class="n">get_bootstrap_result</span><span class="p">(</span><span class="n">battles</span><span class="p">,</span> <span class="n">compute_mle_elo</span><span class="p">,</span> <span class="n">BOOTSTRAP_ROUNDS</span><span class="p">)</span>
</code></pre></div></div>

<p>The implementation above is straightforward. Basically, it loops num_round times as defined by BOOTSTRAP_ROUNDS. In each iteration, it resamples the dataset with replacement <code class="language-plaintext highlighter-rouge">battles.sample(frac=1.0, replace=True)</code>, which means it creates a new dataset the same size as the original but some battles may be repeated and others omitted. It then computes Elo scores using the provided function <code class="language-plaintext highlighter-rouge">func_compute_elo</code> for the resampled dataset and stores the result.</p>

<p>It’s true that some battles may be duplicated in a bootstrap sample, which could introduce bias if certain players are overrepresented in these duplicates. But the purpose of bootstrap resampling is to create many such samples and then analyze the distribution of the computed Elo ratings. The bias introduced by any single bootstrap sample is mitigated by averaging over many samples.</p>

<p>If we visualize the confidence intervals of all models, we can see that the statistical range using MLE ELo is small (always centers around its median).</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/mle_elo_ci_part2.png" alt="mle_elo_ci_part2" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">MLE Elo ranking is more stable than online Elo. Image source: <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH#scrollTo=c0KvFVr-nR2Q" target="_blank">notebook from Chatbot Arena</a></figcaption>
</figure>

<p>However, if we change back to online Elo, we can see the statistical range suddenly increases a lot. In particular, their confidence intervals overlap significantly, which suggests that the difference in their Elo scores might not be statistically significant. In other words, the observed difference could be due to random variations in the data (like specific matchups, outliers, or other noise) rather than a true difference in model’s performance.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/online_elo_ci_part2.png" alt="online_elo_ci_part2" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">Online Elo ranking is not stable, the difference in models' Elo scores might not be statistically significant. Image source: <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH#scrollTo=c0KvFVr-nR2Q" target="_blank">notebook from Chatbot Arena</a></figcaption>
</figure>

<h2 id="some-notes">Some notes</h2>

<h3 id="can-i-use-mle-with-bradley-terry-model-for-data-beyond-pair-wise-comparison">Can I use MLE with Bradley-Terry model for data beyond pair-wise comparison?</h3>

<p>Not really. If the comparisons are not pairwise, the Bradley-Terry model may not be applicable as it stands because it cannot process multiple comparisons simultaneously or scenarios where the structure of competition is not strictly one-on-one. For instance, in events or competitions where outcomes involve more than two participants at a time (like races or multi-player games), alternative models are needed.</p>

<h3 id="any-other-methods-to-compute-elo">Any other methods to compute elo?</h3>

<p>There are many algorithms (at least extensions) to compute Elo score. One popular method, termed whole history rating (WHR),  is specifically designed to more accurately reflect changes in a player’s performance over time.</p>

<p>Like we have mentioned, MLE Elo typically computes ratings based on the assumption that a player’s skill level is static or changes very slowly. It treats all matches with equal weight regardless of when they occurred. However, for some situations where player performance may change significantly over time, such as in long career sports or games, academic or professional development tracking, etc., it is better to explicitly model changes in player strength over time, so here comes the whole history rating.</p>

<p>For detailed implementations, we refer you to this great <a href="https://github.com/pfmonville/whole_history_rating">Github repo</a>, which you can directly pip install and import <code class="language-plaintext highlighter-rouge">whole_history_rating</code> to compute. Simply put, WHR calculates ratings based on all past results, taking into account the time when each match was played. providing a more nuanced and responsive rating system that adjusts as more data becomes available.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">whr</span> <span class="kn">import</span> <span class="n">whole_history_rating</span>

<span class="n">whr</span> <span class="o">=</span> <span class="n">whole_history_rating</span><span class="p">.</span><span class="n">Base</span><span class="p">()</span>

<span class="n">whr</span><span class="p">.</span><span class="n">create_game</span><span class="p">(</span><span class="s">"shusaku"</span><span class="p">,</span> <span class="s">"shusai"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">whr</span><span class="p">.</span><span class="n">create_game</span><span class="p">(</span><span class="s">"shusaku"</span><span class="p">,</span> <span class="s">"shusai"</span><span class="p">,</span> <span class="s">"W"</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">whr</span><span class="p">.</span><span class="n">create_game</span><span class="p">(</span><span class="s">"shusaku"</span><span class="p">,</span> <span class="s">"shusai"</span><span class="p">,</span> <span class="s">"W"</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>

<span class="n">whr</span><span class="p">.</span><span class="n">auto_iterate</span><span class="p">(</span><span class="n">time_limit</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">precision</span><span class="o">=</span><span class="mf">1e-3</span><span class="p">,</span> <span class="n">batch_size</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>

<span class="n">ratings</span> <span class="o">=</span> <span class="n">whr</span><span class="p">.</span><span class="n">get_ordered_ratings</span><span class="p">(</span><span class="n">current</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">compact</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</code></pre></div></div>

<p>This code snippet starts by importing the library and initializing the base WHR object. Then adding games to the system using <code class="language-plaintext highlighter-rouge">create_game()</code> method. It takes the names of the black and white players, the winner (‘B’ for black, ‘W’ for white), the day number, and an optional handicap (generally less than 500 elo). To emphasize, the day number here is to improve the temporal awareness. Finally, the WHR algorithm allows for iterative refinement to achieve accurate and stable ratings, and retrieve all ratings in order.</p>

<p>However for LLMs, their capabilities are relatively stable once they are done training. This is within the assumption of MLE Elo that player’s skill level is static or changes very slowly. That is why in most situations of LLM evaluation, people just use MLE Elo due to its simpleness and stableness.</p>

<h3 id="why-do-people-compute-win-rate">Why do people compute win rate?</h3>

<p>Win rate is a statistical measure that represents the percentage of games, matches, or competitions that a player wins over a certain period or across a series of events. It is calculated as the number of wins divided by the total number of matches played, often expressed as a percentage. Thus, it offers a straightforward, easily understood metric of success, which complements Elo rating to make the evaluation more comprehensive.</p>

<p>In addition, win rates can also highlight anomalies or interesting trends that Elo might not capture. For instance, a player might have a high Elo rating but a surprisingly low win rate, like in a scenario that the player did 50 matches,</p>
<ul>
  <li>Wins: 15 (Against top 20 players mostly)</li>
  <li>Losses: 35 (Loses more frequently to lower-ranked players)</li>
  <li>Win Rate: 30%</li>
  <li>Elo Rating: High (Due to wins against top players)</li>
</ul>

<p>This could indicate issues such as inconsistency in performance or also have psychological factors at play, such as greater motivation or focus against better-known players, while underestimating or lacking the same drive against lower-ranked players.</p>

<p>On the other hand, we can use win rate to gain insight into the accuracy and quality of the Elo rating system. This is because utilizing Elo ratings allows us to predict win probabilities. If the predicted win rate match closely with the actual win rate, it means the Elo rating system is is high quality.</p>

<h2 id="summary">Summary</h2>

<p>At this point, we have discussed MLE Elo, win rate, and confidence interval by bootstrapping, this should cover most of the evaluation scenarios, not just for LLM.</p>]]></content><author><name>Yi Zhu</name><email>yizhu59@gmail.com</email></author><category term="AI" /><category term="LLM evaluation" /><category term="Elo" /><category term="Chatbot arena" /><category term="Maximum Likelihood Estimation" /><category term="Bradley-Terry model" /><category term="Bootstrap" /><category term="Win rate" /><summary type="html"><![CDATA[In our previous blog post on Elo rating system, we introduced the basics of the Elo rating system and its online linear update algorithm, hereafter referred to as “online Elo”. However, we identified a significant concern with online Elo: its instability and tendency to bias toward recent results. For example, a demonstration from Chatbot Arena showed substantial shifts in model ratings when Elo was recalculated using the reverse order of matches.]]></summary></entry><entry><title type="html">Chatbot Arena and the Elo rating system - Part 1</title><link href="https://bryanyzhu.github.io/posts/2024-06-20-elo-part1/" rel="alternate" type="text/html" title="Chatbot Arena and the Elo rating system - Part 1" /><published>2024-06-20T00:00:00-07:00</published><updated>2024-06-20T00:00:00-07:00</updated><id>https://bryanyzhu.github.io/posts/elo-part1</id><content type="html" xml:base="https://bryanyzhu.github.io/posts/2024-06-20-elo-part1/"><![CDATA[<p><a href="https://lmsys.org/blog/2023-05-03-arena/">Chatbot Arena</a>, developed by members from LMSYS and UC Berkeley SkyLab, is a benchmark platform designed to evaluate large language models (LLMs) through anonymous, randomized battles in a crowdsourced environment. Launched in May 2023, it has been continuously updated to reflect the latest advancements in the field. <a href="https://chat.lmsys.org/?leaderboard">The platform’s leaderboard</a> is widely regarded as one of the most credible sources for ranking LLMs. The screenshot below highlights the competitive landscape featuring major players in the LLM space.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/arena_leaderboard_0620.png" alt="leaderboard" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">A screenshot of the leaderboard of Chatbot Arena as of 06/20/2024</figcaption>
</figure>

<p>But how do we get this leaderboard? What exactly is the Arena Elo score? Is this ranking manually decided by a panel of experts? How can a newly released model get so many votes and climb the ranks so quickly? And why do people trust this leaderboard so much? The answer to all these questions lies in the Elo rating system, a fascinating method used to rank competitors in a variety of games and sports.</p>

<p>In this blog post, we’ll dive into the Elo rating system and explore how it works. This is the first part of a series where we’ll break down the basics and show you why it’s such a popular way to rank players – and chatbots!</p>

<h2 id="why-elo-rating-system">Why Elo rating system?</h2>

<p>In the quest to identify the best models or to determine which ones outperform others, an impartial and reliable leaderboard becomes essential. One way to build such a leaderboard is if you can compute some metrics like accuracy and simply rank the models based on accuracy scores from high to low. Benchmarking LLMs, however, poses significant challenges due to the open-ended nature of user queries. Traditional metrics fall short in evaluating these models automatically, as they must account for numerous perspectives and the complexities of nuanced responses.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/user_queries_elo_part1.png" alt="user_query" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">A screenshot of ChatGPT.com which shows the open-ended nature of user queries</figcaption>
</figure>

<p>While some literature suggests using AI models as judges—like the popular MTBench [1], which utilizes GPT-4 as the evaluator—this approach has limitations. AI judges often struggle to grasp the subtleties in long and complex responses, especially in real-world use cases. This is because they don’t have feelings, motives and values like humans do. Simply put, they are not perfectly aligned with us yet. Thus, human evaluation remains indispensable. Platforms like Chatbot Arena leverage crowdsourcing to facilitate pair-wise comparisons, where models are pitted against each other in “battles” to determine which one performs better.</p>

<p>To convert these pair-wise comparisons into a meaningful ranking, we turn to the <a href="https://en.wikipedia.org/wiki/Elo_rating_system">Elo rating system</a>. The Elo rating system is particularly well-suited for this purpose due to its advantageous properties in benchmarking based on pairwise comparisons:</p>

<ul>
  <li><strong>Scalability:</strong> The Elo rating system can handle a large number of models efficiently. It doesn’t require extensive data for every possible model pair, making it feasible to benchmark numerous models.</li>
  <li><strong>Incrementality:</strong> New models can be evaluated with relatively few trials. This feature allows for quick integration and assessment of new entries into the ranking system.</li>
  <li><strong>Unique Order:</strong> The Elo system provides a clear, unique ranking for all models. For any two models, it can determine which one ranks higher or if they are tied, ensuring a straightforward and comprehensible leaderboard.</li>
</ul>

<p>By leveraging the Elo rating system, we can maintain a dynamic and accurate leaderboard that reflects the performance of various models based on comprehensive pair-wise comparisons.</p>

<h2 id="what-is-elo-rating-system">What is Elo rating system?</h2>

<p>The Elo rating system is a widely recognized method for calculating the relative skill levels of players in zero-sum games, including chess, e-sports, and now, LLM evaluations. A zero-sum game, in game theory, is a situation where the total amount of resources available is fixed. Any gain by one player results in a loss by another player, meaning the sum of the gains and losses among all players is zero. For one player to succeed, others must fail.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://64.media.tumblr.com/dbe30d3edd8792c130f167d07b066210/26d1ab3611d6a1f1-63/s500x750/02684e0d2f13134fea652cb629cd53de203200b6.gif" alt="chess" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">The Queen's Gambit. Image source: <a href="https://www.tumblr.com/victorias-imagination/633998565888393216/the-queens-gambit-on-netflix" target="_blank">tumblr</a></figcaption>
</figure>

<p>In the context of LLM competitions, the Elo rating system can be used to evaluate and rank models based on their performance in head-to-head comparisons. Intuitively, there are three steps:</p>

<ol>
  <li><strong>Initial Scores:</strong> Every model starts with an initial score, commonly set at 1000.</li>
  <li><strong>Competitions:</strong> When two models compete, and model A’s response is preferred over model B’s response, model A “wins” and takes some points from model B.</li>
  <li><strong>Score Adjustments:</strong> After numerous matches, models that consistently perform well and align better with human preferences (e.g., like GPT-4) will have higher scores than their initial rating. Conversely, models that perform poorly will have lower scores, as they lose points to stronger models. This will naturally lead to the leaderboard ranking.</li>
</ol>

<p>But how exactly this works? How many scores should model A take from model B? How does the system work for multiple models and update their rankings in a continuous and stable manner?</p>

<h2 id="dive-deep-into-the-elo-rating-system">Dive deep into the Elo rating system</h2>

<p>To answer the above questions, let’s look at the simplest online linear update algorithm to compute Elo ratings. The python implementation can be seen below, which is borrowed from <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH">this notebook</a> from Chatbot Arena.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">compute_online_elo</span><span class="p">(</span><span class="n">battles</span><span class="p">,</span> <span class="n">K</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">SCALE</span><span class="o">=</span><span class="mi">400</span><span class="p">,</span> <span class="n">BASE</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">INIT_RATING</span><span class="o">=</span><span class="mi">1000</span><span class="p">):</span>
    <span class="n">rating</span> <span class="o">=</span> <span class="n">defaultdict</span><span class="p">(</span><span class="k">lambda</span><span class="p">:</span> <span class="n">INIT_RATING</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">rd</span><span class="p">,</span> <span class="n">model_a</span><span class="p">,</span> <span class="n">model_b</span><span class="p">,</span> <span class="n">winner</span> <span class="ow">in</span> <span class="n">battles</span><span class="p">[[</span><span class="s">'model_a'</span><span class="p">,</span> <span class="s">'model_b'</span><span class="p">,</span> <span class="s">'winner'</span><span class="p">]].</span><span class="n">itertuples</span><span class="p">():</span>
        <span class="n">ra</span> <span class="o">=</span> <span class="n">rating</span><span class="p">[</span><span class="n">model_a</span><span class="p">]</span>
        <span class="n">rb</span> <span class="o">=</span> <span class="n">rating</span><span class="p">[</span><span class="n">model_b</span><span class="p">]</span>
        <span class="n">ea</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">BASE</span> <span class="o">**</span> <span class="p">((</span><span class="n">rb</span> <span class="o">-</span> <span class="n">ra</span><span class="p">)</span> <span class="o">/</span> <span class="n">SCALE</span><span class="p">))</span>
        <span class="n">eb</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">/</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">BASE</span> <span class="o">**</span> <span class="p">((</span><span class="n">ra</span> <span class="o">-</span> <span class="n">rb</span><span class="p">)</span> <span class="o">/</span> <span class="n">SCALE</span><span class="p">))</span>
        <span class="k">if</span> <span class="n">winner</span> <span class="o">==</span> <span class="s">"model_a"</span><span class="p">:</span>
            <span class="n">sa</span> <span class="o">=</span> <span class="mi">1</span>
        <span class="k">elif</span> <span class="n">winner</span> <span class="o">==</span> <span class="s">"model_b"</span><span class="p">:</span>
            <span class="n">sa</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">elif</span> <span class="n">winner</span> <span class="o">==</span> <span class="s">"tie"</span> <span class="ow">or</span> <span class="n">winner</span> <span class="o">==</span> <span class="s">"tie (bothbad)"</span><span class="p">:</span>
            <span class="n">sa</span> <span class="o">=</span> <span class="mf">0.5</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="sa">f</span><span class="s">"unexpected vote </span><span class="si">{</span><span class="n">winner</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="n">rating</span><span class="p">[</span><span class="n">model_a</span><span class="p">]</span> <span class="o">+=</span> <span class="n">K</span> <span class="o">*</span> <span class="p">(</span><span class="n">sa</span> <span class="o">-</span> <span class="n">ea</span><span class="p">)</span>
        <span class="n">rating</span><span class="p">[</span><span class="n">model_b</span><span class="p">]</span> <span class="o">+=</span> <span class="n">K</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">sa</span> <span class="o">-</span> <span class="n">eb</span><span class="p">)</span>
</code></pre></div></div>

<p>Given a collection of battle results <code class="language-plaintext highlighter-rouge">battles</code>, we loop through them to update models’ rankings. For each battle, we first compute the expected outcome for each model, denoted as <code class="language-plaintext highlighter-rouge">ea</code> and <code class="language-plaintext highlighter-rouge">eb</code>. Then we compare these expected outcomes with the actual competition results <code class="language-plaintext highlighter-rouge">sa</code>, and update the models’ ratings <code class="language-plaintext highlighter-rouge">rating[model_a]</code> and <code class="language-plaintext highlighter-rouge">rating[model_b]</code> respectively. There are two key parts we need to elaborate: (1) computing the expected outcome for each model, and (2) updating the models’ ratings.</p>

<h3 id="computing-the-expected-outcome-for-each-model">Computing the expected outcome for each model</h3>

<p>First of all, why do we want to compute the expected outcome? The expected outcome is crucial because it allows us to quantify the probability of each model winning based on their current ratings. This probabilistic approach ensures that the rating adjustments are fair and proportional to the models’ performance expectations. If a highly-rated model wins against a lower-rated model, the rating change should be smaller because the outcome is expected. Conversely, if an underdog wins, the rating change should be more significant, reflecting the surprising result. This will help to stabilize the ranking system. For example, GPT4 can win over most models in most cases, but given its expected win rate is high, the actual rating change is minimal. Otherwise, slightly stronger models would quickly achieve extremely high scores, while slightly weaker models would be quickly eliminated.</p>

<p>Second, why we use this formula to compute the expected outcome, e.g., the expected outcome of model A <code class="language-plaintext highlighter-rouge">ea = 1 / (1 + BASE ** ((rb - ra) / SCALE))</code>?  This formula is derived from the <a href="https://en.wikipedia.org/wiki/Logistic_function">logistic distribution</a> and is designed to provide a smooth, continuous function that maps rating differences to probabilities of winning. Talking about probabilities, this implies that the value range for <code class="language-plaintext highlighter-rouge">ea</code> and <code class="language-plaintext highlighter-rouge">eb</code> is between 0 and 1.</p>
<ul>
  <li>When <code class="language-plaintext highlighter-rouge">rb</code> is much higher than <code class="language-plaintext highlighter-rouge">ra</code>, the denominator will become very large, which leads to a very small <code class="language-plaintext highlighter-rouge">ea</code> towards 0.</li>
  <li>When <code class="language-plaintext highlighter-rouge">rb</code> is much lower than <code class="language-plaintext highlighter-rouge">ra</code>, this part <code class="language-plaintext highlighter-rouge">BASE ** ((rb - ra) / SCALE)</code> will become very small almost 0, so that the denominator will converge to 1. Then <code class="language-plaintext highlighter-rouge">ea</code> is simply 1, which is the upper bound.</li>
  <li>When <code class="language-plaintext highlighter-rouge">ra = rb</code>, <code class="language-plaintext highlighter-rouge">ea</code> would be <code class="language-plaintext highlighter-rouge">1 / (1 + 1) = 0.5</code>, indicating an equal chance of winning.</li>
</ul>

<p>To summarize, as the rating difference increases, the expected outcome skews towards the higher-rated model. The choice of <code class="language-plaintext highlighter-rouge">BASE = 10</code> and <code class="language-plaintext highlighter-rouge">SCALE = 400</code> is conventional and ensures that a rating difference of 400 points corresponds to a 10-to-1 expected win ratio. This scale factor makes the system intuitive and easy to interpret.</p>

<h3 id="updating-the-models-ratings">Updating the models’ ratings</h3>

<p>Once we have the expected outcomes and the actual results from the battles, we are able to update the models’ ratings. The rating update formula is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rating[model_a] = ra + K * (sa - ea)
</code></pre></div></div>

<p>where:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">ra</code> is the original rating of model A before the battle.</li>
  <li><code class="language-plaintext highlighter-rouge">K</code> indicates the maximum change in rating (commonly set to 32 for chess but can vary). The default value from Chatbot Arena sets <code class="language-plaintext highlighter-rouge">K=4</code> because they want to make the Elo ratings more stable and less biased towards recent games. We will talk about this bias problem in just one minute.</li>
  <li><code class="language-plaintext highlighter-rouge">sa</code> represents the actual result after the game (1 for a win, 0.5 for a draw, 0 for a loss).</li>
</ul>

<p>One interesting thing is if you look at the formula closely, you will find that the lower-rated player will also gain a few points from the higher-rated player in the event of a draw. This means that this rating system is self-correcting. Players whose ratings are too low or too high should, in the long run, do better or worse correspondingly than the rating system predicts and thus gain or lose rating points until the ratings reflect their true playing strength.</p>

<p>Another interesting point is, this formula looks very similar to the update rule used in Stochastic Gradient Descent (SGD). In SGD, the update rule is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>w' = w − η * ∇L(w)
</code></pre></div></div>
<p>where:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">w</code> represents the old model weights and <code class="language-plaintext highlighter-rouge">w'</code> represents the updated model weights</li>
  <li><code class="language-plaintext highlighter-rouge">η</code> is the learning rate</li>
  <li><code class="language-plaintext highlighter-rouge">∇L(w)</code> is the gradient of the loss function with respect to the model parameters.</li>
</ul>

<p>Comparatively, the Elo rating update rule can be seen as:</p>
<ul>
  <li>The rating of the model <code class="language-plaintext highlighter-rouge">ra</code> is analogous to the model parameters <code class="language-plaintext highlighter-rouge">w</code> in SGD</li>
  <li>The scaling factor <code class="language-plaintext highlighter-rouge">K</code> is similar to the learning rate <code class="language-plaintext highlighter-rouge">η</code>, controlling the step size</li>
  <li>The score difference <code class="language-plaintext highlighter-rouge">sa - ea</code> is akin to the gradient, representing the error between the actual (model prediction) and expected outcomes (ground truth).</li>
</ul>

<p>This similarity illustrates how the Elo rating system can be viewed as an iterative optimization process. Just like in machine learning where models improve through training, the Elo rating system allows models to “learn” from each match, progressively refining their ratings.</p>

<h2 id="some-notes">Some notes</h2>

<p>While the Elo rating system is widely used and effective in many contexts, there are some interesting notes worth discussing.</p>

<h3 id="is-elo-ranking-an-absolute-metric">Is Elo ranking an absolute metric?</h3>
<p>Elo ratings are comparative only, and are valid only within the rating pool in which they were calculated, rather than being an absolute measure of a player’s strength. Your rating this year may not be the same as you rating next year, even your ability stays the same. A player with a high Elo ranking just means they are good in this pool, but not necessarily mean they are good universally.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/unrated_elo_part1.gif" alt="unrated" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">The Queen's Gambit. Image source: <a href="https://trailers.getyarn.io/yarn-clip/6676f252-5b30-4d23-bcd6-4a7f14fd0f81/gif" target="_blank">yarn clips</a></figcaption>
</figure>

<h3 id="bias-towards-recent-battles">Bias towards recent battles</h3>

<p>In terms of the online linear update algorithm to compute Elo ratings, it is sensitive to recent results, because the ratings are updated sequentially, meaning each new result builds on the last updated rating. This sequential dependency can amplify the impact of recent results, especially if they deviate significantly from expected outcomes. This can lead to significant fluctuations in ratings if the rating update order is changed.</p>

<p>To demonstrate it, in the <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH#scrollTo=c0KvFVr-nR2Q">notebook</a> from Chatbot Arena, they recompute Elo rating by using the reversed game order and observe significant difference due to online update of Elo which biases the recent games. We can see that when the order is reversed, the winner changes from <code class="language-plaintext highlighter-rouge">gemini-1.5-pro-api-0409-preview</code> to <code class="language-plaintext highlighter-rouge">gpt-4o-2024-05-13</code>. The ratings of all other models are also changed  significantly.</p>

<figure style="width: 80%; margin: auto;">
  <img src="https://github.com/bryanyzhu/tiny-ucf101/raw/master/reverse_order_online_elo.png" alt="reverse_online_elo" style="width: 100%; height: auto;" />
  <figcaption style="text-align: center;">Online Elo ranking is not stable. Image source: <a href="https://colab.research.google.com/drive/1KdwokPjirkTmpO_P1WByFNFiqxWQquwH#scrollTo=c0KvFVr-nR2Q" target="_blank">notebook from Chatbot Arena</a></figcaption>
</figure>

<h3 id="sensitivity-to-matchmaking">Sensitivity to matchmaking</h3>

<p>The rating updates depend heavily on the matchmaking process. If matches are not balanced (e.g., pairing high-rated models against very low-rated models frequently), the ratings can become distorted. Hence, the matchmaking process should also be handled carefully.</p>

<p>Chatbot Arena mentioned that they had adopted several different matching and sampling algorithms. They employed uniform sampling as well as weighted sampling methods, which assign greater weights to better models. That is probably why we can see the new models like GPT-4o gets to the top of the leaderboard soon after its release.</p>

<h2 id="summary">Summary</h2>

<p>So, next time you need to rank something and find yourself without a clear metric, remember the Elo rating system. It’s a proven approach that can turn a series of individual comparisons into a meaningful and dynamic leaderboard.</p>

<h2 id="references">References</h2>

<p>[1] Zheng et al., Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena, NeurIPS 2023 Datasets and Benchmarks Track.</p>]]></content><author><name>Yi Zhu</name><email>yizhu59@gmail.com</email></author><category term="AI" /><category term="LLM evaluation" /><category term="Elo" /><category term="Chatbot arena" /><summary type="html"><![CDATA[Chatbot Arena, developed by members from LMSYS and UC Berkeley SkyLab, is a benchmark platform designed to evaluate large language models (LLMs) through anonymous, randomized battles in a crowdsourced environment. Launched in May 2023, it has been continuously updated to reflect the latest advancements in the field. The platform’s leaderboard is widely regarded as one of the most credible sources for ranking LLMs. The screenshot below highlights the competitive landscape featuring major players in the LLM space.]]></summary></entry></feed>