<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.2.1">Jekyll</generator><link href="https://danielchen0.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://danielchen0.github.io/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-07-10T09:51:25+00:00</updated><id>https://danielchen0.github.io/feed.xml</id><title type="html">Daniel Chen</title><subtitle>Daniel Chen is an AI researcher, co-founder and Chief Scientist at Fabricate, writing about AI evaluation, machine learning, mathematics, and science.</subtitle><author><name>Daniel Chen</name></author><entry><title type="html">The Only Linear Algebra You Must Know</title><link href="https://danielchen0.github.io/2026/02/25/The-Only-Linear-Algebra-You-Must-Know.html" rel="alternate" type="text/html" title="The Only Linear Algebra You Must Know" /><published>2026-02-25T00:00:00+00:00</published><updated>2026-02-25T00:00:00+00:00</updated><id>https://danielchen0.github.io/2026/02/25/The-Only-Linear-Algebra-You-Must-Know</id><content type="html" xml:base="https://danielchen0.github.io/2026/02/25/The-Only-Linear-Algebra-You-Must-Know.html">&lt;style&gt;
.math-statement {
    border-left: 3px solid rgba(0,0,0,0.18);
    padding: 8px 0 8px 14px;
    margin: 18px 0;
    background: rgba(0,0,0,0.025);
}
.math-statement-title {
    font-weight: bold;
}
.proof {
    margin: 12px 0 18px 0;
}
.proof-title {
    font-style: italic;
}
&lt;/style&gt;

&lt;p&gt;Linear algebra is often taught backwards.&lt;/p&gt;

&lt;p&gt;A standard course starts with row reduction, determinants, matrix multiplication, eigenvalues, diagonalization, etc. These are all useful, but taught in that order, the subject can feel like a list of unrelated tricks.&lt;/p&gt;

&lt;p&gt;The more useful framing is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A matrix is not a grid of numbers.
A matrix is a coordinate description of a linear transformation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is most of linear algebra.&lt;/p&gt;

&lt;p&gt;Everything else is bookkeeping.&lt;/p&gt;

&lt;p&gt;The few facts worth remembering are stated explicitly below. The proofs are short because the point is not to make the subject feel more formal. The point is to make the conceptual dependencies visible.&lt;/p&gt;

&lt;h2 id=&quot;vectors-are-not-columns-of-numbers&quot;&gt;Vectors are not columns of numbers&lt;/h2&gt;

&lt;p&gt;A vector is an element of a vector space.&lt;/p&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;definition-1&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Definition 1 (vector space).&lt;/span&gt;
A vector space over a field \(\mathbb{F}\) is a set \(V\) whose elements can be added together and scaled by elements of \(\mathbb{F}\), in a way that behaves the way addition and scaling are supposed to behave:
\[
u+v \in V,
\quad
\lambda v \in V,
\]
and the usual rules like associativity, commutativity of addition, distributivity, additive identity, and additive inverses all hold.
&lt;/div&gt;

&lt;p&gt;That definition is intentionally plain. A vector space is just a place where linear combinations make sense.&lt;/p&gt;

&lt;p&gt;The important operation is:&lt;/p&gt;

\[x_1v_1 + \cdots + x_nv_n\]

&lt;p&gt;Once objects can be added and scaled, linear algebra can begin.&lt;/p&gt;

&lt;p&gt;The column of numbers is what appears after choosing a basis.&lt;/p&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;definition-2&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Definition 2 (coordinate representation).&lt;/span&gt;
Let \(V\) be a finite-dimensional vector space over \(\mathbb{F}\), and let
\(B = \{e_1,\dots,e_n\}\) be a basis of \(V\). If
\[
v = x_1e_1 + \cdots + x_ne_n,
\]
then the coordinate representation of \(v\) in the basis \(B\) is
\[
[v]_B =
\begin{bmatrix}
x_1 \\
\vdots \\
x_n
\end{bmatrix}.
\]
&lt;/div&gt;

&lt;p&gt;For example, the notation&lt;/p&gt;

\[v =
\begin{bmatrix}
3 \\
5
\end{bmatrix}\]

&lt;p&gt;usually means&lt;/p&gt;

\[v = 3e_1 + 5e_2\]

&lt;p&gt;where&lt;/p&gt;

\[e_1 =
\begin{bmatrix}
1 \\
0
\end{bmatrix},
\quad
e_2 =
\begin{bmatrix}
0 \\
1
\end{bmatrix}\]

&lt;p&gt;But the important thing is that the standard basis has been chosen.&lt;/p&gt;

&lt;p&gt;The vector is not inherently the pair of numbers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(3, 5)&lt;/code&gt;. The pair of numbers is the vector’s address in a particular coordinate system.&lt;/p&gt;

&lt;p&gt;This sounds pedantic until the source of confusion becomes clear: many linear algebra mistakes come from forgetting this distinction.&lt;/p&gt;

&lt;h2 id=&quot;bases-are-coordinate-systems&quot;&gt;Bases are coordinate systems&lt;/h2&gt;

&lt;p&gt;A basis is just a coordinate system for a vector space.&lt;/p&gt;

&lt;p&gt;If (B = {e_1, \dots, e_n}) is a basis for a vector space (V), then every vector (v \in V) can be written uniquely as&lt;/p&gt;

\[v = x_1 e_1 + \cdots + x_n e_n\]

&lt;p&gt;So choosing (B) gives a coordinate map:&lt;/p&gt;

\[\Phi_B : V \to \mathbb{F}^n\]

&lt;p&gt;where&lt;/p&gt;

\[\Phi_B(v) =
\begin{bmatrix}
x_1 \\
\vdots \\
x_n
\end{bmatrix}\]

&lt;p&gt;This map is doing something conceptually important. It takes an abstract vector and gives coordinates for it.&lt;/p&gt;

&lt;p&gt;The vector space did not come with coordinates. The coordinates were added by choosing a basis.&lt;/p&gt;

&lt;h2 id=&quot;linear-transformations-are-the-actual-objects&quot;&gt;Linear transformations are the actual objects&lt;/h2&gt;

&lt;p&gt;The real object in linear algebra is a linear transformation.&lt;/p&gt;

&lt;p&gt;A function&lt;/p&gt;

\[T : V \to W\]

&lt;p&gt;is linear if&lt;/p&gt;

\[T(v + w) = T(v) + T(w)\]

&lt;p&gt;and&lt;/p&gt;

\[T(\lambda v) = \lambda T(v)\]

&lt;p&gt;That is all linearity means: the function respects the vector space structure.&lt;/p&gt;

&lt;p&gt;The reason bases matter is that a linear transformation is completely determined by what it does to basis vectors.&lt;/p&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;proposition-1&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Proposition 1 (a linear map is determined by a basis).&lt;/span&gt;
Let \(T : V \to W\) be linear, and let \(B=\{e_1,\dots,e_n\}\) be a basis of \(V\).
If \(T(e_i)\) is known for every basis vector \(e_i\), then \(T(v)\) is determined for every \(v \in V\).
&lt;/div&gt;

&lt;div class=&quot;proof&quot;&gt;
&lt;span class=&quot;proof-title&quot;&gt;Proof.&lt;/span&gt;
Every vector \(v \in V\) has a unique expansion
\[
v = x_1e_1 + \cdots + x_ne_n.
\]
Since \(T\) is linear,
\[
T(v) = T(x_1e_1 + \cdots + x_ne_n)
     = x_1T(e_1) + \cdots + x_nT(e_n).
\]
So once the values of \(T\) on the basis vectors are known, the value of \(T\) on every vector is forced. \(\square\)
&lt;/div&gt;

&lt;p&gt;This is the structural reason matrices exist.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-matrix&quot;&gt;What is a matrix?&lt;/h2&gt;

&lt;p&gt;Suppose:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;(V) has basis (B = {e_1, \dots, e_n})&lt;/li&gt;
  &lt;li&gt;(W) has basis (C = {f_1, \dots, f_m})&lt;/li&gt;
  &lt;li&gt;(T : V \to W) is linear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To describe (T), look at where it sends each basis vector:&lt;/p&gt;

\[T(e_1), \dots, T(e_n)\]

&lt;p&gt;Each of these lives in (W), so each one can be expressed using the basis (C).&lt;/p&gt;

&lt;p&gt;For each (j):&lt;/p&gt;

\[T(e_j) = a_{1j}f_1 + a_{2j}f_2 + \cdots + a_{mj}f_m\]

&lt;p&gt;The coefficients become the (j)-th column of the matrix:&lt;/p&gt;

\[A =
\begin{bmatrix}
a_{11} &amp;amp; \cdots &amp;amp; a_{1n} \\
\vdots &amp;amp;        &amp;amp; \vdots \\
a_{m1} &amp;amp; \cdots &amp;amp; a_{mn}
\end{bmatrix}\]

&lt;p&gt;So the matrix is not the transformation itself.&lt;/p&gt;

&lt;p&gt;It is the coordinate representation of the transformation, after choosing:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;coordinates for the input space&lt;/li&gt;
  &lt;li&gt;coordinates for the output space&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;definition-3&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Definition 3 (matrix of a linear transformation).&lt;/span&gt;
Let \(T : V \to W\) be linear. Let \(B=\{e_1,\dots,e_n\}\) be a basis of \(V\), and let \(C=\{f_1,\dots,f_m\}\) be a basis of \(W\).
The matrix of \(T\) with respect to input basis \(B\) and output basis \(C\), written \([T]_{C \leftarrow B}\), is the matrix whose \(j\)-th column is \([T(e_j)]_C\).
&lt;/div&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;proposition-2&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Proposition 2 (the coordinate equation).&lt;/span&gt;
For every \(v \in V\),
\[
[T(v)]_C = [T]_{C \leftarrow B}[v]_B.
\]
&lt;/div&gt;

&lt;div class=&quot;proof&quot;&gt;
&lt;span class=&quot;proof-title&quot;&gt;Proof.&lt;/span&gt;
Write
\[
v = x_1e_1 + \cdots + x_ne_n.
\]
Then
\[
T(v) = x_1T(e_1) + \cdots + x_nT(e_n).
\]
The \(j\)-th column of \([T]_{C \leftarrow B}\) is \([T(e_j)]_C\), so multiplying \([T]_{C \leftarrow B}\) by the coordinate column \([v]_B\) forms exactly the same linear combination in coordinates. Therefore
\[
[T(v)]_C = [T]_{C \leftarrow B}[v]_B.
\]
\(\square\)
&lt;/div&gt;

&lt;p&gt;Equivalently, writing the coordinate maps explicitly, the matrix (A) satisfies:&lt;/p&gt;

\[\Phi_C(T(v)) = A \Phi_B(v)\]

&lt;p&gt;or as a commuting diagram:&lt;/p&gt;

\[\begin{array}{ccc}
V &amp;amp; \xrightarrow{T} &amp;amp; W \\
\downarrow \Phi_B &amp;amp; &amp;amp; \downarrow \Phi_C \\
\mathbb{F}^n &amp;amp; \xrightarrow{A} &amp;amp; \mathbb{F}^m
\end{array}\]

&lt;p&gt;This is the whole picture.&lt;/p&gt;

&lt;p&gt;The top row is the real transformation.&lt;/p&gt;

&lt;p&gt;The bottom row is what that transformation looks like in coordinates.&lt;/p&gt;

&lt;h2 id=&quot;matrix-multiplication-is-function-composition&quot;&gt;Matrix multiplication is function composition&lt;/h2&gt;

&lt;p&gt;Matrix multiplication also becomes less arbitrary from this view.&lt;/p&gt;

&lt;p&gt;Suppose:&lt;/p&gt;

\[T : U \to V\]

&lt;p&gt;and&lt;/p&gt;

\[S : V \to W\]

&lt;p&gt;They can be composed:&lt;/p&gt;

\[S \circ T : U \to W\]

&lt;p&gt;If (T) has matrix ([T]), and (S) has matrix ([S]), then the composition has matrix:&lt;/p&gt;

\[[S \circ T] = [S][T]\]

&lt;div class=&quot;math-statement&quot; id=&quot;proposition-3&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Proposition 3 (matrix multiplication is composition).&lt;/span&gt;
Let \(T : U \to V\) and \(S : V \to W\) be linear maps. After choosing compatible bases for \(U,V,W\),
\[
[S \circ T] = [S][T].
\]
&lt;/div&gt;

&lt;div class=&quot;proof&quot;&gt;
&lt;span class=&quot;proof-title&quot;&gt;Proof.&lt;/span&gt;
For any \(u \in U\), Proposition 2 gives
\[
[T(u)] = [T][u].
\]
Applying \(S\) next gives
\[
[S(T(u))] = [S][T(u)] = [S][T][u].
\]
But \(S(T(u)) = (S \circ T)(u)\), so the matrix that represents \(S \circ T\) is \([S][T]\). \(\square\)
&lt;/div&gt;

&lt;p&gt;This is not an arbitrary multiplication rule.&lt;/p&gt;

&lt;p&gt;It is just the coordinate version of doing one function and then the next.&lt;/p&gt;

&lt;p&gt;That is why the order can seem backwards at first:&lt;/p&gt;

\[[S][T]\]

&lt;p&gt;means:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;do (T)&lt;/li&gt;
  &lt;li&gt;then do (S)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Functions compose right-to-left, so matrices multiply right-to-left.&lt;/p&gt;

&lt;h2 id=&quot;why-change-of-basis-is-annoying&quot;&gt;Why change of basis is annoying&lt;/h2&gt;

&lt;p&gt;Change of basis is another topic that becomes simpler once vectors are no longer treated as columns.&lt;/p&gt;

&lt;p&gt;The same vector can have different coordinate columns under different bases.&lt;/p&gt;

&lt;p&gt;The vector did not change.&lt;/p&gt;

&lt;p&gt;The coordinate system changed.&lt;/p&gt;

&lt;div class=&quot;math-statement&quot; id=&quot;proposition-4&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Proposition 4 (change of basis changes descriptions, not vectors).&lt;/span&gt;
If \(B\) and \(C\) are two bases for the same vector space \(V\), then there is an invertible matrix \(P_{C \leftarrow B}\) such that
\[
[v]_C = P_{C \leftarrow B}[v]_B
\]
for every \(v \in V\).
&lt;/div&gt;

&lt;div class=&quot;proof&quot;&gt;
&lt;span class=&quot;proof-title&quot;&gt;Proof.&lt;/span&gt;
Each basis vector \(e_j\) of \(B\) can be written in the basis \(C\). Put those coordinate columns into a matrix:
\[
P_{C \leftarrow B} =
\begin{bmatrix}
[e_1]_C &amp;amp; \cdots &amp;amp; [e_n]_C
\end{bmatrix}.
\]
If \(v = x_1e_1 + \cdots + x_ne_n\), then multiplying by \(P_{C \leftarrow B}\) forms
\[
x_1[e_1]_C + \cdots + x_n[e_n]_C,
\]
which is exactly \([v]_C\). The matrix is invertible because changing from \(B\)-coordinates to \(C\)-coordinates can be undone by changing back. \(\square\)
&lt;/div&gt;

&lt;p&gt;So a change-of-basis matrix is not doing something to the vector itself. It is translating between descriptions of the same vector.&lt;/p&gt;

&lt;p&gt;Likewise, two different matrices can represent the same linear transformation if they are written using different bases.&lt;/p&gt;

&lt;p&gt;This is why statements like “this matrix has eigenvalues…” are a little imprecise. The main object is the linear operator, and the matrix is one coordinate representation of it.&lt;/p&gt;

&lt;h2 id=&quot;why-diagonalization-matters&quot;&gt;Why diagonalization matters&lt;/h2&gt;

&lt;p&gt;Diagonalization is often taught as another algorithm:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;find eigenvalues&lt;/li&gt;
  &lt;li&gt;find eigenvectors&lt;/li&gt;
  &lt;li&gt;build (PDP^{-1})&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But conceptually, diagonalization means:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Find a basis where the transformation acts independently on each coordinate direction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If an operator is diagonal in some basis, then in that basis it just scales each basis vector:&lt;/p&gt;

\[T(e_i) = \lambda_i e_i\]

&lt;div class=&quot;math-statement&quot; id=&quot;proposition-5&quot;&gt;
&lt;span class=&quot;math-statement-title&quot;&gt;Proposition 5 (diagonalization is choosing an eigenbasis).&lt;/span&gt;
Let \(T : V \to V\) be linear. If \(B=\{e_1,\dots,e_n\}\) is a basis of eigenvectors with
\[
T(e_i) = \lambda_i e_i,
\]
then the matrix \([T]_B\) is diagonal, with diagonal entries \(\lambda_1,\dots,\lambda_n\).
&lt;/div&gt;

&lt;div class=&quot;proof&quot;&gt;
&lt;span class=&quot;proof-title&quot;&gt;Proof.&lt;/span&gt;
The \(i\)-th column of \([T]_B\) is \([T(e_i)]_B\). Since \(T(e_i)=\lambda_i e_i\), this coordinate column has \(\lambda_i\) in the \(i\)-th slot and zeros everywhere else. So every off-diagonal entry is zero, and the diagonal entries are the eigenvalues. \(\square\)
&lt;/div&gt;

&lt;p&gt;That is why diagonal matrices are useful.&lt;/p&gt;

&lt;p&gt;They are not useful because zeros are aesthetically pleasing. They are useful because the transformation has been expressed in coordinates where its behavior is decoupled.&lt;/p&gt;

&lt;h2 id=&quot;the-sentence-to-remember&quot;&gt;The sentence to remember&lt;/h2&gt;

&lt;p&gt;Linear algebra is the study of linear transformations between vector spaces.&lt;/p&gt;

&lt;p&gt;Matrices are coordinate descriptions of those transformations.&lt;/p&gt;

&lt;p&gt;With that distinction in place, many standard facts become instances of the same idea:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;matrix multiplication is composition&lt;/li&gt;
  &lt;li&gt;change of basis is changing coordinates&lt;/li&gt;
  &lt;li&gt;invertible matrices are isomorphisms in coordinates&lt;/li&gt;
  &lt;li&gt;the identity matrix is the identity transformation in coordinates&lt;/li&gt;
  &lt;li&gt;diagonalization is finding coordinates where an operator is simple&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The useful diagnostic question is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What transformation does this matrix describe, and which bases are involved?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question usually identifies the relevant object and the relevant coordinates.&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html"></summary></entry><entry><title type="html">Understanding Transformers III - Cross Attention</title><link href="https://danielchen0.github.io/2025/11/13/Understanding-Transformers-III-Cross-Attention.html" rel="alternate" type="text/html" title="Understanding Transformers III - Cross Attention" /><published>2025-11-13T00:00:00+00:00</published><updated>2025-11-13T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/11/13/Understanding-Transformers-III-Cross-Attention</id><content type="html" xml:base="https://danielchen0.github.io/2025/11/13/Understanding-Transformers-III-Cross-Attention.html">&lt;p&gt;This post is a follow up to Part II on Encoders, you should start there if you are unfamiliar with encoders.&lt;/p&gt;

&lt;p&gt;Recall that the Transformer architecture consists of three parts: the Decoder, the Encoder, and Cross Attention. In parts I and II we studied the decoder only transformer and the encoder only transformer, respectively. Now it is time to combine these things together to form the original encoder-decoder transformer architecture, using the Cross Attention mechanism.&lt;/p&gt;

&lt;p&gt;Up to now, all mentions of “Attention” have referred to “Self Attention”, where a token pays attention to other tokens in the same sequence. Cross Attention is a mechanism where a token pays attention to tokens in a different sequence. In particular, Cross Attention is used to connect the Encoder and the Decoder.&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/transformer-with-labels.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 1.&lt;/span&gt; The transformer architecture with labels for the encoder, decoder, and cross attention. (Choi, 2024)
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;how-cross-attention-connects-the-encoder-and-the-decoder&quot;&gt;How Cross Attention connects the Encoder and the Decoder&lt;/h2&gt;

&lt;p&gt;Something we should first clarify is how exactly the connection is made. The original diagram above is a bit confusing, but Murel and Noble (2024) provide a more clear explanation:&lt;/p&gt;
&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/ibm-cross-attention.jpg&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 2.&lt;/span&gt; The cross attention mechanism when expanded fully (Murel &amp;amp; Noble, 2024).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In words, once the encoder has processed the input sentence, the cross attention mechanism feeds the final encoding to each decoder block of the decoding stack.&lt;/p&gt;

&lt;h2 id=&quot;the-cross-attention-mechanism-in-detail&quot;&gt;The Cross Attention Mechanism in Detail&lt;/h2&gt;

&lt;p&gt;The cross attention mechanism is nearly identical to the self attention mechanism, the main difference now is that in Cross Attention, we port the Key and Value matrices over from the Encoder and the decoder uses its own Query matrix on these encoder matrices. This is illustrated in the diagram below:&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/self-attention-vs-cross-attention.jpeg&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 3.&lt;/span&gt; The cross attention mechanism in detail (Benveniste, 2024).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The math is entirely the same, the magic occurs just by the fact that we are reusing the Key and Value matrices from the Encoder and the Query matrix from the Decoder and performing this fancy rerouting.&lt;/p&gt;

&lt;h2 id=&quot;but-why&quot;&gt;But why?&lt;/h2&gt;

&lt;p&gt;Doing this allows each decoder block to pay attention to the final encoding of the input sentence. This is useful because it allows the decoder to use the information from the input sentence to help it generate the next token, and also prevents the decoder from “forgetting” the input sentence (vanishing gradient problem).&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That’s it, that’s really all there is to the Encoder-Decoder Transformer.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;Benveniste, D. (2024). What is the difference between self-attention and cross-attention? [LinkedIn post]. LinkedIn. https://www.linkedin.com/posts/damienbenveniste_what-is-the-difference-between-self-attention-activity-7211029906166624257-m0Wn/&lt;/p&gt;

&lt;p&gt;Choi, J. (2024, March 2). Where the term “cross-attention” is first used? (couldn’t find the term in Attention is all you need paper) [Question on the Data Science Stack Exchange]. Data Science Stack Exchange. https://datascience.stackexchange.com/questions/128123/where-the-term-cross-attention-is-first-used-couldnt-find-the-term-in-attention-is-all-you-need-paper&lt;/p&gt;

&lt;p&gt;Murel, J., &amp;amp; Noble, J. (2024). What is an encoder-decoder model? [Article]. IBM Think. https://www.ibm.com/think/topics/encoder-decoder-model&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">This post is a follow up to Part II on Encoders, you should start there if you are unfamiliar with encoders.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://danielchen0.github.io/assets/transformer-with-labels.png" /><media:content medium="image" url="https://danielchen0.github.io/assets/transformer-with-labels.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Why do Magnetic Field Lines go from South to North inside of a bar magnet?</title><link href="https://danielchen0.github.io/2025/08/23/magnetic-fields-inside-bar-magnet.html" rel="alternate" type="text/html" title="Why do Magnetic Field Lines go from South to North inside of a bar magnet?" /><published>2025-08-23T00:00:00+00:00</published><updated>2025-08-23T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/08/23/magnetic-fields-inside-bar-magnet</id><content type="html" xml:base="https://danielchen0.github.io/2025/08/23/magnetic-fields-inside-bar-magnet.html">&lt;p&gt;When reading about magnetic field lines for bar magnets, you will often hear that field lines go from north to south outside the bar magnet, and they go from south to north inside of the bar magnet, thus forming closed loops. The direction of the field line is interpreted to be the direction of force the bar magnet imposes on a point north pole particle. So it would make sense that field lines go from north to south outside of the magnet, but why does it make sense that they would go from south to north then when &lt;em&gt;inside&lt;/em&gt; of a bar magnet? How can you ascertain what would happen to a north pole particle when you cannot physically measure this since you can’t place a particle there physically? In otherwords, if there’s no way to experimentally verify or dispute this, why do we say this?&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/Bar-Magnet-Magnetic-Field-With-Compass.gif&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 1.&lt;/span&gt; Magnetic Field lines indicate which direction a north monopole will be pushed due to the magnetic field of the bar magnet (StickMan Physics).
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/Magnet_Iron_Filings.jpg&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 2.&lt;/span&gt; You can empirically verify the existence and behavior of field lines by using iron filaments (E-TCOURSE). However, this only works for the outside of the bar magnet, as you obviously cannot place filaments inside of the bar magnet.
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/bar-magnet.gif&quot; style=&quot;width: 50%; height: 50%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 3.&lt;/span&gt; Magnetic Field lines are often shown going from north to south outside of the bar magnet, while south to north inside of the bar magnet. (Nave).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Such a statement has bothered me since my youth when it was first taught to me, and even now most sources don’t really do the topic justice, so I’ll try my best to break this down into intuitive terms.&lt;/p&gt;

&lt;h2 id=&quot;first-principles&quot;&gt;First principles&lt;/h2&gt;

&lt;p&gt;To begin to understand this behavior, we need to recall some facts about bar magnets that we &lt;em&gt;can&lt;/em&gt; verify.&lt;/p&gt;

&lt;p&gt;Fact 1: A bar magnet cannot be split into two monopoles. In fact, when splitting a bar magnet, you will get two bar magnets with both north and south poles, regardless of whether you split it vertically or horizontally.&lt;/p&gt;

&lt;p&gt;Note that this is equivalent to the fact that magnetic monopoles (i.e. magnets with only a north or south pole) don’t exist.&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/split-magnet.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 4.&lt;/span&gt; Splitting a North-South bar magnet just recursively produces smaller North-South bar magnets, you cannot separate the north from the south pole even if you try (Monash University).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Clearly, if you keep doing this recursion, you end up with a collection of ferromagnetic &lt;em&gt;units&lt;/em&gt;, each of which of course has its own north and south poles.&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/ferromagnetic-bar-magnet.jpg&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 5.&lt;/span&gt; A magnet consists of ferromagnetic sections. (Lehan, 2020)
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now, intuitively, if you place a north pole somewhere in this array of north-south dipoles, the force enacted upon the north pole will tend to move towards the top (north side) of the magnet, hence why the field lines point towards the north pole of the overall bar magnet.&lt;/p&gt;

&lt;p&gt;There is really no outside vs inside, at all points in space there are many of these ferromagnetic particles acting on those points inside of the overall bar magnet. Basically, the north pole of the magnet is implied by the particles and not the otherway around - the particles imbue an overall sense of north vs southness of the bar magnet.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;E-TCOURSE. (2020, November 26). An overview of magnetic field lines and its characteristics. E-TCOURSE News Blog. Retrieved August 23, 2025, from https://www.etcourse.com/news-blog/magnetic-field-lines&lt;/p&gt;

&lt;p&gt;Lehan, D. (2020). Permanent and Induced Magnetism (4.7.1 Permanent and induced magnetism). In Physics-SchoolUK.com. Retrieved August 23, 2025, from https://physics-schooluk.com/magnetism_permanent.html&lt;/p&gt;

&lt;p&gt;Monash University. (n.d.). Magnetic fields. In Student Academic Success – Physics: Fields and interactions. Retrieved August 23, 2025, from https://www.monash.edu/student-academic-success/physics/fields-and-interactions/magnetic-fields&lt;/p&gt;

&lt;p&gt;Nave, C. R. (n.d.). Magnetism &amp;amp; electromagnetism. In HyperPhysics. Georgia State University. Retrieved August 23, 2025, from http://hyperphysics.phy-astr.gsu.edu/hbase/magnetic/elemag.html&lt;/p&gt;

&lt;p&gt;StickMan Physics. (n.d.). Magnetic fields. In Magnets and magnetism [Web page]. Retrieved August 23, 2025, from https://stickmanphysics.com/stickman-physics-home/magnets-and-magnetism/magnetic-fields/&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">When reading about magnetic field lines for bar magnets, you will often hear that field lines go from north to south outside the bar magnet, and they go from south to north inside of the bar magnet, thus forming closed loops. The direction of the field line is interpreted to be the direction of force the bar magnet imposes on a point north pole particle. So it would make sense that field lines go from north to south outside of the magnet, but why does it make sense that they would go from south to north then when inside of a bar magnet? How can you ascertain what would happen to a north pole particle when you cannot physically measure this since you can’t place a particle there physically? In otherwords, if there’s no way to experimentally verify or dispute this, why do we say this?</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://danielchen0.github.io/assets/Magnet_Iron_Filings.jpg" /><media:content medium="image" url="https://danielchen0.github.io/assets/Magnet_Iron_Filings.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Understanding Transformers II - The Encoder</title><link href="https://danielchen0.github.io/2025/07/13/Understanding-Transformers-II-The-Encoder.html" rel="alternate" type="text/html" title="Understanding Transformers II - The Encoder" /><published>2025-07-13T00:00:00+00:00</published><updated>2025-07-13T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/07/13/Understanding-Transformers-II-The-Encoder</id><content type="html" xml:base="https://danielchen0.github.io/2025/07/13/Understanding-Transformers-II-The-Encoder.html">&lt;p&gt;This post is a follow up to Part I on Decoders, you should start there if you are unfamiliar with decoders.&lt;/p&gt;

&lt;p&gt;Recall that the Transformer architecture consists of three parts: the Decoder, the Encoder, and Cross Attention.&lt;/p&gt;

&lt;p&gt;An encoder-only transformer looks like this:&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/encoder-only.png&quot; style=&quot;width: 25%; height: 25%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 1.&lt;/span&gt; The encoder-only architecture [Adapted from Vaswani et al., 2017].
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;encoder-only-transformers---bert&quot;&gt;Encoder-only Transformers - BERT&lt;/h2&gt;

&lt;p&gt;Studying encoder-only transformers such as BERT (Bidirectional Encoder Representations from Transformers) (Devlin, 2019) allows us to understand encoders as a concept. Unlike decoder-only transformers which consume sentences and predict the next token, encoder-only transformers take sentences and &lt;em&gt;encode&lt;/em&gt; them in a higher dimensional space. Encoders don’t do any prediction of next tokens or any meaningful task on their own. If we want them to do something like classification, we need to add task specific layers at the end of the model. For classification problems, this would be the &lt;em&gt;classification head&lt;/em&gt; which would be some Multilayer Perceptron that consumes the encodings from the encoder blocks and outputs classification logits.&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/encoder-with-classifier.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 2.&lt;/span&gt; The BERT architecture with a classifier head (Khalid, 2021).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A key difference here between BERT and GPT-2 (decoder only) is that BERT consumes pairs of sentences. However this is just a choice of input, and is not necessitated by the architecture itself. A model like this can be broken down into simple steps, each corresponding to a part of the diagram above:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Receive an input sentence, consisting of two smaller sentences: “The cat is black. It licks its fur.”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tokenization and embeddings&lt;/strong&gt;: The process of tokenization and embedding the tokens is identical to that of decoder models. One additional step is we add a &lt;em&gt;separator&lt;/em&gt; token (denoted SEP) between the two sentences.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Positional encodings&lt;/strong&gt;: Similar to the decoder-only transformer, we have positional vectors that we add to each token embedding to encode information about its position in the sentence. We also have &lt;em&gt;segment&lt;/em&gt; encodings to indicate whether the token is in the first or second sentence.
    &lt;div class=&quot;figure&quot;&gt;
     &lt;img src=&quot;/assets/positional-encoder.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
     &lt;div class=&quot;caption&quot;&gt;
         &lt;span class=&quot;caption-label&quot;&gt;Figure 3.&lt;/span&gt; In BERT, we have both positional _and_ segment encodings (Devlin, 2019).
     &lt;/div&gt;
 &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;: This corresponds to the “Multi-head attention” box in the transformer diagram. The process is nearly identical to the “Masked Multi-head attention” mechanism in the Decoder block so I will not repeat its details here. Recall that attention is called &lt;em&gt;masked&lt;/em&gt; when we disallow tokens from paying attention to tokens ahead of it in the sentence, by zeroing out these values. So, the only difference in the encoder case is we allow for tokens to pay attention to &lt;em&gt;all&lt;/em&gt; other tokens in the input sentence, since the attention is not masked here. We have an Add and Normalize step after this is done to avoid vanishing gradient problems.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Identically to the Decoder case, we have a Feed Forward block where the attention value vectors are passed through a Multilayer Perceptron (MLP) to introduce non linearity. Once again we then do an Add and Normalize step.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Steps 4-5 constitute one transformer &lt;em&gt;block&lt;/em&gt;. The outputs are then fed to the next block. This process can be repeated as many times as desired. In BERT’s case, this is repeated 12 times.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;At the output end of the last transformer block, we receive the &lt;em&gt;encodings&lt;/em&gt; and can add any task head to &lt;em&gt;fine tune&lt;/em&gt; the model to a specific task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This completes the architecture.&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;Devlin, J., Chang, M.-W., Lee, K., &amp;amp; Toutanova, K. (2019). &lt;em&gt;BERT: Pre‑training of deep bidirectional transformers for language understanding&lt;/em&gt; (arXiv:1810.04805). arXiv. &lt;a href=&quot;https://doi.org/10.48550/arXiv.1810.04805&quot;&gt;https://doi.org/10.48550/arXiv.1810.04805&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Khalid, U., Beg, M. O., &amp;amp; Arshad, M. U. (2021, February 22). &lt;em&gt;RUBERT: A bilingual Roman Urdu BERT using cross‑lingual transfer learning&lt;/em&gt; (arXiv:2102.11278). arXiv. https://doi.org/10.48550/arXiv.2102.11278&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">This post is a follow up to Part I on Decoders, you should start there if you are unfamiliar with decoders.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://danielchen0.github.io/assets/encoder-only.png" /><media:content medium="image" url="https://danielchen0.github.io/assets/encoder-only.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Don’t Use Truthy/Falsy Values</title><link href="https://danielchen0.github.io/2025/07/07/truthy-tests.html" rel="alternate" type="text/html" title="Don’t Use Truthy/Falsy Values" /><published>2025-07-07T00:00:00+00:00</published><updated>2025-07-07T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/07/07/truthy-tests</id><content type="html" xml:base="https://danielchen0.github.io/2025/07/07/truthy-tests.html">&lt;p&gt;I’m not a fan of so called Truthy or Falsy values in programming languages for a variety of reasons. For those of you who are unfamiliar with these, truthy and falsy values are basically default &lt;em&gt;boolean&lt;/em&gt; values associated with values. For example, in Python, a number implictly has boolean value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt; if and only if it is equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;. Similarly, an empty list &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt; has boolean value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; but any list with &lt;em&gt;any&lt;/em&gt; values, even if they are all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, has boolean value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;. So the lists &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[0]&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[1]&lt;/code&gt;, etc. all have value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means you can write nice little code like this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Nothing to do!&quot;&lt;/span&gt;
    
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Nothing to do!&quot;&lt;/span&gt;
    
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The key of course is just that writing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!inputList&lt;/code&gt; is a lot more consise than writing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len(inputList) == 0&lt;/code&gt;, when you want to check if the list is empty or not.&lt;/p&gt;

&lt;p&gt;I’ll now go through a list of reasons colleagues have presented to me for why truthy falsy values are useful and evaluate their merits.&lt;/p&gt;

&lt;h2 id=&quot;various-reasons-for-why-truthy-falsy-checks-are-good&quot;&gt;Various reasons for why Truthy Falsy checks are good&lt;/h2&gt;

&lt;h3 id=&quot;avoids-repetitive-code-for-routine-checks&quot;&gt;Avoids repetitive code for routine checks&lt;/h3&gt;

&lt;p&gt;In the example above, its useful to use the shorthand &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!inputList&lt;/code&gt; and anyone who is fluent in their language to take advantage of the option especially when the check comes up often. I agree with this point that if you’re going to do something a lot you should have nice syntax for it, and truthy/falsy values get you that.&lt;/p&gt;

&lt;h3 id=&quot;if-it-is-a-feature-of-the-language-you-should-use-it&quot;&gt;If it is a feature of the language you should use it&lt;/h3&gt;

&lt;p&gt;I never understood this one but have heard it. It sort of assumes that every language is designed perfectly and has no pitfalls.&lt;/p&gt;

&lt;p&gt;A common gotcha in python is that default arguments in function args are mutable and shared across all calls to the function.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# each time myFunc is called, the inputList default mutates from [], [5], [5,5]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You are often recommended to this instead for safety:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# always defaults to [] across all function calls
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;if-you-change-the-type-of-your-variable-then-you-dont-have-to-update-any-of-your-checks-again&quot;&gt;If you change the type of your variable then you don’t have to update any of your checks again&lt;/h3&gt;

&lt;p&gt;I’m not sure why you would want this, the example presented to me was that converting the following from a list input to an integer input&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Nothing to do!&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;would allow us to seamlessly change the type without updating the code of the check&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;processList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputNum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Nothing to do!&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This clearly depends on the fact that your desired check would have remained the same in the new datatype, but I can’t think of immediate cases as to why you would want this. Doesn’t it seem safer to have had the explicit check &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len(inputList) == 0&lt;/code&gt; so that you immediately get compile/run time errors and you now have to make sure the checks are what you want in the new datatype?&lt;/p&gt;

&lt;p&gt;There is then the added case of, if your variable name contains the type like in the example above, you still have to edit the line with the new variable name, so I don’t understand what time was saved.&lt;/p&gt;

&lt;p&gt;Finally, I don’t think you change the type of a variable often anyways, so the whole case seems irrelevant.&lt;/p&gt;

&lt;h2 id=&quot;various-reasons-for-why-truthyfalsy-checks-are-bad&quot;&gt;Various reasons for why truthy/falsy checks are bad:&lt;/h2&gt;

&lt;h3 id=&quot;it-violates-write-once-read-many&quot;&gt;It violates “Write once, read many”&lt;/h3&gt;

&lt;p&gt;Using these checks kind of reminds me of a time when programmers around me would write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alp&lt;/code&gt; everywhere instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alpha&lt;/code&gt; just to save time. This leads to the classic case that anyone reading a line in the code needs to now think about what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alp&lt;/code&gt; means, similar to how ayone reading &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!myList&lt;/code&gt; needs to think about the False/True cases of list values when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;len(myList) == 0&lt;/code&gt; would have immediately told you the check condition.&lt;/p&gt;

&lt;h3 id=&quot;no-objective-default-across-languages&quot;&gt;No objective default across languages&lt;/h3&gt;

&lt;p&gt;The boolean values we associate with objects and primitives are inherently arbitrary. For example, in python the empty list &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt; has boolean value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;, but in Javascript an empty array &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[]&lt;/code&gt; has boolean value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;. Therefore, there is no &lt;em&gt;intuitive&lt;/em&gt; way to know this knowledge, you just have to use it often and only in one language, and hope you don’t forget that the behavior is different when switching to another language.&lt;/p&gt;

&lt;h3 id=&quot;no-objective-preference-across-languages&quot;&gt;No objective preference across languages&lt;/h3&gt;

&lt;p&gt;In python, it is often recommended to use these truthy/falsy checks just as it is tacitly the preferred style in the community, as part of writing “Pythonic” code.&lt;/p&gt;

&lt;p&gt;In C++, the only truthy/falsy value provided by the language is that for numerical values i.e. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; and their variants. This also applies to pointer values which are just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;size_t&lt;/code&gt; values. However we all know a good C++ programmer uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nullptr&lt;/code&gt; keyword when checking if a pointer is null or not as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;size_t* ptr;
if (ptr == nullptr){
    std::cout &amp;lt;&amp;lt; &quot;Got a null pointer!&quot; &amp;lt;&amp;lt; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;even though you could do this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-C++&quot;&gt;size_t* ptr;
if (!ptr) {
    std::cout &amp;lt;&amp;lt; &quot;Got a null pointer!&quot; &amp;lt;&amp;lt; std::endl;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we have an example where whether you should use it or not is subjective based on the community you are a part of.&lt;/p&gt;

&lt;h3 id=&quot;contradictory-internal-style-guides&quot;&gt;Contradictory internal style guides&lt;/h3&gt;

&lt;p&gt;Python programmers &lt;em&gt;love&lt;/em&gt; truthy/falsy values because it makes their code so-called “pythonic”.&lt;/p&gt;

&lt;p&gt;I now refer you to the following lines from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Zen of Python&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
Explicit is better than implicit
...
Readability counts
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you read these sentences, you would probably realize that truthy/falsy values violate both - implicit boolean checks are inherently not explicit, and they are harder to read if you don’t know what the defaults are.&lt;/p&gt;

&lt;h3 id=&quot;confusing-and-inefficient-when-layered&quot;&gt;Confusing and inefficient when layered&lt;/h3&gt;

&lt;p&gt;In python, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; evaluates to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; in boolean contexts. This means that there are two cases when an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Optional[int]&lt;/code&gt; evaluates to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;: when it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;, and when it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may forget this when writing code and do:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;No val set... performing handling...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Handling no quantity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a bug. Remember - &lt;em&gt;both&lt;/em&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; values hit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; block, so you need to do this:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;myFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;No val set... performing handling...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myVal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Handling no quantity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case we weren’t able to use the truthy values at all. We &lt;em&gt;could&lt;/em&gt; do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!myVal&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; block if we think we’re smart, but that would require you to read all of the code &lt;em&gt;around&lt;/em&gt; that block in order to realize that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myVal&lt;/code&gt; couldn’t be a possible value in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; block. Doing the explicit check is much more readable.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In conclusion, just don’t…&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">I’m not a fan of so called Truthy or Falsy values in programming languages for a variety of reasons. For those of you who are unfamiliar with these, truthy and falsy values are basically default boolean values associated with values. For example, in Python, a number implictly has boolean value True if and only if it is equal to 0. Similarly, an empty list [] has boolean value False but any list with any values, even if they are all 0, has boolean value True. So the lists [0], [1], etc. all have value True.</summary></entry><entry><title type="html">Understanding Transformers I - The Decoder</title><link href="https://danielchen0.github.io/2025/05/31/Understanding-Transformers-I-The-Decoder.html" rel="alternate" type="text/html" title="Understanding Transformers I - The Decoder" /><published>2025-05-31T00:00:00+00:00</published><updated>2025-05-31T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/05/31/Understanding-Transformers-I-The-Decoder</id><content type="html" xml:base="https://danielchen0.github.io/2025/05/31/Understanding-Transformers-I-The-Decoder.html">&lt;p&gt;In this blog post I give an introduction to the Transformer architecture as originally presented by Vaswani et al., in their landmark paper, “Attention Is All You Need”. My focus will be on visuals and intuition. Specifically, I intend to explain the Transformer in three parts: Decoders, Encoders, and Cross Attention. This blog post covers part one of this list.&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/encoder-decoder.png&quot; style=&quot;width: 50%; height: 50%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 1.&lt;/span&gt; The transformer architecture features encoders, decoders, positional encodings, and token embeddings (Vaswani et al., 2017).
    &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;breaking-it-down---decoders-encoders-and-cross-attention&quot;&gt;Breaking it down - Decoders, Encoders, and Cross Attention&lt;/h2&gt;

&lt;p&gt;For reasons, decoder-only architectures such as GPT-2 (released in 2019) and encoder-only architectures such as BERT (released 2018) actually came after the original encoder-decoder transformer paper in 2017. Despite this chronology it is useful to focus on these simpler transformers and build our way up in future sections to eventually combine the encoders and decoders together (via Cross Attention) to form the original transformer.&lt;/p&gt;

&lt;p&gt;An easy way to visualize this is to divide the Transformer and relate it to these simpler transformers:&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/disect-transformer.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 2.&lt;/span&gt; The transformer architecture consists of two parts - an encoder stack, and a decoder stack (Esmailbeigi, 2023).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;That is - Decoder only architectures mimic the right side of the Transformer stack, while encoder only architectures mimic the left side.&lt;/p&gt;

&lt;p&gt;There is one subtle detail - in decoder only models i.e. the right side, there is of course no cross attention mechanism that connects the encoders to the decoders, so the second multi-head attention unit should be removed:&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/cross-attention.png&quot; style=&quot;width: 50%; height: 50%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 3.&lt;/span&gt; The encoder decoder transformer features a Cross attention mechanism that connects these together. In a decoder only model this is not present (Tensorflow).
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Therefore, a decoder-only transformer would look like this:&lt;/p&gt;

&lt;div class=&quot;figure&quot;&gt;
    &lt;img src=&quot;/assets/decoder-only.png&quot; style=&quot;width: 50%; height: 50%; display: block; margin: 0 auto;&quot; /&gt;
    &lt;div class=&quot;caption&quot;&gt;
        &lt;span class=&quot;caption-label&quot;&gt;Figure 4.&lt;/span&gt; The decoder-only architecture [Adapted from Vaswani et al., 2017].
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;You may notice that this looks very similar to the encoder block, I will discuss the subtle differences in a separate post.&lt;/p&gt;

&lt;h2 id=&quot;decoder-only-transformers---gpt-2&quot;&gt;Decoder-only transformers - GPT-2&lt;/h2&gt;

&lt;p&gt;Let us now focus on the topic of this blog post which is Decoder-only architectures such as GPT-2. A model like this consumes a sentence and predicts the next token. In this sense, it can be understood that the Decoder architecture “decodes” what the next token should be, hence the name.&lt;/p&gt;

&lt;p&gt;Some ideas below are inspired by the Transformer Explainer tool (Liang, D. &amp;amp; Klein, D.).&lt;/p&gt;

&lt;p&gt;A model like this can be broken down into simple steps, each corresponding to a part of the diagram above:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Receive an input sentence: “Data visualization empowers users to”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tokenization and embeddings&lt;/strong&gt;: For each &lt;em&gt;token&lt;/em&gt; in the sentence, convert it to an &lt;em&gt;embedding&lt;/em&gt; vector of fixed length.
    &lt;ul&gt;
      &lt;li&gt;A &lt;em&gt;token&lt;/em&gt; is a string of continuous characters treated as a unit. For example, in GPT-2’s tokenizer, ‘data’, ‘visualization’, ‘users’ and ‘to’ are all tokens. However, ‘em’ and ‘powers’ are separate tokens.&lt;/li&gt;
      &lt;li&gt;An &lt;em&gt;embedding&lt;/em&gt; is a vector that corresponds to the token, and represents its meaning.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;The embedding vector represents the token’s meaning in the sense that vector operations can be performed to produce similar concepts:&lt;/p&gt;

        &lt;div class=&quot;figure&quot;&gt;
       &lt;img src=&quot;/assets/embedding-meaning.png&quot; style=&quot;width: 100%; height: 100%; display: block; margin: 0 auto;&quot; /&gt;
       &lt;div class=&quot;caption&quot;&gt;
           &lt;span class=&quot;caption-label&quot;&gt;Figure 5.&lt;/span&gt; Subtracting the embedding vectors for man and women is equivalent to subtracting the embedding vectors for uncle and aunt (3Blue1Brown, 2024).
       &lt;/div&gt;
   &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Positional encodings&lt;/strong&gt; Special &lt;em&gt;positional encoding&lt;/em&gt; vectors are added to each embedding to add meaning about the position of the token in the sentence. For example, there is a positional encoding vector for position 1, and it is added to the first token only.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Attention&lt;/strong&gt;: This corresponds to the “Masked Multi-head attention” box in the transformer diagram, it works as follows: For each embedding $\vec{e}$ (corresponding to an input token), apply special transforms (understood to be &lt;em&gt;weights&lt;/em&gt; matrices, but this isn’t too important) $W_K$, $W_Q$, and $W_V$ to get the Key, Query, and Value vectors corresponding to the token, respectively. These matrices are &lt;em&gt;learnt&lt;/em&gt; during the training process of the transformer.
    &lt;ul&gt;
      &lt;li&gt;Such vectors can be understood as follows:
        &lt;ul&gt;
          &lt;li&gt;The Key vector $\vec{k} = W_k \vec{e}$ is a vector of dimension $d_k$ such that when multiplied by another token’s Query vector, gives us a magnitude representing how much &lt;em&gt;attention&lt;/em&gt; that other token is paying attention to us.&lt;/li&gt;
          &lt;li&gt;The Query vector $\vec{q} = W_q \vec{e}$ is symmetrically a vector of dimension $d_q = d_k$ such that, when multiplied by another token’s Key vector, gives us a magnitude representing how much &lt;em&gt;attention&lt;/em&gt; our token is paying attention to that other token.&lt;/li&gt;
          &lt;li&gt;The Value vector $\vec{v} = W_v \vec{e}$ is a vector that represents the original embedding of the token in a new vector space, such that, when multiplied by attention (a scalar number), gives us a vector representing the original token scaled by the attention the current token has for it.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;To calculate the attention token $i$ has for token $j$, we could do something like this: $\vec{q_i}^\intercal \cdot \vec{k_j}$ thus getting a scalar number via the usual dot product. Then we could scale the value vector of token $j$, so that our scaled attention for token $j$ is just  $\left(\vec{q_i}^\intercal \cdot \vec{k_j}\right) \vec{v_j}$.&lt;/li&gt;
      &lt;li&gt;An astute reader would note that instead of doing each of these calculations as a for loop over all $i$ and $j$, we can get all of this together as one matrix mulitplication $Q^\intercal K V$, where $Q$, $K$, $V$ are matrices such that the ith column is the vector for the ith token.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;The variance of the multiplication of $Q$ and $K$ happens to be $\sqrt{d_k}$ (user3667125, 2020). Then if we divide by this we can reduce the variance of the multiplication to 1. And we can then apply a softmax so that the sum of attention scores a token has for other tokens adds up to 1. This would give us $\text{softmax}\left( \frac{Q^\intercal K}{\sqrt{d_k}} \right) V$.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;Therefore, for each input token’s embedding, we get a list of vectors that represent other vectors in the sentence, scaled by the attention this token has for them.&lt;/li&gt;
      &lt;li&gt;This attention is called &lt;em&gt;masked&lt;/em&gt; because we disallow tokens from paying attention to tokens ahead of it in the sentence, by zeroing out these values.&lt;/li&gt;
      &lt;li&gt;This attention is called &lt;em&gt;multi-head&lt;/em&gt; because technically, we run 12 of these attention heads in parallel, each doing the above as described, but for smaller sections of the input embeddings. For example, one attention head would look at the first 12th of each embedding. The second attention head would look at the second 12th of each embedding, etc. And then we just concatenate these results together to produce the same output had we done it all in one single head of attention.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Once we have these scaled attention-value vectors, we run these through a Multilayer Perceptron (MLP). This corresponds to the “Feed Forward” box in the transformer diagram (note: MLPs are only one type of Feed Forward network, but not all Feed Forward networks are MLPs). This adds many layers of non linearity that allows the transformer to learn deep features about these vectors.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Steps 4-5 constitute one transformer &lt;em&gt;block&lt;/em&gt;. The outputs are then fed to the next block. This process can be repeated as many times as desired. In GPT-2’s case, this is repeated 12 times.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;At the output end of the last transformer block, we apply a softmax layer to convert the outputs to probabilities. This represents the probability of a particular token being the next token in an input sentence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This completes the architecture. There are a couple of details I left out above because I felt they would disrupt the flow and are of minor importance. They are as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Add and Norm&lt;/strong&gt;: There are several layers of Add and Normalization, how this works is we take the input before MLP or attention respectively and add it to the output, and then normalize the values to some range ex. between 0 and 1. The point here is to avoid vanishing gradient and exploding gradient problems by feeding the original inputs through the model and then ensuring output numbers don’t get too large.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;p&gt;3Blue1Brown. (2024, May 27). How word vectors encode meaning [Video]. YouTube. https://www.youtube.com/watch?v=FJtFZwbvkI4&lt;/p&gt;

&lt;p&gt;Esmailbeigi, R. (2023, January 20). BERT, GPT, and BART: A short comparison. Medium. https://medium.com/@reyhaneh.esmailbeigi/bert-gpt-and-bart-a-short-comparison-5d6a57175fca&lt;/p&gt;

&lt;p&gt;Liang, D., &amp;amp; Klein, D. (n.d.). Transformer explainer. Polo Club of Data Science, Georgia Institute of Technology. https://poloclub.github.io/transformer-explainer/&lt;/p&gt;

&lt;p&gt;TensorFlow. (n.d.). Text generation with a transformer. TensorFlow. Retrieved June 1, 2025, from https://www.tensorflow.org/text/tutorials/transformer#the_cross_attention_layer&lt;/p&gt;

&lt;p&gt;user3667125. (2020, August 16). Answer to “Why does this multiplication of Q and K have a variance of d_k, in scaled dot product attention?” Artificial Intelligence Stack Exchange. https://ai.stackexchange.com/a/25057&lt;/p&gt;

&lt;p&gt;Vaswani, A., Shazeer, N., Parmar, N., Uszoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., &amp;amp; Polosukhin, I. (2017). Attention is all you need. In Advances in Neural Information Processing Systems (pp. 5998–6008). https://arxiv.org/abs/1706.03762&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">In this blog post I give an introduction to the Transformer architecture as originally presented by Vaswani et al., in their landmark paper, “Attention Is All You Need”. My focus will be on visuals and intuition. Specifically, I intend to explain the Transformer in three parts: Decoders, Encoders, and Cross Attention. This blog post covers part one of this list.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://danielchen0.github.io/assets/decoder-only.png" /><media:content medium="image" url="https://danielchen0.github.io/assets/decoder-only.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Creating Meaningful Evaluations for Agentic App Builders</title><link href="https://danielchen0.github.io/2025/05/17/evals-for-agentic-app-builders.html" rel="alternate" type="text/html" title="Creating Meaningful Evaluations for Agentic App Builders" /><published>2025-05-17T00:00:00+00:00</published><updated>2025-05-17T00:00:00+00:00</updated><id>https://danielchen0.github.io/2025/05/17/evals-for-agentic-app-builders</id><content type="html" xml:base="https://danielchen0.github.io/2025/05/17/evals-for-agentic-app-builders.html">&lt;p&gt;For the last two months at &lt;a href=&quot;https://www.create.xyz&quot;&gt;Create&lt;/a&gt;, my main focus has been building evaluations for our AI agent – the thing that takes a user’s natural language prompt and turns it into a working application. This is a hard problem, and the space is largely unresearched, so I want to share what we’ve learned so far.&lt;/p&gt;

&lt;h2 id=&quot;what-are-evaluations&quot;&gt;What are evaluations?&lt;/h2&gt;

&lt;p&gt;Evaluations are automated setups where we give the AI agent a set of tasks (an array of prompts that a user would have typed in manually), and then score how well the agent performs on those tasks. Scores range from 0% to 100%, and there can be multiple scores per run. The key property of a meaningful score is that it correlates with quality: a higher score than before implies improvement, a lower score implies regression.&lt;/p&gt;

&lt;p&gt;In simpler terms, it is a way to give the AI agent grades on various tasks. If the grade changes day-over-day after our engineers ship code changes, it tells us whether the product experience got better or worse.&lt;/p&gt;

&lt;h2 id=&quot;why-this-is-hard&quot;&gt;Why this is hard&lt;/h2&gt;

&lt;p&gt;Traditional software tests assert exact outputs. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add(2, 3)&lt;/code&gt; returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5&lt;/code&gt;, it passes. Agentic systems don’t work this way. The prompt “build a mentoring marketplace with Stripe payments” has no single correct answer, and the agent could produce many valid implementations that all look completely different.&lt;/p&gt;

&lt;p&gt;We tried the common approaches, and each has limitations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LLM-as-a-judge&lt;/strong&gt;: pass the output of the agent to another LLM and ask it to score the result. The problem is that LLMs hallucinate success and miss functionality bugs when reading codebases. They have no way to actually &lt;em&gt;run&lt;/em&gt; the code or test the web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Computer Use Agents (CUA) as judge&lt;/strong&gt;: a computer use agent like OpenAI’s Operator uses a physical browser to interact with the generated website and judge it. This is better because it actually tests the app, but accuracy is still not where it needs to be. Anthropic’s CUA performs at around 90% accuracy on our text-to-app evaluation set, while OpenAI’s Operator is at around 70%. These error rates get embedded into the provided scores.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;String or DOM comparisons&lt;/strong&gt; break whenever the agent chooses a different but valid layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual QA&lt;/strong&gt; doesn’t scale.&lt;/p&gt;

&lt;h2 id=&quot;what-we-built&quot;&gt;What we built&lt;/h2&gt;

&lt;p&gt;We built a daily evaluation framework that simulates user sessions, scores the results, and gives engineers a signal on whether the agent is getting better or worse. It has three main components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt sets&lt;/strong&gt; are sets of prompts drawn from real user sessions, edge cases, and synthetic flows. We have two main categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Text-to-app one shot&lt;/strong&gt;: Given a single prompt, how well can the agent build the app in one go?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Long conversation&lt;/strong&gt;: Given a long array of prompts in series, how well can the agent implement all of them without introducing regressions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each set holds roughly 1 to 50 high quality examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scorers&lt;/strong&gt; calculate the scores. We use three types:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;LLM judges&lt;/strong&gt; for relevance and coherence.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Computer use agents&lt;/strong&gt; that launch the generated app in a real browser, click through flows, and observe state.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Humans-in-the-loop&lt;/strong&gt; for side-by-side comparisons on selected failures.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The human-in-the-loop component is important. Because no automated method is 100% accurate, gold standard evaluation sets must be feasible for human experts to evaluate. There must be a small enough number that humans can review day-over-day, and they need to provide meaningful signal on each run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daily tracking&lt;/strong&gt;: Scores, logs, and qualitative notes go into &lt;a href=&quot;https://www.braintrust.dev/&quot;&gt;Braintrust&lt;/a&gt;. Engineers can review regressions in minutes. If a change lands, we see the effect the same day.&lt;/p&gt;

&lt;h2 id=&quot;scoring-vs-meaningfulness&quot;&gt;Scoring vs meaningfulness&lt;/h2&gt;

&lt;p&gt;Balancing accurate scoring with meaningfulness is difficult.&lt;/p&gt;

&lt;p&gt;You can build automatable evaluations by forcing the agent to produce specific, testable outputs – for example, requiring hardcoded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-testid&lt;/code&gt; attributes on page elements so you can write deterministic assertions. These are stable and can run without human review.&lt;/p&gt;

&lt;p&gt;But such evaluations don’t represent what a real human would type. No real user prompts “build me a landing page and make sure the hero section has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-testid=&apos;hero-section&apos;&lt;/code&gt;.” Evaluations like these don’t tell you how the product experience is changing.&lt;/p&gt;

&lt;p&gt;We went with evaluations that represent real human use, even though it means we need humans in the loop and can’t fully automate scoring. Selecting the right set of evaluation examples requires a lot of experimentation.&lt;/p&gt;

&lt;h2 id=&quot;what-weve-learned&quot;&gt;What we’ve learned&lt;/h2&gt;

&lt;p&gt;Evals have been useful for identifying issues with the agent. By their nature, they are a small set of high quality examples that provide a lot of information on each run. The small size allows for humans to build intuition around the behavior of the agent (which can be noisy due to the fundamental nature of LLMs), and the fact that the evals run repeatedly allows engineers to identify persistent issues as well as flaky ones. Some concrete results:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We caught regressions before they hit users.&lt;/li&gt;
  &lt;li&gt;We flagged prompt templates that degraded output quality.&lt;/li&gt;
  &lt;li&gt;We stretched one long conversation evaluation from 8 to 165+ turns without errors, by iterating on the eval and using it to drive improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;where-this-fits-in-the-bigger-picture&quot;&gt;Where this fits in the bigger picture&lt;/h2&gt;

&lt;p&gt;Create’s platform produces full applications for non-technical users from natural language. That includes auth, payments, databases, deployment, integrations, etc. The agent has to be reliable, and reliability requires metrics and feedback loops.&lt;/p&gt;

&lt;p&gt;Evaluations provide information about the current state of the platform independent of production data. This allows us to see how configuration changes to things like models or tools will affect performance.&lt;/p&gt;

&lt;p&gt;However, these evaluations are still limited in scope. The ultimate test is how the agent performs across real production sessions.&lt;/p&gt;

&lt;h2 id=&quot;industry-context&quot;&gt;Industry context&lt;/h2&gt;

&lt;p&gt;Academic benchmarks like SWE-Bench, WebArena, and AppBench focus on code reasoning or single-turn tasks. They don’t cover the full workflow of generating a working app from a prompt, which is what we need to evaluate. As far as I can tell, there isn’t much existing work on evaluations for text-to-app agents specifically.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Evaluations are a constant work in progress. The question “how well does a generated website represent a prompt?” is still open-ended, and there is no state of the art way to answer it fully automatically. But even imperfect evaluations have already helped us catch real issues, and I expect them to keep being useful as the agent gets more capable.&lt;/p&gt;</content><author><name>Daniel Chen</name></author><summary type="html">For the last two months at Create, my main focus has been building evaluations for our AI agent – the thing that takes a user’s natural language prompt and turns it into a working application. This is a hard problem, and the space is largely unresearched, so I want to share what we’ve learned so far.</summary></entry></feed>