
Deep Learning · Probability & Information Theory
Department of Computer Engineering, Chiang Mai University
Reference: Bishop & Bishop (2024), Ch. 2 (Probabilities) & Ch. 3 (Standard Distributions).
Deep learning is probabilistic at its core:
Everything here is review-level probability — but it is the language the rest of the course speaks. We build each idea from a concrete count first.
100 days. Did it rain (\(Y\))? Did you carry an umbrella (\(X\))? Just count:
| counts | rain | no rain | total |
|---|---|---|---|
| umbrella | 30 | 20 | 50 |
| no umbrella | 10 | 40 | 50 |
| total | 40 | 60 | 100 |
Every probability was a fraction of counts. And notice the pattern: \(\;0.3 = 0.75\times 0.4\), i.e. \(\;p(\text{rain},\text{umb}) = p(\text{umb}\given\text{rain})\,p(\text{rain})\).

Replace numbers with counts \(n_{ij}\) in a grid of \(N\) trials; column total \(c_i=\sum_j n_{ij}\).
The same three fractions, now general:
and \(\dfrac{n_{ij}}{N}=\dfrac{n_{ij}}{c_i}\cdot\dfrac{c_i}{N}\) → product rule.
Two patterns emerge straight from the counts — the sum rule and the product rule (next).
Bishop §2.1, Fig 2.4 — \(n_{ij}\) = count in cell, \(c_i\) = column total.
Everything distills to two rules — these are the whole foundation:
Sum rule (marginalize) \[p(X)=\sum_Y p(X,Y)\] add over the variable you don’t care about
Product rule (factorize) \[p(X,Y)=p(Y\given X)\,p(X)\] a joint = conditional \(\times\) marginal
All of probabilistic modelling — likelihoods, Bayes’ theorem, marginalizing latent variables in deep models — is built from just these two. Worth memorizing.
The product rule always holds: \(\;p(X,Y)=p(Y\given X)\,p(X)\).
Independence is the special case where conditioning changes nothing — knowing one tells you nothing about the other, \(p(Y\given X)=p(Y)\) — so the product rule collapses to a plain product:
\[X \perp Y \iff p(Y\given X)=p(Y) \iff p(X,Y)=p(X)\,p(Y)\]

Back to our toy: \(p(\text{umb})=0.5\) but \(p(\text{umb}\given\text{rain})=0.75\neq0.5\) → rain & umbrella are dependent (right) — exactly why a model can learn one from the other. The i.i.d. assumption (L4) is that training points are independent, letting us multiply per-point likelihoods (MLE, later in this deck).
The question. A disease affects only 1 in 100 people. A test is 90% sensitive and 90% specific. You take the test and it comes back positive — what is the probability that you actually have the disease? (Any guess?)
First, what do “90% sensitive” and “90% specific” mean? Run the test on people whose status we already know → four outcomes:
| sick | healthy | |
|---|---|---|
| test + | ✅ TP | ❌ FP |
| test − | ❌ FN | ✅ TN |
“90 / 90” sounds great — but on healthy people it still raises a false alarm 10% of the time. Hold that thought.
Back to the question: the disease is rare (1%), the test is 90% sensitive and 90% specific, and yours came back positive. Are you actually sick? Instead of a formula, let’s just count people.
Count 10,000 people:
Among all who test positive:
\[\frac{90}{\underbrace{90}_{\text{sick}}+\underbrace{990}_{\text{healthy}}}=\frac{90}{1080}\approx \mathbf{8.3\%}\]
The 990 false alarms swamp the 90 true cases.
Notice what we did: reversed the conditional, from \(p(+\given\text{sick})\) to \(p(\text{sick}\given +)\). Is there a formula for that? → next.
Only ~8% — the prior (rarity) dominates. Same arithmetic appears as precision under class imbalance in ML.
That reversal — going from \(p(+\given\text{sick})\) to \(p(\text{sick}\given +)\) — is Bayes’ theorem. It drops out of the product rule written two ways:
\[p(X,Y)=p(Y\given X)\,p(X)=p(X\given Y)\,p(Y)\;\Rightarrow\; \boxed{\,p(Y\given X)=\dfrac{p(X\given Y)\,p(Y)}{p(X)}\,}\]
Our test, plugged in: \[p(\text{sick}\given +)=\frac{0.9\times0.01}{0.9\times0.01+0.1\times0.99}\approx 0.083\]
— the same 8.3% we just counted.
\(\text{posterior}\propto\text{likelihood}\times\text{prior}\) — Bayes is just the two rules combined, yet it is the engine for reversing conditionals and updating belief from data.
import numpy as np
rng = np.random.default_rng(0) # rng.random(n) = n draws from Uniform[0,1) (same as rng.uniform(0,1,n))
N = 1_000_000
disease = rng.random(N) < 0.01 # 1% prevalence (the prior)
positive = np.empty(N, bool)
positive[disease] = rng.random(disease.sum()) < 0.90 # sick → 90% test positive (sensitivity)
positive[~disease] = rng.random((~disease).sum()) < 0.10 # healthy → 10% test positive (false alarm)
print("P(disease | positive) ≈", round(disease[positive].mean(), 3))P(disease | positive) ≈ 0.083
Simulating a million people lands on ~0.083 — exactly the Bayes calculation. Code confirms the theory.
Infer the model parameters \(\vw\) from the observed dataset \(\mathcal D=\{(\vx_n,t_n)\}\).
\[ \underbrace{p(\vw \given \mathcal D)}_{\text{posterior}} = \frac{\overbrace{p(\mathcal D \given \vw)}^{\text{likelihood}}\;\overbrace{p(\vw)}^{\text{prior}}}{p(\mathcal D)} \]
This single equation is the backbone behind MLE, MAP, and regularization — we use it today and all term
How tall is a random person? A mixed population gives a multimodal density \(p(x)\) (left). Conditioning on a subgroup — given Thai — keeps one slice and renormalizes (right): the continuous version of “only rain days”.

\[ p(x) \ge 0, \quad \int_{-\infty}^{\infty}\! p(x)\,dx = 1, \quad p(a\le x\le b) = \int_a^b p(x)\,dx \]
Now take height and weight together → a density over two variables, a surface \(p(x,y)\). Taller people tend to weigh more, so the cloud tilts (correlation). (Volume under the surface = 1.)

Beyond 2D: a density over \(D\) variables is the same idea — we just can’t draw it past 3D. In deep learning \(\vx\) often lives in thousands of dimensions (e.g. pixels); the sum / product / Bayes rules still hold exactly (sums → integrals).
Expectation \(\E[X]=\sum_x p(x)\,x\) (or \(\int p(x)\,x\,dx\)) = the balance point (center of mass) of the probability mass. Variance \(\mathrm{var}[X]=\E[(X-\E X)^2]\) = how widely the mass is spread. (Fair die → \(\E[X]=3.5\).)

Why we care: every loss is an expectation (“average over the data”). Covariance \(\E[(x-\bar x)(y-\bar y)]\) extends this — do two variables move together?

\[ \mathcal N(x \given \mu, \sigma^2) = \frac{1}{\sqrt{2\pi\sigma^2}}\exp\!\Big\{ -\frac{(x-\mu)^2}{2\sigma^2} \Big\} \]
Why is it everywhere? Add up many small independent random effects and the total is always bell-shaped (the Central Limit Theorem). Measurement noise, heights, exam scores — all roughly Gaussian.
Bishop Fig 2.8 (§2.3)
import numpy as np, matplotlib.pyplot as plt
x = np.random.default_rng(0).normal(loc=2, scale=1.5, size=2000)
grid = np.linspace(-4, 8, 200)
pdf = np.exp(-(grid-2)**2 / (2*1.5**2)) / np.sqrt(2*np.pi*1.5**2)
plt.figure(figsize=(5, 2.6))
plt.hist(x, bins=40, density=True, alpha=0.5, label="2000 samples")
plt.plot(grid, pdf, "r", lw=2, label="N(2, 1.5²)")
plt.legend(); plt.tight_layout(); plt.show()

\[ \mathcal N(\vx \given \boldsymbol\mu, \boldsymbol\Sigma) = \frac{1}{(2\pi)^{D/2}|\boldsymbol\Sigma|^{1/2}}\exp\!\Big\{ -\tfrac{1}{2}(\vx-\boldsymbol\mu)^{\mathsf T}\boldsymbol\Sigma^{-1}(\vx-\boldsymbol\mu) \Big\} \]
Bishop Fig 3.3 (§3.2.1, geometry of the Gaussian)
Push a random variable through \(y=g(x)\). Probability mass is conserved, so the density must rescale by how much \(g\) stretches space:
\[ p_y(y) = p_x(x)\,\Big|\tfrac{dx}{dy}\Big| \qquad\text{(1D)}, \qquad p_y(\vy)=p_x(\vx)\,\big|\det \mathbf J\big| \quad \mathbf J=\tfrac{\partial \vx}{\partial \vy} \]

The input is flat, yet \(p_y\) spikes near 0 — because \(g=x^2\) is flat there (\(g'(0)=0\)), so points pile up; where \(g\) is steep, mass thins. The simulated histogram matches the exact \(|dx/dy|=1/(2\sqrt y)\). This Jacobian rule is the engine of normalizing flows and change-of-variables in diffusion/VAE (L12). (A density’s peak is not transform-invariant — unlike an expectation.)
Bishop §2.4 — transformation of densities

Idea: choose parameters that make the observed data most probable.
\[ \boldsymbol\theta_{\mathrm{ML}} = \arg\max_{\boldsymbol\theta}\; p(\mathcal D \given \boldsymbol\theta) = \arg\max_{\boldsymbol\theta}\sum_n \ln p(x_n\given\boldsymbol\theta) \]
Toy: flip a coin 10 times, see 7 heads. The bias \(p\) that makes “7 heads” most likely is just \(\hat p=\tfrac{7}{10}\) — the fraction. That’s MLE.
For a Gaussian, it gives the equally intuitive answers: \[ \mu_{\mathrm{ML}} = \tfrac{1}{N}\textstyle\sum_n x_n, \quad \sigma^2_{\mathrm{ML}} = \tfrac{1}{N}\textstyle\sum_n (x_n-\mu_{\mathrm{ML}})^2 \]
We take the log to turn products into sums — the trick behind the least-squares derivation (L2).
Bishop Fig 2.9 (§2.3.3)

MLE is powerful but not perfect — it underestimates the variance:
\[ \E\!\big[\sigma^2_{\mathrm{ML}}\big] = \frac{N-1}{N}\,\sigma^2 \;<\; \sigma^2 \]
The bias vanishes as \(N\to\infty\). Knowing when ML misleads is exactly the judgement this course builds.
Bishop Fig 2.10 (§2.3.3)
import numpy as np
rng = np.random.default_rng(0)
true_var, N, trials = 4.0, 5, 50_000
# np.var divides by N → this is exactly σ²_ML
vars_ml = [rng.normal(0.0, np.sqrt(true_var), N).var() for _ in range(trials)]
print("mean σ²_ML =", round(np.mean(vars_ml), 3), " (true =", true_var, ")")
print("ratio =", round(np.mean(vars_ml)/true_var, 3),
" ≈ (N-1)/N =", round((N-1)/N, 3))mean σ²_ML = 3.21 (true = 4.0 )
ratio = 0.802 ≈ (N-1)/N = 0.8
Averaging 50,000 small samples, \(\sigma^2_{\mathrm{ML}}\) lands at \(\tfrac{N-1}{N}\sigma^2\) — the bias is real and predictable.
How much do you learn from seeing outcome \(x\)? Start from what we want, then derive the formula.
Wish-list for “information” \(h(x)\):
The only function turning a product into a sum is the log. So:
\[ \boxed{\,h(x) = -\log p(x)\,} \;\ge 0 \]
(minus sign since \(p\le 1\); base 2 → bits, base \(e\) → nats)
Toy (fair coin, \(p=\tfrac12\)): \(h = -\log_2\tfrac12 = \mathbf{1\ bit}\). Certain (\(p=1\)): \(0\) bits. Rare (\(p=\tfrac1{4}\)): \(2\) bits.
Bishop §2.5 — information content

Entropy = the average information content — how surprised you expect to be:
\[ \mathrm H[p] = \mathbb E_{p}\!\big[\,h(x)\,\big] = -\sum_x p(x)\,\ln p(x) \]
Toy: a fair coin = \(\mathbb E[h] =\) 1 bit; a two-headed coin = 0 (no surprise).
Bishop §2.5, Fig 2.14

A function is convex if it lies below its chords. The picture says it all:
\[ f(\E[x]) \;\le\; \E[f(x)] \qquad\textbf{(Jensen's inequality)} \]
Toy: take \(f(x)=x^2\). Jensen gives \(\E[x^2]\ge(\E[x])^2\) — i.e. \(\mathrm{var}[x]\ge 0\). Obvious fact, deep tool.
Jensen is the lever for two things we need: it makes KL \(\ge 0\) (next slide), and it builds the ELBO — the bound that trains VAEs & diffusion (L12).
Bishop §2.5.5 (convexity), used throughout for bounds
How far is a model \(q\) from the truth \(p\)? The Kullback–Leibler divergence:
\[ \mathrm{KL}(p\,\|\,q) = -\sum_x p(x)\,\ln\frac{q(x)}{p(x)} \;\ge\; 0, \qquad =0 \iff q=p \]
Since \(-\ln\) is convex, Jensen (previous slide) guarantees \(\mathrm{KL}\ge 0\) — it acts like a “distance” to the truth (though it is not symmetric).
\[ \mathrm{KL}(p\,\|\,q) = \underbrace{\Big(-\textstyle\sum_x p\ln q\Big)}_{\text{cross-entropy } \mathrm H(p,q)} \;-\; \underbrace{\Big(-\textstyle\sum_x p\ln p\Big)}_{\text{entropy } \mathrm H(p)} \]
Minimizing KL to the data = maximizing likelihood = minimizing cross-entropy — the loss for classification (L3) and the backbone of VAEs later
Bishop §2.5.5
import numpy as np
def H(p): p = np.asarray(p); return -(p*np.log(p)).sum()
def KL(p, q): p, q = np.asarray(p), np.asarray(q); return (p*np.log(p/q)).sum()
p = [0.70, 0.20, 0.10] # "truth"
q = [0.40, 0.40, 0.20] # "model"
print("H(p) =", round(H(p), 3), " H(q) =", round(H(q), 3))
print("KL(p||q) =", round(KL(p, q), 3))
print("KL(q||p) =", round(KL(q, p), 3), " → NOT symmetric!")H(p) = 0.802 H(q) = 1.055
KL(p||q) = 0.184
KL(q||p) = 0.192 → NOT symmetric!
\(\mathrm{KL}(p\|q)\neq\mathrm{KL}(q\|p)\) — direction matters. This asymmetry shapes how VAEs behave (later).
Two more quantities, both built from entropy:
Conditional entropy — uncertainty left in \(y\) after seeing \(x\): \[ \mathrm H[y\given x] = -\sum_{x,y} p(x,y)\,\ln p(y\given x) \] with the chain rule \(\;\mathrm H[x,y]=\mathrm H[x]+\mathrm H[y\given x]\).
Mutual information — how much \(x\) reduces uncertainty about \(y\): \[ \mathrm I[x,y] = \mathrm H[y]-\mathrm H[y\given x] = \mathrm{KL}\big(p(x,y)\,\|\,p(x)p(y)\big) \ge 0 \] \(\mathrm I=0 \iff x,y\) independent.
Back to rain & umbrella: they were dependent, so \(\mathrm I[\text{rain},\text{umb}]\approx 0.09\) nats \(>0\) — knowing one genuinely lowers uncertainty about the other. Representation learning (L11) trains features by maximizing mutual information with the input (contrastive / InfoNCE).
Bishop §2.5.6–2.5.7
We’ve met the Gaussian — the workhorse. A few more continuous densities show up later:

Bishop §3.2–3.5. The Gaussian, Beta and Dirichlet — with Bernoulli/Categorical (next) — belong to the exponential family, a unifying umbrella; mixtures and Student-t are not (notable exceptions).
For the classification lecture we’ll need distributions over categories:
Bernoulli — one binary outcome \(t\in\{0,1\}\): \[ p(t\given\mu) = \mu^{t}(1-\mu)^{1-t} \]
Categorical — one of \(K\) classes: \[ p(\vt\given\boldsymbol\mu) = \prod_{k=1}^{K}\mu_k^{\,t_k} \]
Lecture 2 — Linear Regression. We turn maximum likelihood under Gaussian noise into the squared-error loss and its closed-form least-squares solution.
Reading: Bishop & Bishop (2024), Ch. 2–3 — https://www.bishopbook.com/
Deep Learning — Lecture 1