Approaches to biomedical knowledge

Session #5: Logistic regression - sigmoid functions, gradient descent, Python

Peter N Robinson

Free University Berlin

2026-04-26

Overview: Logistic regression

Game plan

Logistic regression shares some characteristics with neural networks including the weighted sum and activation function (for single neurons) and gradient-descent training loop. Studying logistic regression therefore serves as a good preparation for understanding neural networks.

Part 1: Introduction

  • Components of logistic regression
  • Sentiment analysis

Part 2: Sigmoid function

  • Definition
  • First derivative

Part 3: Gradient descent

  • Learning
  • Momentum & Adam
  • Learning rates

Part 4: Python

  • Full implementation

Part 5: Overfitting

Logistic Regression

Logistic Regression (LogReg) is one of the most common machine learning algorithms. It can be used to predict the probability of an event occurring based on a given labeled data set.

  • Email analysis (Is an email spam or not?)
  • Sentiment analysis (is a movie review positive or negative?)
  • Medical diagnostics (is a given diagnosis present or absent?)

We will go over the algorithm in detail, because it is an excellent preparation for understanding neural networks.

Logistic regression: review

The basics are explained very well by Wikipedia (we summarize the Wikipedia entry here!)

  • A group of 20 students spends between 0 and 6 hours studying for an exam. How does the number of hours spent studying affect the probability of the student passing the exam?
Table 1: Exam pass/fail outcome by hours studied.
Hours: \(x_i\) 0.50 0.75 1.00 1.25 1.50 1.75 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 4.00 4.25 4.50 4.75 5.00 5.50
Pass: \(y_i\) 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1
  • The logistic function has the form \[ p(x) = \frac{1}{1+e^{-\tfrac{x-\mu}{s}}} \tag{1}\]

Logistic regression: review

  • In Equation 1, \(\mu\) is the location parameter (midpoint of the curve, \(\tfrac{1}{2}\), and \(s\) is the scale parameter.
  • We generally rewrite this with \(\beta_0 = -\tfrac{\mu}{s}\) and \(\beta_1=\tfrac{1}{s}\), yielding

\[ p(x) = \frac{1}{1+e^{-\beta_0 + \beta_1x}} \tag{2}\] - In our example, \(y_k=p(x_k)\) is the probability of passing given \(x_k\) hours studied

Log odds

  • In our example, \(\beta_1\) is the log odds of passing for each additional hour studied

\[ \log\left(\frac{p}{1-p}\right) = \beta_o + \beta_1x \]

  • In our example, \(\beta_1 = 1.505\), so each additional hour of studying increased log odds of passing by 1.5

  • It is more interpretable to use the odds ratio defined as \[ e^{\beta_1} = e^{1.505}\approx 4.5 \]

  • For each additional hour, we multiply the odds of passing by 4.5

  • We can also perform multiple logistic regression with a vector of variables

\[ p(\mathbf{x}) = \frac{1}{1+e^{-\beta_0 + \beta_1x + \beta_2x_2+\ldots}} \tag{3}\]

The five components of Logistic Regression

1. Feature Representation

For each input \(x\), we have a vector: \(\mathbf{x} = [x_1, x_2, \ldots, x_n]\)

2. Classification Function

Computes the estimated class using the Sigmoid function: \(\sigma(z) = \frac{1}{1 + e^{-z}}\)

3. Objective Function

A Loss function (Cross-Entropy) to measure how well the model is performing ( cross-entropy loss function).

4. Optimization

Gradient Descent: The method used to minimize the loss and find the best weights.

5. Prediction

The learned model can be used to classify new data points.

LogReg: Features

For each input \(x\), we create a vector of features: \(\mathbf{x} = [x_1, x_2, \ldots, x_n]\).

There are many different ways of generating a feature vector

  • Raw numerical data: If the input data is numerical with \(n\) dimensions, each of the dimensions can act as a feature
  • Polynomial & interaction features: We can add interaction terms (\(x_ix_j\)) or polynomial features (e.g., \(x_i^7\)) if this makes sense for the classification task
  • Images: Flatten pixel values (e.g., an \(8\times 8\) image would have 64 features)
  • Text to vector: e.g., count word occurrences across a vocabulary
  • Domain-specific feature engineering

Example

In the Python exercise for this lecture, we will generate two dimensional points with overlapping Gaussian distributions, but in general, the features can also be created (e.g., by counting positive and negative words for sentiment analysis).

Weights and bias

Weights

LogReg learns a vector of a vector of weights and a bias term to solve the classification task

  • Linear combination of input features
  • Each data point is multiplied by weights and a bias is added
  • Here, \(x_{i,j}\) refers to the \(j^{th}\) component of the \(i^{th}\) data point. \[ z_i = \sum_{j=1}^n w_ix_{i,j} + b \tag{4}\]

Equation 4 can be represented identically using dot product notation (where the bold font indicates a vector of weights (\(\mathbf{w}\)) and inputs (\(\mathbf{x}\)))

\[ z_i = \mathbf{w}\cdot \mathbf{x}_i + b \]

This is identical to the sums we will see at individual neurons in neural networks

Sigmoid

Sigmoid function

To create a probability, we transform z through the sigmoid function, \(\sigma(z)\)

  • The sigmoid \(\sigma(z)\) takes a real-valued number \(z\in [-\infty, \infty]\) and effectively squashes it to lie in the range \([0,1]\): \(0<\sigma(z) < 1\).

\[ \sigma(z) = \frac{1}{1+e^{-z}} = \frac{1}{1+\exp(-z)} \]

  • Interpretation: \(P(y=1 | x, w, b)\), i.e., a probability for classification
  • \(\sigma(z) > 0.5 \Leftrightarrow z > 0\)
  • i.e., whenever \(z = \mathrm{w}\cdot \mathrm{x} + b\) is over zero, the model predicts the positive class (\(\hat{y}=1\)).

Sigmoid: A convenient identity

  • \(1−\sigma(x) = \sigma(−x)\)

\[ \begin{align*} 1−\sigma(x) &=& 1- \frac{1}{1+e^{-x}}\\ &=& \frac{1+e^{-x} - 1}{1+e^{-x}} \\ &=& \frac{e^{-x}}{1+e^{-x}} \cdot \frac{e^{x}}{e^{x}}\\ &=& \frac{1}{1+e^{x}} \\ &=& \sigma(-x) \\ \end{align*} \]

Sigmoid: A convenient identity

\(1−\sigma(x) = \sigma(−x)\)

\(1−\sigma(x)\) \(= 1- \dfrac{1}{1+e^{-x}}\) \(\bullet\) definition of \(\sigma(x)\)
\(= \dfrac{1+e^{-x} - 1}{1+e^{-x}}\) \(\bullet\) common denominator
\(= \dfrac{e^{-x}}{1+e^{-x}} \cdot \dfrac{e^{x}}{e^{x}}\) \(\bullet\) multiply by \(1=\frac{e^x}{e^x}\)
\(= \dfrac{1}{1+e^{x}}\) \(\bullet\) simplify
\(= \sigma(-x)\) \(\bullet\) definition of \(\sigma(-x)\)

Logit

  • Odds: The ratio of success to failure: \(p / (1-p)\).
  • Logit: The natural logarithm of those odds (log odds): \(\ln (\frac{p}{1-p})\).
  • The logit is the inverse of the sigmoid function:
  • \(z=\sigma(\mathbf{w}\cdot\mathbf{x}+b)\) can be any real number \((-\infty, \infty)\)
  • \(p\in [0, 1]\) represents a probability
  • These functions are inverses of each other because \(\sigma(\text{logit}(p)) = p\)

Proof

\(\sigma(\text{logit}(p))\) \(= \dfrac{1}{1 + e^{-\left[ \ln \left( \frac{p}{1-p} \right) \right]}}\) \(\bullet\) Substitute Logit into Sigmoid \(z\)
\(= \dfrac{1}{1 + e^{\left[ \ln \left( \frac{1-p}{p} \right) \right]}}\) \(\bullet\) Apply \(-\ln(A) = \ln(1/A)\)
\(= \dfrac{1}{1 + \frac{1-p}{p}}\) \(\bullet\) Identity: \(e^{\ln(x)} = x\)
\(= \dfrac{1}{\frac{p + 1 - p}{p}}\) \(\bullet\) \(1=\tfrac{p}{p}\)
\(= \dfrac{1}{1/p}\) \(\bullet\) Simplify
\(= p\)
Therefore The logit is the inverse of the sigmoid

Learning a classification rule

  • We need to learn the parameters of the model \(\mathbf{w}\) and \(b\):

\[ \begin{array}{c c c c c} \mathbf{x}& \longrightarrow & \hat{y} = \sigma(z)=\sigma(\mathbf{w}\cdot\mathbf{x}+b) & \longrightarrow \\ \text{\small Input features} & & \text{\small Output probability} & \end{array} \]

  • The class label \(y\) is 1 (true) or 0 (false)
  • The prediction of the class label \(\hat{y}=P(y = 1|x)\) is a real number between 0 and 1

Classification Decision Rule

\[ \mathrm{classification}(x) = \begin{cases} 1 & \text{if }\hat{y} > 0.5 \\ 0 & \text{otherwise} \end{cases} \]

Loss function

  • A good model will minimize the difference between our prediction \(\hat{y}\) and the ground truth \(y\)

  • this distance is defined by the loss function (also known as the cost function).

  • The same loss function is commonly used for logistic regression and for neural networks, the cross-entropy loss.

  • Recall that our classifier output is \(\hat{y} = \sigma(\mathbf{w}\cdot\mathbf{x} + b)\)

  • For logistic regression with binary classification, \(y\) can be either 0 or 1, but \(\hat{y}\) is a probability that ranges from 0 to 1.

  • We measure the difference with the loss function \(\mathcal{L}(\hat{y}, y)\)

Loss function

  • Using \(\hat{y}=\sigma(z)\), we can concisely write the loss function as: \[ \log p(y|x) = \log[\hat{y}^y(1-\hat{y})^{1-y}] = y\log\hat{y} + (1-y)\log(1-\hat{y}) \]

  • Note this simplifies to either \(\log\hat{y}\) or \(\log(1-\hat{y})\) depending on whether \(y\) is 0 or 1.

  • Since it is convenient to minimize the function, we multiply it by -1: The result is known as the cross-entropy loss

\[ \mathcal{L}_{CE}(\hat{y}, y) = - y\log\hat{y} - (1-y)\log(1-\hat{y}) \]

  • Since we have \(\mathbf{\hat{y}} = \sigma(\mathbf{w}\cdot \mathbf{x} + b)\), this is equivalent to

\[ \mathcal{L}_{CE}(\hat{y}, y) = - y\log\sigma(\mathbf{w}\cdot \mathbf{x} + b) - (1-y)\log(1-\sigma(\mathbf{w}\cdot \mathbf{x} + b)) \]

Loss function

  • \(- y\log\sigma(\mathbf{w}\cdot \mathbf{x} + b) - (1-y)\log(1-\sigma(\mathbf{w}\cdot \mathbf{x} + b))\) is equivalent to the following piecewise loss function \[ \mathcal{L}(\sigma(z), y) = \begin{cases} -\log \sigma(z) & \text{if } y_i = 1 \\ -\log 1- \sigma(z) & \text{if } y_i = 0 \\ \end{cases} \]

  • If \(y_i=1\), then As \(\log \sigma(z) \rightarrow 1\), the loss approaches zero

  • Also, if \(y_i=0\), then the loss approaches zero as \(\sigma(z)\rightarrow 0\)

Loss function (sanity check)

\[ \mathcal{L}_{CE}(\hat{y}, y) = - y\log\sigma(\mathbf{w}\cdot \mathbf{x} + b) - (1-y)\log(1-\mathbf{w}\cdot \mathbf{x} + b)) \]

  • Note that if we predict (correctly) for a true example that \(\hat{y}=1\), then the second term drops out and we have

\[ \mathcal{L}_{CE}(\hat{y}, y) = - 1\log 1 = 0 \]

  • Similar things apply for a correct prediction of a negative example as \(\hat{y}=0\)
  • The loss for one example ranges from 0 to infinity (\(-\log 0\))

Optimizing the loss

Optimization Goal

To create a high-performing classifier, we minimize the Cost Function \(J(\theta)\), which is the average loss over the entire training set of \(m\) examples.

  • If we symbolize the parameters (weights, bias) of the logistic regression as \(\theta\), our objective function is:

\[ J(\theta) = \frac{1}{m} \sum_{i=1}^{m} \mathcal{L}(\hat{y}^{(i)}, y^{(i)}) \]

  • We seek \(\hat{\theta}\), the parameters that minimize the loss

\[ \hat{\theta} = \arg\min_{\theta} J(\theta) \]

  • It can be shown that the logistic regression loss function is convex (which enables us to reliably find its minimum)

Gradient descent

Basic idea of gradient descent

The gradient descent algorithm finds the gradient of the loss function at the current point and moves the parameters in the opposite direction.

  • Given a learning rate \(\eta\) and the gradient of the weights and bias:

  • Each iteration of the GD processes Updates the weights and bias \[ \begin{eqnarray*} \mathbf{w} &\leftarrow &\mathbf{w} - \eta\Delta \mathbf{w} \\ \mathbf{b} &\leftarrow &\mathbf{b} - \eta\Delta \mathbf{b} \end{eqnarray*} \]

  • We will explain how the gradient is calculated and then return to the mechanics of the gradient descent algorithm.

The Gradient

Another commonly encountered notation is the gradient, which by convention is represented as a column vector

\[ \nabla f(\mathbf{x}) = \begin{bmatrix} \dfrac{\partial f}{\partial \mathbf{x}} \end{bmatrix}^T = \begin{bmatrix} \dfrac{\partial f}{\partial x_1}\\ \dfrac{\partial f}{\partial x_2} \\ \cdots \\ \dfrac{\partial f}{\partial x_n} \end{bmatrix} \tag{5}\]

Note

  • \(f(x)\) is a scalar
  • We take the first derivative of \(f(x)\) with respect to each of the \(n\) components of \(\mathbf{w}\)
  • We will have more to say about matrix calculus in a future lecture.

Gradient descent

  • We iteratively take steps towards the minimum along the slope of the function
  • But how do we calculate the slope?

Calculating derivatives

We need to update each component of the weight vector \(\mathbf{w}\), e.g., \(w_j\) based on the first derivative of the loss \(\mathcal{L}=\mathcal{L}_{CE}(\hat{y}, y)\) with respect to the component.

  • Apply the chain rule twice

\[ \frac{\partial \mathcal{L}}{\partial w_j} = \frac{\partial \mathcal{L}}{\partial \sigma_i} \cdot \frac{\partial \sigma_i}{\partial w_j} = \frac{\partial \mathcal{L}}{\partial \sigma_i} \cdot \frac{\partial \sigma_i}{\partial z_i} \cdot \frac{\partial z_i}{\partial w_j} \tag{6}\]

Derivation and chain rule

  • HOMEWORK To understand the derivations (and to understand backprop in the next lecture!), it is essential to be familiar with the chain rule. We will practice in the practical.
  • If \(f\) and \(g\) are differentiable functions, then \[ \left(f(g(x))\right)^{\prime} = f^{\prime}(g(x))\cdot g^{\prime}(x) \]

  • The chain rule can also be written as follows. If \(y=f(u)\) and \(u=g(x)\), then \[ \dfrac{dy}{dx} =\dfrac{dy}{du}\dfrac{du}{dx} \]

Examples

  • Power Rule: \(y = (5+3x)^5\)
    • Let \(u = 5+3x\), so \(y = u^5\)
    • \(\frac{dy}{du} = 5u^4\) and \(\frac{du}{dx} = 3\) \[\frac{dy}{dx} = 5(5+3x)^4 \cdot 3 = 15(5+3x)^4\]

Question

  • How does the chain rule work for \(\frac{dy}{dx} = \frac{d}{dx}\sin(4x+3)\)?

Answer

\[ \frac{dy}{dx} = \frac{d}{dx}\sin(4x+3) \]

  • Use the chain rule to evaluate this expression!
  • What is \(u\)?
  • Let \(u = 4x+3\), so \(y = \sin(u)\)
  • What is \(\tfrac{dy}{du}\)?
  • \(\frac{dy}{du} = \cos(u)\)
  • What is \(\tfrac{du}{dx}\)?
  • \(\tfrac{du}{dx}=\tfrac{d}{dx}4x+3 = 4\)
  • Use the chain rule!
  • \(\frac{dy}{dx} = \tfrac{dy}{du}\cdot \tfrac{du}{dx} = \cos(u) \cdot 4 = \cos(4x+3) \cdot 4 = 4\cos(4x+3)\)

Calculating derivatives

  • Let’s return to the calculation of the derivative of the loss function for coefficient \(w_j\) of logistic regression (Equation 6)

\[ \frac{\partial \mathcal{L}}{\partial w_j} = \underbrace{\frac{\partial \mathcal{L}}{\partial \sigma_i}}_{\text{Part A}} \cdot \underbrace{\frac{\partial \sigma_i}{\partial z_i}}_{\text{Part B}} \cdot \underbrace{\frac{\partial z_i}{\partial w_j}}_{\text{Part C}} \]

  • In the following slides, we will calculate the three parts separately.

Part A: \(\frac{\partial \mathcal{L}}{\partial \hat{y}}\)

\(\dfrac{\partial \mathcal{L}}{\partial \hat{y}}\) \(= -\dfrac{\partial }{\partial \hat{y}} [y \ln \hat{y} + (1-y) \ln(1-\hat{y})]\) \(\bullet\) Using \(\hat{y}=\sigma(wx+b)\)
\(= -y \dfrac{\partial }{\partial \hat{y}}\ln \hat{y} - (1-y)\dfrac{\partial }{\partial \hat{y}}\ln(1-\hat{y})\) \(\bullet\) Move constants out of derivative
\(= -\dfrac{y}{\hat{y}} - (1-y) \dfrac{-1}{1-\hat{y}}\) \(\bullet\) Recall \(\dfrac{d \ln x}{dx} = \dfrac{1}{x}\)
\(= -\dfrac{y}{\hat{y}} + \dfrac{1-y}{1-\hat{y}}\) \(\bullet\) Simplify signs
\(= \dfrac{-y(1-\hat{y}) + \hat{y}(1-y)}{\hat{y}(1-\hat{y})}\) \(\bullet\) Common denominator
\(= \dfrac{-y + y\hat{y} + \hat{y} - y\hat{y}}{\hat{y}(1-\hat{y})}\) \(\bullet\) Expand numerator
\(= \dfrac{\hat{y} - y}{\hat{y}(1-\hat{y})}\) \(\bullet\) Final result

Part B: derivative of the sigmoid activation function

\(\dfrac{d\sigma(x)}{dx}\) \(= \dfrac{d}{dx} \dfrac{1}{1+e^{-x}}\)
\(= \dfrac{-1}{(1+e^{-x})^2}\cdot (-e^{-x})\) \(\bullet\) chain rule with \(u=1+e^{-x}\)
\(= \dfrac{e^{-x}}{(1+e^{-x})^2}\) \(\bullet\) simplify
\(= \dfrac{1}{1+e^{-x}} \cdot \dfrac{e^{-x}}{1+e^{-x}}\) \(\bullet\) rearrange
\(= \sigma(x) \cdot \dfrac{e^{-x}}{1+e^{-x}}\) \(\bullet\) definition of \(\sigma(x)\)
\(= \sigma(x) \cdot \dfrac{1 + e^{-x} - 1}{1+e^{-x}}\) \(\bullet\) add 1, subtract 1
\(= \sigma(x) \cdot \left( \dfrac{1 + e^{-x} }{1+e^{-x}} -\dfrac{1}{1+e^{-x}} \right)\) \(\bullet\) rearrange
\(= \sigma(x) \cdot \left( 1 -\sigma(x) \right)\) \(\bullet\) simplify using definition of \(\sigma(x)\)

derivative of the sigmoid activation function

  • Thus we get the fascinating result that

\[ \frac{d\sigma(x)}{dx} = \sigma(x)(1-\sigma(x)) \]

  • Substituting and remembering that we define \[ \hat{y} = \sigma(\mathbf{w}\cdot\mathbf{x} + b) \] we get \[ \underbrace{\frac{\partial \sigma_i}{\partial z_i}}_{\text{Part B}} = \hat{y}(1- \hat{y}) \]

Part C: \(\frac{\partial z}{\partial w_j}\): Gradient of the \(z\) with respect to the Weight \(w_j\)

The Since \(z = w_1x_1 + w_2x_2 + \dots + b\), the derivative with respect to \(w_j\) is simply the feature it is multiplied by: \[ \frac{\partial z}{\partial w_j} = x_j \]

Putting it all together

\[ \frac{\partial \mathcal{L}}{\partial w_j} = \underbrace{\left[ \frac{\hat{y} - y}{\hat{y}(1-\hat{y})} \right]}_{\text{Part A}} \cdot \underbrace{\left[ \hat{y}(1-\hat{y}) \right]}_{\text{Part B}} \cdot \underbrace{x_j}_{\text{Part C}} \]

  • Thanks to cancelations, we are left with

\[ \begin{align*} \frac{\partial \mathcal{L}}{\partial w_j} &= (\hat{y} - y)x_j \end{align*} \]

Intuition

The gradient is a product of the error and the magnitude of the input.

  • The Error (\(\hat{y} - y\)): How wrong were we?
  • The Input (\(x_j\)): How much did this specific feature contribute to that wrong prediction?

Bias term

  • HOMEWORK You will adapt this example The term for the partial derivative of the bias can be determined analogously to be

\[ \frac{\partial \mathcal{L}}{\partial b} = (\hat{y} - y) \]

  • In the homework, you will be asked to derive this formally.

Gradient descent

Basic idea of gradient descent

  • Update the weights and biases \[ \begin{eqnarray*} \mathbf{w} &\leftarrow &\mathbf{w} - \eta\Delta \mathbf{w} \\ \mathbf{b} &\leftarrow &\mathbf{b} - \eta\Delta \mathbf{b} \end{eqnarray*} \]

  • Let’s do one simple example – finding the minimum of a function

\[ f(x) = 7x^2 + 3x-9 \]

  • It is straightforward to find the minimum analytically by setting the derivative to zero

\[ \begin{eqnarray*} \dfrac{df}{dx} (7x^2 + 3x-9) &=& 14x +3 &=& 0 \\ x &=& - \dfrac{3}{14} \end{eqnarray*} \]

  • To use gradient descent to solve this equation, we need to define the update equation based on the first derivative and a step size \(\eta\)1

\[ x \leftarrow x-\eta (14x +3 ) \]

Gradient descent example

import numpy as np
import matplotlib.pylab as plt

def f(x):
  return 7*x**2 + 3*x - 9

def d(x):
  return 14*x + 3

# first guess

eta = 0.03
# plot
x = np.linspace(-1, 1.5, 1000)
plt.figure(figsize=(3, 3))
plt.plot(x, f(x))
t = 1
for i in range(15):
  plt.plot(t, f(t), marker='o', color='r')
  t = t - eta*d(t)
print(f"Solution: {t:.4f} (-3/14={-3/14:.4f})")
plt.axvline(x=t, color='blue', linestyle='--', linewidth=0.8)
Solution: -0.2139 (-3/14=-0.2143)

Gradient descent: Overshoot

Final Solution: -0.0199 (Target: -0.2143)
  • Same code as in the previous example, but learning rate increased from \(\eta = 0.03\) to \(\eta=0.13\)

Stochastic gradient descent

  • If we write the loss as

\[ \mathcal{L} = L(\Theta; \mathbf{x},y) \]

  • This means that we are including all training data (\(\mathbf{x},y\))
  • Gradient descent needs \(\frac{\partial L}{\partial \Theta}\), which is obtained by backprop
  • batch training refers to averaging over all training data
  • As the volume of training data increased, it became less sensible to pass all data to the model for each gradient descent step.
  • minibatch training refers to using a subset of all data for each gradient descent step.
  • Because this procedure is noisy compared to full batch training, we refer to it as stochastic gradient descent (SGD).
  • The noisiness may even be an advantage because it may help avoid falling into local minima
  • minibatch size is a hyperparameter, but typically the order of examples is randomized and chunks of data are chosen until all samples have been used.

Updates

If the following is the derivative rule for one example \[ \frac{\partial \mathcal{L}}{\partial w_j} = (\sigma(z_i) - y_i)x_{i,j} \] then the following is the cost across a batch with m examples \[ \frac{\partial C}{\partial w_j} = \frac{1}{m}\sum_{i=1}^m(\sigma(z_i) - y_i)x_{i,j} \] - The update rule for \(w_j\) is thus \[ w_j \leftarrow w_j - \eta \frac{\partial C}{\partial w_j} \]

Stochastic gradient descent

  • We will usually possess multiple labeled examples to train the logistic regression
  • Stochastic gradient descent means that we calculate the gradient after each training example and adjust the parameters (\(\theta\)) by adjusting \(\theta\) in the direction opposite the gradient

\[ \begin{array}{ll} \hline \mathbf{Algorithm:} & \text{Gradient Descent Update} \\ \hline 1: & \text{Initialize } \mathbf{w} \in \mathbb{R}^d, b \in \mathbb{R} \\ 2: & \textbf{for } i \leftarrow 1 \text{ to } \text{iterations } \textbf{do} \\ 3: & \quad \hat{\mathbf{y}} \leftarrow \sigma(\mathbf{Xw} + b) \\ 4: & \quad \mathbf{w} \leftarrow \mathbf{w} - \eta \frac{1}{m} \mathbf{X}^T(\hat{\mathbf{y}} - \mathbf{y}) \\ 5: & \textbf{end for} \\ \hline \end{array} \]

Batch and Mini-batch training

  • Stochastic gradient descent is called stochastic because it chooses a single random example at a time
  • Batch training trains over all examples before adjusting parameters
  • Since the total Cost \(J\) is the average of all individual losses (\(\frac{1}{m} \sum \mathcal{L}\)), the derivative of the total cost is simply the average of the individual derivatives:\[\frac{\partial J}{\partial w_j} = \frac{1}{m} \sum_{i=1}^{m} (\hat{y}^{(i)} - y^{(i)}) x_j^{(i)}\]
  • In Mini-batch training, we train on a group of examples at a time, and take the average loss of these examples.
  • Modern hardware lets mini-batch training be vectorized for efficiency

Part 4: Python implementation from scratch

  • We will show how to perform LR “from scratch” to promote understanding
  • Usually, it is recommendable to use library code (scikit-learn etc.) for actual analysis
  • HOMEWORK You will adapt this example
  • Here we have created points two classes and want to learn LR parameters for classification

Sigmoid

  • To code up a simple version of logistic regression from scratch, we will need five main items. The sigmoid is the simplest.

\[ \sigma(z) = \frac{1}{1+e^{-z}} = \frac{1}{1+\exp(-z)} \]

import numpy as np
import numpy.typing as npt

def sigmoid(z: npt.NDArray) -> npt.NDArray:
    return 1 / (1 + np.exp(-z))
  • NumPy N-Dimensional Array: the function takes an array and returns an array
  • The function takes the data (X,y) and the current values of the parameters w and b

Cost function

def cost_function(
    X: npt.NDArray, 
    y: npt.NDArray, 
    w: npt.NDArray, 
    b: float
) -> float:
    m = len(y)  # Define m based on the number of labels
    cost_sum = 0.0

    for i in range(m):
        # np.dot between vectors returns a scalar, b is a float
        z = float(np.dot(w, X[i]) + b)
        g = sigmoid(z)

        cost_sum += -y[i] * np.log(g) - (1 - y[i]) * np.log(1 - g)

    return (1 / m) * cost_sum
  • i.e., we calculate the Binary Cross-Entropy Cost Function \[ C(w,b) = \frac{1}{m} \mathcal{L}(\sigma(z_i), y_i) \]

Gradient Function

def gradient_function(
    X: npt.NDArray, 
    y: npt.NDArray, 
    w: npt.NDArray, 
    b: float
) -> typing.Tuple[float, npt.NDArray]:
    m, n = X.shape  # m = examples, n = features
    grad_w = np.zeros(n)
    grad_b = 0.0

    for i in range(m):
        z = float(np.dot(w, X[i]) + b)
        g = sigmoid(z)
        error = g - y[i]
        grad_b += error
        
        for j in range(n):
            grad_w[j] += error * X[i, j]

    # Average the gradients over all examples
    grad_b = (1 / m) * grad_b
    grad_w = (1 / m) * grad_w

    return grad_b, grad_w

Compute derivatives of the cost function

  • \(\dfrac{\partial C}{\partial w_j} = \frac{1}{m}\sum_{i=1}^m(\sigma(z_i) - y_i)x_{i,j}\)
  • \(\dfrac{\partial C}{\partial b} = \frac{1}{m}\sum_{i=1}^m(\sigma(z_i) - y_i)\)

Gradient descent

def gradient_descent(X: npt.NDArray, 
    y: npt.NDArray, 
    alpha: float, 
    iterations: int
) -> typing.Tuple[npt.NDArray, float]:
    w = np.zeros(n)
    b = 0

    for i in range(iterations):
        grad_b, grad_w = gradient_function(X, y, w, b)

        w = w - alpha * grad_w
        b = b - alpha * grad_b

        if i % 1000 == 0:
            print(f"Iteration {i}: Cost {cost_function(X, y, w, b)}")
    
    return w, b
  • \[w_j \leftarrow w_j - \eta \frac{\partial C}{\partial w_j}\]

  • \[b \leftarrow b - \eta \frac{\partial C}{\partial b}\]

Prediction

def predict(
    X: npt.NDArray, 
    w: npt.NDArray, 
    b: float
) -> npt.NDArray:
    preds = np.zeros(m)

    for i in range(m):
        z = np.dot(w, X[i]) + b
        g = sigmoid(z)

        preds[i] = 1 if g >= 0.5 else 0
    
    return preds

\[ pred(i) = \begin{cases} 1& \text{if }\sigma(z_i) >= 0.5 \\ 0& \text{if }\sigma(z_i) < 0.5 \\ \end{cases} \]

Running

learning_rate = 0.01
iterations = 10000

final_w, final_b = gradient_descent(X_train, y_train, learning_rate, iterations)

predictions = predict(X_train, final_w, final_b)
accuracy = np.mean(predictions == y_train) * 100
print(f"training accuracy: {accuracy:.2f}%")
Iteration 0: Cost 0.6863856844505929
Iteration 1000: Cost 0.24893304312617473
Iteration 2000: Cost 0.19455725857907238
Iteration 3000: Cost 0.17109379033874833
Iteration 4000: Cost 0.15808906650231236
Iteration 5000: Cost 0.1498628871067555
Iteration 6000: Cost 0.14421883627612167
Iteration 7000: Cost 0.14012775640570907
Iteration 8000: Cost 0.13704269179323025
Iteration 9000: Cost 0.13464584006217875
training accuracy: 95.60%

Decision decision_boundary

  • As mentioned above, the decision boundary for the output of the sigmoid function is typically taken to be 0.5: \[ \begin{align*} \sigma(z) = \sigma(w_1x_{1} + w_2x_2 + b) &= 0.5 \\ w_1x_{1} + w_2x_2 + b &= 0\\ x_2 &= -\frac{w_1}{w_2}x_1 - \frac{b}{w_2}\\ \end{align*} \] Therefore, the slope of the decision boundary is \(-\frac{w_1}{w_2}\) and the intercept is \(-\frac{b}{w_2}\).

Plotting this, we get

Overfitting

  • Here we generate data from two classes with a somewhat more complex decision boundary
  • Underfitting: Logistic regression with x,y values (same as above)
  • Overfitting: 15th-degree polynomial features as input to the logistic regression model
  • Balanced fit: Applying L2 regularization to second model

Part 5: Overfitting

“With four parameters I can fit an elephant and with five I can make him wiggle his trunk.” — John von Neumann

Measuring Model Performance

Model fit can be assessed using the difference between predictions and reality:

  • Prediction Error: Difference between the model’s predictions and new data.
  • Estimation Error: Difference between the estimated and true parameter values.
  • Both types of error are driven by two competing forces, which are heavily dictated by model complexity1:

The Bias-Variance Tradeoff

Bias

  • Error introduced by using a predictive model that is incapable of capturing the underlying structure.
  • Underfitting: Models that are too simple have high bias and low variance.

Variance

  • Error due to excessive sensitivity to small fluctuations and noise in the training data.
  • Overfitting: Overly complex models typically have low bias and high variance.

Regularization

a technique used to enhance the generalization ability of machine learning models by adding a penalty term to the loss function.

  • We will focus on L2 regularization here (but see also Lasso and Elastic Net)
  • For simplicity, let’s focus for now on linear regression with a standard linear model1:

\[ Y = \beta_0 + \beta_1X_1 + \ldots + \beta_pX_p \]

  • If the true relationship between the response and the predictors is approximately linear, the least squares estimates will have low bias.
  • If \(n \gg p\) — that is, if \(n\), the number of observations, is much larger than \(p\), the number of variables—then the least squares estimates tend to also have low variance, and hence will perform well on test observations.
  • if \(n\) is not much larger than \(p\), then there can be a lot of variability in the least squares fit, resulting in overfitting and consequently poor predictions on future observations not used in model training.
  • If \(p>n\), here is no longer a unique least squares coefficient estimate: there are infinitely many solutions. Each of these least squares solutions gives zero error on the training data, but typically very poor test set performance due to extremely high variance

Shrinkage

Shrinkage

Shrinkage (also known as regularization) has the effect of reducing variance.

  • Today, we will focus on L2 regularization (Ridge regression)
  • Lasso regression and elastic net regression are also important techniques to learn about

🧮 The Regularized Cost Function

We add an L2 penalty term to the standard cross-entropy loss function:

\[ J(\mathbf{w}) = -\frac{1}{m} \sum_{i=1}^{m} \left[ y^{(i)} \log(a^{(i)}) + (1 - y^{(i)}) \log(1 - a^{(i)}) \right] + \frac{\lambda}{2m} \|\mathbf{w}\|_2^2 \tag{7}\]

Where the L2 norm penalty is defined as: \[ \|\mathbf{w}\|_2^2 = \sum_{j=1}^{n} w_j^2 \]

🔑 Key Parameters

  • \(\lambda\) (Lambda): The regularization strength hyperparameter.
  • If \(\lambda = 0\): Standard logistic regression (potential overfitting).
  • If \(\lambda \to \infty\): Weights are driven toward zero (underfitting).

Gradient of Log-Loss with L2 Regularization

To train our regularized model, we need the gradient of the objective function \(J(\mathbf{w})\), which combines our standard cross-entropy loss \(\mathcal{L}\) and the L2 penalty.

Using the sum rule for differentiation, we take the derivative of both parts with respect to weight \(w_j\):

\[ \frac{\partial J(\mathbf{w})}{\partial w_j} = \underbrace{\frac{\partial \mathcal{L}}{\partial w_j}}_{\text{Standard Gradient}} + \underbrace{\frac{\partial}{\partial w_j} \left( \frac{\lambda}{2m} \sum_{k=1}^{n} w_k^2 \right)}_{\text{L2 Derivative}} \tag{8}\]

Evaluating the derivative of the penalty term (where \(\frac{\partial}{\partial w_j}(w_j^2) = 2w_j\)), we get:

\[ \frac{\partial J(\mathbf{w})}{\partial w_j} = \underbrace{(\hat{y} - y)x_j}_{\text{Prediction Error}} + \underbrace{\frac{\lambda}{m} w_j}_{\text{Weight Penalty}} \tag{9}\]


💡 Intuition for Gradient Descent Updates

When we update our weights (\(w_j \leftarrow w_j - \alpha \frac{\partial J}{\partial w_j}\)) using Equation 9, the L2 term (i.e., weight penalty) alters the step:

  • The Core Error \((\hat{y} - y)x_j\): Same as above!
  • The Weight Penalty \(\frac{\lambda}{m} w_j\): The larger a weight grows, the harder gradient descent penalizes it, effectively preventing any single feature from dominating the model.


  • The Sum of Convex Functions is Convex

  • The above total cost function \(J(\mathbf{w})\) is composed of two distinct components \[J(\mathbf{w}) = \mathcal{L}_{\text{cross-entropy}}(\mathbf{w}) + \mathcal{L}_{\text{L2}}(\mathbf{w})\]

  • THe Standard negative log-likelihood (cross-entropy loss) for logistic regression is convex.

  • L2 Penalty (\(\frac{\lambda}{2m}\|\mathbf{w}\|_2^2\)) is a quadratic function (“bowl shaped”), which is strictly convex.

  • Thus logistic regression with L2 penalty has a unique solution

  • We still need to decide which value to use for \(\lambda\), which is a hyperparameter.

  • The optimal value of \(\lambda\) can be estimated with \(k\)-Fold Cross-Validation

  • HOMEWORK You will receive code for “do-it-yourself” logistic regression in Python and be askeed to add L2 regularization.

Sources and Suggested Rewarding