10 Artificial Neural Networks - An Economic Perspective

Artificial Neural Networks: An Economic Perspective

A journey from the limits of linear models to the power of deep learning for economic analysis.

Today’s Agenda: Moving Beyond Linearity

  1. Core · Review & Reflection: limitations of linear models.
  2. Core · Core Idea: biological inspiration for a mathematical model.
  3. Core · Building Block: start with one neuron.
  4. Core · Key Innovation: activation functions introduce non-linearity.
  5. Core · Build a Network: from Perceptron to MLP.
  6. Core · Model Learning: gradient descent and backpropagation.
  7. Core · China-Market Practice: chronological split, threshold choice on validation, and one final test evaluation.
  8. Extension (optional) · CNNs and Model History: return to the Core leakage check and transfer.

The Core Question: What If the World Isn’t Linear?

As economics students, our most familiar tool is Ordinary Least Squares (OLS).

\[ \large{Y = \beta_0 + \beta_1 X_1 + \beta_2 X_2 + \dots + \epsilon} \]

  • It is powerful and interpretable, but its specified regressors must adequately describe the conditional mean and the model must remain linear in its coefficients.

  • The raw variables need not have only a straight-line relationship: transformations and interactions can represent nonlinear shapes when the specification is appropriate.

The Beauty and Burden of the Linear Assumption

A linear relationship means that for every one-unit increase in an independent variable \(X\), the change in the dependent variable \(Y\) is constant (\(\beta\)).

Linear Relationship Diagram A scatter plot and regression line illustrating a linear relationship with a constant slope. Years of education (X) Income (Y) Linear Relationship: Simple and Constant ΔX = 1 ΔY = β

But is the real world always this simple?

The Real World: A Web of Complex, Non-Linear Relationships

Many economic phenomena cannot be perfectly described by a straight line.

  • Diminishing Marginal Utility: The happiness gained from an increase in income diminishes at higher income levels.
  • The Laffer Curve: The relationship between tax rates and tax revenue is an ‘inverted U-shape’.
  • ‘Fear’ and ‘Greed’ in Financial Markets: Asset prices react non-linearly to news, exhibiting thresholds and sharp fluctuations.

When faced with these complex non-linear relationships, traditional econometric models may fall short.

Example 1: Diminishing Marginal Utility

The higher the income, the smaller the increase in happiness from the same amount of money.

Diminishing Marginal Utility A curve showing that as income increases, the corresponding increase in utility gets smaller. Two identical income increases are shown, resulting in different utility increases. Diminishing Marginal Utility ΔIncome ΔU₁ ΔIncome ΔU₂ ΔU₁ > ΔU₂ Utility (Happiness) Income

Example 2: The Laffer Curve

Higher tax rates are not always better. Excessively high rates can stifle economic activity, leading to a decrease in tax revenue.

Laffer Curve An inverted U-shaped curve showing the relationship between tax rates and tax revenue, with an optimal tax rate T* that maximizes revenue. The Laffer Curve Peak Revenue Point Tax Revenue Tax Rate 0% T* 100% Normal Zone ProhibitiveZone

This Chapter’s Goal: Introduce a Powerful Non-Linear Tool

In this chapter, we will learn a new modeling paradigm inspired by the workings of the human brain:

Artificial Neural Networks (ANNs)

Our measurable objectives are to:

  1. Compute one neuron’s output from inputs, weights, and bias.
  2. Choose Sigmoid, Tanh, or ReLU from their gradient-propagation risks.
  3. Calculate one chain-rule and gradient-descent update by hand.
  4. Train an MLP on chronologically split local Chinese index data and identify leakage from random splitting.
  5. Evaluate next-period downside alerts using ROC-AUC, AP (average precision), recall, and a confusion matrix.

Metric convention

average_precision_score computes AP (average precision), whose no-skill baseline is prevalence. AP is not the trapezoidal area under the empirical PR curve.

Before You Begin

  1. If (z=2x+1, y=z^2), what is (dy/dx) at (x=1)?
  2. Can a forecast claim be valid if 2024 is randomly placed in training and 2018 in testing?
  3. Is accuracy enough when positives are rare?

Write all three answers before revealing.

Reveal and remediation

  • \(dy/dx=2z\times2=12\); no; no—also inspect AP (average precision), recall, and the decision threshold.

  • If item 1 was wrong, return to the chain rule; for item 2 or 3, return to chronological splitting or imbalance metrics.

90-Minute Main lesson and Optional Topics

  • 0–15 min: perceptron, weighted sum, and nonlinearity; complete the Sigmoid predict–reveal.
  • 15–40 min: feedforward network, loss, gradient descent, and backpropagation; complete one chain-rule check.
  • 40–72 min: predict next-month HS300 direction; split chronologically and compare with prior and Logit baselines.
  • 72–85 min: confusion matrix, calibration, recall interval, and expanding-window stability.
  • 85–90 min: lesson review—why this MLP is not a successful forecast.

Study sequence

Inspiration: The Human Brain’s Neuron

Before diving into the math, let’s look at the source of inspiration. A biological neuron consists of three main parts:

  • Dendrites: Receive signals from other neurons.
  • Soma (Cell Body): Processes the received signals.
  • Axon: Transmits the processed signal outwards.

Signals are passed between neurons across a Synapse.

Biological Neuron Diagram A simplified diagram of a biological neuron, clearly showing the signal flow from dendrites (input), through the soma (processing), to the axon (output). Input 1. Dendrites (Receive Signals) 2. Soma (Cell Body) (Process Signals) 3. Axon (Transmit Signals) Output

The Mathematical Abstraction: The McCulloch-Pitts Neuron

In 1943, Warren McCulloch and Walter Pitts proposed the first mathematical model of a neuron, known as the ‘M-P model’.

It simulates two key processes of a biological neuron:

  1. Signal Aggregation: It receives input signals from multiple upstream neurons and calculates their weighted sum.
  2. Activation Decision: It compares this weighted sum to a threshold. If the sum exceeds the threshold, the neuron ‘fires’ and outputs a signal; otherwise, it remains ‘inhibited’ and outputs nothing.

M-P Model Step 1: Signal Aggregation

Assume a neuron receives p input signals \(x_1, x_2, \dots, x_p\) from other neurons.

First, a linear transformation (weighted sum) is performed:

\[ \large{u = \sum_{i=1}^{p} w_i x_i} \]

Here, \(w_i\) represents the ‘weight’ of the \(i\)-th connection, simulating the strength of a synapse. A higher weight means the corresponding input signal is more important.

M-P Model Step 2: Activation Decision

Next, the weighted sum \(u\) is compared with a threshold \(\theta\):

\[ \large{y = \begin{cases} 1, & \text{if } u \ge \theta \quad \text{(Fires)} \\ 0, & \text{if } u < \theta \quad \text{(Inhibited)} \end{cases}} \]

This is an ‘all-or-nothing’ response pattern, like a switch that is either on (1) or off (0).

Graphical Representation of the M-P Model

We can represent the M-P model with a simple computation graph.

M-P Neuron Model Diagram A diagram showing the computational flow of an M-P neuron, from inputs, weighting, summation, to activation and output. x₁ x₂ xₚ Σ u ≥ θ ? y w₁ w₂ wₚ u = Σwᵢxᵢ

A More Convenient Formulation: Introducing the Bias Term

Working with a threshold \(\theta\) is algebraically inconvenient. We can perform a simple transformation.

Let \(b = -\theta\). This \(b\) is called the bias.

Then, the condition \(u \ge \theta\) is equivalent to \(u - \theta \ge 0\), which is \(u + b \ge 0\).

This allows us to treat the bias \(b\) as a special weight whose corresponding input is always 1.

\[ \large{z = \left(\sum_{i=1}^{p} w_i x_i\right) + b} \]

The activation process then becomes checking if \(z\) is greater than or equal to 0.

The Modern Neuron: From Threshold to Smooth Activation

The M-P model’s all-or-nothing step function is discontinuous and has derivative zero almost everywhere away from its threshold, so ordinary backpropagation receives no useful gradient for updating weights.

The decisive problem is not merely one nondifferentiable point: ReLU also has a kink at zero, but retains nonzero gradients elsewhere and uses a conventional subgradient at the kink.

  • Therefore, modern artificial neural networks replace the simple threshold with an activation function \(f(\cdot)\) that gradient methods can handle.

  • Sigmoid and Tanh are differentiable everywhere; ReLU is differentiable almost everywhere and uses a conventional subgradient at its kink at zero.

\[ \large{z = \mathbf{w}^T \mathbf{x} + b} \]

\[ \large{y = f(z) = f(\mathbf{w}^T \mathbf{x} + b)} \]

Here, \(y\) is no longer just 0 or 1, but can be a continuous value.

The Soul of the Network: The Activation Function

The activation function is the soul of a neural network. It is responsible for introducing non-linearity into the model.

Key Insight

If there were no activation function (or if it were linear, \(f(x)=x\)), then no matter how many layers you stack, the entire network would be equivalent to a single, simple linear model.

Saturated

The function’s curve flattens out at both ends.

  • Sigmoid
  • Tanh

Non-Saturated (ReLU-based)

The derivative is constant in the positive region.

  • ReLU
  • Leaky ReLU

Saturated Activation 1: The Sigmoid Function

The Sigmoid function, also known as the Logistic function, was one of the most common activation functions in early neural networks.

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

  • Role: Squeezes any real-valued input into the range \((0, 1)\).
  • Probability condition: With a binary output layer and an appropriate Bernoulli likelihood/cross-entropy objective, Sigmoid can parameterize a probability; empirical calibration must still be checked on validation data.

Pros and Cons of the Sigmoid Function

Advantages

  • Output is bounded; it parameterizes a Bernoulli probability only with an appropriate probabilistic objective, and calibration still requires validation.
  • Smooth and differentiable everywhere.

Disadvantages

  • Vanishing Gradients: The derivative is close to 0 in the saturated regions, making deep networks hard to train.
  • Not Zero-Centered:
    • Its range is not symmetric around zero.

    • The realized activation mean depends on the preactivation distribution, parameters, and data; optimization can be affected, but convergence speed is not guaranteed by the range alone.

Visualizing the Sigmoid Function and Its Derivative

Derivative: \(\sigma'(z) = \sigma(z)(1 - \sigma(z))\)

Sigmoid (Logistic) Function and its Derivative A plot of the S-shaped sigmoid function and its bell-shaped derivative, showing the function's output range and the derivative's peak at z=0. Sigmoid (Logistic) Function 1.00.50.0 -4-2024 zσ(z) σ(z) = 1 / (1 + e⁻ᶻ) σ'(z)

Sigmoid Numerical Prediction

Without looking ahead, compare \(\sigma'(0)\) and \(\sigma'(2)\). Which is larger? Does the function rise or fall from \(z=0\) to \(z=2\)? Distinguish “function value” from “slope.”

Reveal and remediation

  • \(\sigma'(0)=0.25\) and \(\sigma'(2)\approx0.105\), while \(\sigma(0)=0.5<\sigma(2)\approx0.881\).

  • A positive derivative means the function rises; the smaller derivative means its slope flattens.

  • If you predicted a falling function, revisit derivative sign; if you predicted a steeper slope, revisit saturation.

Saturated Activation 2: The Tanh Function

The hyperbolic tangent (Tanh) function is a variant of the Sigmoid.

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

  • Role: Squeezes input into the range \((-1, 1)\).
  • Core Advantage:
    • Zero-centered means the range and graph are symmetric around zero; it does not guarantee zero-mean realized activations.

    • With a roughly symmetric preactivation distribution this can improve gradient directions, but actual convergence depends on the distribution and optimizer.

Pros and Cons of the Tanh Function

Advantages

  • A zero-centered range can help optimization under suitable input distributions, but does not guarantee faster convergence.
  • Output is bounded.
  • Smooth and differentiable.

Disadvantages

  • The vanishing gradient problem still exists, although it’s slightly less severe than with Sigmoid.

Visualizing the Tanh Function and Its Derivative

Derivative: \(\tanh'(z) = 1 - \tanh^2(z)\)

Hyperbolic Tangent (Tanh) Function A plot of the S-shaped Tanh function and its bell-shaped derivative, showing the function's output range of (-1, 1) and its zero-centered nature. 1.00.0-1.0 -4-2024 zf(z) tanh′(z) tanh(z)

The Modern Default: ReLU (Rectified Linear Unit)

The Rectified Linear Unit (ReLU) is currently the most popular activation function, especially in deep learning.

\[ \large{\text{ReLU}(z) = \max(0, z) = \begin{cases} z, & \text{if } z > 0 \\ 0, & \text{if } z \le 0 \end{cases}} \]

It acts like a gatekeeper: negative values are blocked (set to zero), while positive values pass through unchanged.

Pros and Cons of the ReLU Function

Advantages

  • Extremely simple to compute (just a max operation).
  • The derivative is a constant 1 for positive inputs, which alleviates the vanishing gradient problem.
  • Promotes sparsity in the network (some neurons output 0), reducing the risk of overfitting.

Disadvantages

  • Not zero-centered.
  • The Dying ReLU Problem: If a neuron’s input is consistently negative, its gradient will always be 0, and the neuron effectively ‘dies’.

Visualizing the ReLU Function and Its Derivative

  • Mathematical derivative: \(\text{ReLU}'(z) = \begin{cases} 1, & z > 0 \\ 0, & z < 0 \end{cases}\); it does not exist at \(z=0\).

  • An optimizer may separately adopt 0 (or another selected subgradient) at the kink, but that convention is not the mathematical derivative.

Rectified Linear Unit (ReLU) A plot of the ReLU function, which is zero for negative inputs and linear for positive inputs, and its step-function derivative. Rectified Linear Unit (ReLU) -4-2024 0124 zf(z) f(z) = max(0, z) f′(z) = 1 for z > 0 f′(z) = 0 for z < 0

A ReLU Variant: Leaky ReLU

To solve the ‘Dying ReLU’ problem, researchers proposed Leaky ReLU.

\[ \large{\text{LeakyReLU}(z) = \max(\alpha z, z) = \begin{cases} z, & \text{if } z > 0 \\ \alpha z, & \text{if } z \le 0 \end{cases}} \]

where \(\alpha\) is a small positive constant, such as 0.01.

Core Idea

When the input is negative, it has a small, non-zero gradient of \(\alpha\). This ensures that the neuron’s gradient never becomes completely zero, preventing it from ‘dying’.

Visualizing the Leaky ReLU Function and Its Derivative

  • Mathematical derivative: \(\text{LeakyReLU}'(z) = \begin{cases} 1, & z > 0 \\ \alpha, & z < 0 \end{cases}\); for \(\alpha\ne1\) it does not exist at \(z=0\).

  • An implementation may separately choose a kink gradient, but that convention is not the mathematical derivative.

Leaky Rectified Linear Unit (Leaky ReLU) A plot of the Leaky ReLU function, which has a small positive slope for negative inputs, preventing the 'dying ReLU' problem. Leaky Rectified Linear Unit (Leaky ReLU) -4-2024 012 zf(z) f(z) f'(z) = 1, (z > 0) f'(z) = α = 0.1, (z < 0) Not differentiable at z=0

Activation Function Choice Strategy

Layer Task Type Recommended Activation Rationale
Hidden Layers (General) ReLU Fast computation, good performance, the default choice.
(If ReLU fails) Leaky ReLU / ELU Solves the ‘Dying ReLU’ problem.
Output Layer Binary Classification Sigmoid Pair with Bernoulli likelihood/cross-entropy; validate calibration.
Multiclass Classification Softmax Pair with categorical likelihood/cross-entropy; validate calibration.
Regression None (Linear) Outputs a continuous value in any range.

Scoped default: for ordinary feedforward hidden layers, usually start with ReLU. Gated/recurrent units, legacy-compatible architectures, or other explicit constraints may legitimately use Sigmoid/Tanh; choose using validation evidence.

From a Single Neuron to a Network: The Perceptron

In 1957, Frank Rosenblatt introduced the Perceptron, which can be considered the first complete, learnable neural network model.

  • Structure: A single M-P model neuron.

  • Activation Function: The sign function, which outputs -1 or 1.

    \[ \large{\hat{y} = \text{sign}(\mathbf{w}^T \mathbf{x} + b)} \]

  • Capability: The Perceptron is a linear classifier. It can find a line (or hyperplane) in the feature space to separate data points into two classes.

The Perceptron Learning Algorithm: Error-Driven

The Perceptron’s learning rule is very intuitive: ‘Correct mistakes as you see them’.

  1. Initialize weights \(\mathbf{w}\) and bias \(b\).
  2. For each training example \((\mathbf{x}, y)\):
    1. Make a prediction \(\hat{y}\) using the current parameters.

    2. If the prediction is wrong (\(y \neq \hat{y}\)), update the parameters:

      \[ \large{\mathbf{w} \leftarrow \mathbf{w} + \eta y \mathbf{x}} \]

      \[ \large{b \leftarrow b + \eta y} \]

      where \(\eta\) is the learning rate.

    3. If the prediction is correct, do nothing.

  3. If the data are linearly separable, convergence is finite. Otherwise cap epochs or use an error tolerance and retain the best iterate.

The Perceptron’s Achilles’ Heel: The XOR Problem

As a linear classifier, the Perceptron has a famous limitation—it cannot solve the Exclusive OR (XOR) problem.

The XOR logic is as follows:

\(x_1\) \(x_2\) \(y\)
0 0 0
0 1 1
1 0 1
1 1 0

Visualizing the XOR Problem: Linearly Inseparable

It is impossible to draw a single straight line to separate the blue squares (y=0) from the orange triangles (y=1).

Linear Inseparability of the XOR Problem A scatter plot with four points representing the XOR logic, demonstrating that they cannot be separated by a single straight line. The XOR Problem: Linearly Inseparable x₁ x₂ 01 10 No single line separates both classes

The Solution: Stacking Neurons to Form a Network

  • The solution to the XOR problem is to combine multiple neurons into a network.

  • By introducing one or more ‘Hidden Layers’, we can build a Multi-Layer Perceptron (MLP), also known as a Feedforward Neural Network (FNN).

Multi-Layer Perceptron Structure A diagram of an MLP structure with an input layer, a hidden layer, and an output layer. Input · 2 Hidden · 3 Output · 1

How MLPs Solve the XOR Problem

  • An MLP with a hidden layer can perform a non-linear transformation on the original input space, mapping it to a new feature space.

  • In this new space, data that was previously linearly inseparable can become linearly separable.

MLP Solving XOR via Feature Space Transformation A diagram showing that XOR data points, while linearly inseparable in the original space, become linearly separable in a new feature space after transformation by a hidden layer. Original Input Space x₁x₂ Hidden transform New Feature Space (Linearly Separable) h₁h₂

Mathematical Representation of an MLP: Layer by Layer

Consider an L-layer MLP. For the \(l\)-th layer (where \(l=1, \dots, L\)):

  • Linear Transformation:

    \[ \large{\mathbf{z}^{(l)} = \mathbf{W}^{(l)} \mathbf{y}^{(l-1)} + \mathbf{b}^{(l)}} \]

  • Non-linear Activation:

    \[ \large{\mathbf{y}^{(l)} = f^{(l)}(\mathbf{z}^{(l)})} \]

Where:

  • \(\mathbf{y}^{(l-1)}\) is the output of the \((l-1)\)-th layer (or the original input \(\mathbf{x}\) when \(l=1\)).
  • \(\mathbf{W}^{(l)}\) and \(\mathbf{b}^{(l)}\) are the weight matrix and bias vector for the \(l\)-th layer.
  • \(f^{(l)}\) is the activation function for the \(l\)-th layer.

Network Architecture: Depth vs. Width

Width

  • The number of neurons in a hidden layer.
  • Wider networks can learn more complex features at a given layer.
  • Risk: Prone to overfitting.

Depth

  • The number of hidden layers.
  • Deeper networks can learn a hierarchy of features (from simple to complex).
  • Universal Approximation Theorem: A single hidden layer network with enough width can approximate any continuous function. However, in practice, deep networks are often more efficient than shallow, wide ones.

How to Train an MLP: The Core Idea

We have the network structure, but how do we find the optimal parameter values for the thousands (or millions) of parameters (all the W’s and b’s)?

  1. Define a Loss Function: First, we need a function to measure how ‘bad’ the model’s predictions are.
    • Regression: Mean Squared Error (MSE)
    • Classification: Cross-Entropy
  2. Objective: Find the set of parameters \((\mathbf{W}, \mathbf{b})\) that minimizes the total loss over the entire training set.
  3. Method: Use the Gradient Descent algorithm.

Gradient Descent: An Intuition

Imagine you are on a dark mountain and your goal is to walk to the lowest point in the valley.

  1. You feel around with your foot to find the direction of the steepest slope (this is the gradient).
  2. You take a small step in the direction of the steepest descent.
  3. You repeat this process, step by step, making your way down to the valley floor.
An Intuitive Understanding of Gradient Descent A structured diagram supporting the concept explained on this slide. Gradient Descent: Local vs. Global Optima J(θ) θ Local Optimum (local minimum) Global Optimum (stationary trough) Start Every step lowers J(θ)

The Mathematics of Gradient Descent

The parameter update rule is:

\[ \large{\theta_{\text{new}} = \theta_{\text{old}} - \eta \nabla_{\theta} J(\theta)} \]

  • \(\theta\): Represents all model parameters (W, b).
  • \(J(\theta)\): The loss function.
  • \(\nabla_{\theta} J(\theta)\): The gradient of the loss function with respect to the parameters. It points in the direction of the steepest ascent.
  • \(-\nabla_{\theta} J(\theta)\): Points in the direction of the steepest descent.
  • \(\eta\): The learning rate, which determines the size of each step.

The Biggest Challenge: How to Compute the Gradient?

For a deep network, the loss function is an extremely complex composite function of thousands or millions of parameters.

\[ \large{L = f_L(f_{L-1}(\dots f_1(\mathbf{x}; \mathbf{W}^{(1)}, \mathbf{b}^{(1)}); \dots); \mathbf{W}^{(L)}, \mathbf{b}^{(L)})} \]

Taking the derivative of this directly is nearly impossible. We need an efficient algorithm to compute this gradient.

The Solution: The Backpropagation Algorithm

The Backpropagation (BP) algorithm is the cornerstone of training neural networks. It is essentially an efficient application of the Chain Rule from calculus to a neural network.

It involves two phases:

  1. Forward Pass: From input to output, compute the prediction and the loss.
  2. Backward Pass: From output to input, compute the gradient of the loss with respect to the parameters of each layer.
Neural Network: Forward & Backward Propagation A computational graph showing the forward pass for calculating loss and the backward pass for calculating gradients in a neural network. Neural Network: Forward & Backward Propagation x h₁ h₂ ŷ L Forward pass · compute loss hₗ = σ(Wₗhₗ₋₁) · L = Cost(ŷ,y) Backward pass · compute ∇W and update weights ∂L/∂ŷ∂L/∂h₂∂L/∂h₁∂L/∂x ∇W₃∇W₂∇W₁

The Core of Backpropagation: The Chain Rule

If we have \(y = f(u)\) and \(u = g(x)\), then the derivative of \(y\) with respect to \(x\) is:

\[ \large{\frac{\partial y}{\partial x} = \frac{\partial y}{\partial u} \cdot \frac{\partial u}{\partial x}} \]

  • Dependency chain: \(L\) depends on the final output \(\mathbf{y}^{(L)}\), which depends on the net input \(\mathbf{z}^{(L)}\).

  • Layerwise dependence: \(\mathbf{z}^{(L)}\) is determined by \(\mathbf{y}^{(L-1)}\) and parameters \(\mathbf{W}^{(L)},\mathbf{b}^{(L)}\).

  • Backpropagation: the chain rule passes the gradient signal efficiently from the last layer back to the first.

Chain-Rule Check

  • Compute first: if \(u=2x+1\) and \(y=u^2\), what is \(dy/dx\) at \(x=1\)? Write both local derivatives.
  • Reveal and remediation: \(du/dx=2\) and \(dy/du=2u=6\), so \(dy/dx=12\). If you wrote 6, revisit multiplying local gradients; if you wrote 4, substitute \(x=1\) into \(u\) first.

Core Computation Practice: Neuron, Activation, and Update

Complete all three steps before revealing:

  1. Given \(\mathbf{x}=(2,-1)\), \(\mathbf{w}=(0.5,-0.25)\), \(b=0.1\), and ReLU, compute \(z=\mathbf{w}^T\mathbf{x}+b\) and output \(y\).
  2. A deep hidden unit must retain gradient for large positive inputs.
  • Which comes first among Sigmoid, Tanh, and ReLU?

  • If the output must parameterize a Bernoulli probability, what training objective and validation check are also required?

  1. If \(u=2\theta+1\), \(L=u^2\), \(\theta_{old}=1\), and \(\eta=0.1\), compute \(dL/d\theta\) and \(\theta_{new}\).

Core Computation Practice: Complete Solution

    1. \(z=0.5(2)+(-0.25)(-1)+0.1=1.35\), so \(y=\max(0,z)=1.35\). (2) Use ReLU first for the hidden unit because its positive-region gradient does not saturate.
  • Sigmoid can parameterize a Bernoulli probability when paired with a Bernoulli likelihood/cross-entropy objective, and calibration must be checked on validation data.

  • Tanh has a range symmetric around zero, but its realized mean need not be zero and it still saturates at both tails. (3) \(dL/d\theta=(2u)(2)=12\), so \(\theta_{new}=1-0.1(12)=-0.2\).

  • If you obtained \(2.2\), you performed ascent along the gradient.

In Practice: Alerting Next-Month HS300 Downside with Local Data

Using local HS300 daily observations, we construct a monthly task: at month-end (t), use only information then available to predict whether month (t+1) has a negative return.

  • File/key: data/index/hs300_index_only.h5 / hs300
  • Raw fields: datetime, close, volume, total_turnover; prices are index points and turnover follows the local dictionary
  • Sample: 2005-01-01 to 2024-12-31; the target only denotes next-month HS300 return direction
  • Evaluation: first 70% train, next 15% validation, final 15% test, strictly chronological

Feature Selection

  • All inputs are computable at month-end (t): current monthly return, three-month momentum, 20-day realized volatility, and monthly turnover growth.

  • The label uses the next month’s return, keeping the contemporaneous outcome out of the feature set.

Step 1: Acquiring and Preparing the Data

Read the local HDF5 directly, with no network dependency and no random fallback.

Code
from pathlib import Path  # Locating Local Index Files Using Path Objects
import numpy as np  # Calculate Logarithmic Change vs. Finite Value
import pandas as pd  # Read daily rows and aggregate them by month
# Public download: https://assets.qiufei.site/data/index/hs300_index_only.h5
# After downloading, change the next line to the file's actual location on your device.
# Course-relative option: Path("data/index/hs300_index_only.h5")
# Windows: Path(r"C:\qiufei\data\index\hs300_index_only.h5")
# macOS: Path("/Users/your_name/data/index/hs300_index_only.h5")
# Linux: Path("/home/your_name/data/index/hs300_index_only.h5")
index_path = Path("/home/ubuntu/r2_data_mount/data/index/hs300_index_only.h5")
daily_index = pd.read_hdf(index_path, key='hs300')  # Reading real daily quotes from fixed HDF key
daily_index['date'] = pd.to_datetime(daily_index['datetime'].astype(str), format='%Y%m%d%H%M%S')  # Parse local timestamp
daily_index = daily_index.query("'2005-01-01' <= date <= '2024-12-31'").set_index('date').sort_index()  # Fixed Sample Period and Sequence
monthly_index = daily_index.resample('ME').agg(close=('close', 'last'), turnover=('total_turnover', 'sum'))  # Summarize end-of-month point and monthly turnover
monthly_index['monthly_return'] = monthly_index['close'].pct_change()  # Calculate the current monthly return
monthly_index['momentum_3m'] = monthly_index['close'].pct_change(3)  # Compute three-month momentum at month-end
monthly_index['realized_volatility'] = daily_index['close'].pct_change().rolling(20).std().resample('ME').last() * np.sqrt(20)  # Calculate 20th month Volatility
monthly_index['turnover_growth'] = monthly_index['turnover'].pct_change()  # Calculate current-month turnover growth
monthly_index['next_month_return'] = monthly_index['monthly_return'].shift(-1)  # Aligning next-month realized return
monthly_index['target_date_t1'] = monthly_index.index.to_series().shift(-1)  # Preserve the next-month label-realization date
feature_columns = ['monthly_return', 'momentum_3m', 'realized_volatility', 'turnover_growth']  # Fix four features available at month-end
analysis_frame = monthly_index.dropna(subset=feature_columns + ['next_month_return', 'target_date_t1']).copy()  # Drop the final month whose next-month return is unknown
analysis_frame['next_month_down'] = analysis_frame['next_month_return'].lt(0).astype(int)  # Create binary labels only for observed future returns
label_realization_date = analysis_frame.index + pd.offsets.MonthEnd(1)  # Record label realization at the following month-end
assert (analysis_frame['target_date_t1'].dt.to_period('M') == analysis_frame.index.to_period('M') + 1).all()  # Verify exact next-calendar-month realization
display(analysis_frame.head())  # Display real input fields and label construction
close turnover monthly_return momentum_3m realized_volatility turnover_growth next_month_return target_date_t1 next_month_down
date
2005-04-30 932.395 1.611263e+11 -0.010406 -0.023547 0.059615 0.046432 -0.081992 2005-05-31 1
2005-05-31 855.946 7.756412e+10 -0.081992 -0.176967 0.049075 -0.518613 0.026567 2005-06-30 0
2005-06-30 878.686 1.681570e+11 0.026567 -0.067410 0.104620 1.167974 0.010787 2005-07-31 0
2005-07-31 888.164 1.172239e+11 0.010787 -0.047438 0.058266 -0.302890 0.044757 2005-08-31 0
2005-08-31 927.916 2.182591e+11 0.044757 0.084082 0.058778 0.861898 -0.011342 2005-09-30 1

Step 2: Define Features and Target, and Split the Dataset

  • Features: monthly_return, momentum_3m, realized_volatility, turnover_growth
  • Target: next_month_down
  • Split train/validation/test by date position; later observations never enter an earlier training window.
Code
input_feature_matrix = analysis_frame[feature_columns]  # Construct Feature Matrix Sorted by Date
target_values = analysis_frame['next_month_down']  # Extract the next-month decline target
train_end = int(len(analysis_frame) * .70)  # Use the earliest 70% month as the training period
validation_end = int(len(analysis_frame) * .85)  # Use the next 15% month as the validation period
validation_start_date = analysis_frame.index[train_end]
test_start_date = analysis_frame.index[validation_end]
train_mask = (analysis_frame.index < validation_start_date) & (analysis_frame['target_date_t1'] < validation_start_date)  # Purge training labels realized in validation
validation_mask = (analysis_frame.index >= validation_start_date) & (analysis_frame.index < test_start_date) & (analysis_frame['target_date_t1'] < test_start_date)  # Purge validation labels realized in test
test_mask = analysis_frame.index >= test_start_date
training_features, y_train = input_feature_matrix.loc[train_mask], target_values.loc[train_mask]  # Keep the purged training window
validation_features, y_validation = input_feature_matrix.loc[validation_mask], target_values.loc[validation_mask]  # Keep the purged validation window
testing_features, y_test = input_feature_matrix.loc[test_mask], target_values.loc[test_mask]  # Keep the held-out test window
assert analysis_frame.loc[train_mask, 'target_date_t1'].max() < validation_features.index.min() and analysis_frame.loc[validation_mask, 'target_date_t1'].max() < testing_features.index.min()  # Verify label-realization boundaries
split_summary = pd.DataFrame({'start': [training_features.index.min(), validation_features.index.min(), testing_features.index.min()], 'end': [training_features.index.max(), validation_features.index.max(), testing_features.index.max()], 'size': [len(training_features), len(validation_features), len(testing_features)], 'down_rate': [y_train.mean(), y_validation.mean(), pd.NA]}, index=['train', 'validation', 'test'])  # Report boundaries while keeping test prevalence held-out until the threshold is fixed
display(split_summary)  # Verify that the time boundary is strictly incremented
start end size down_rate
train 2005-04-30 2018-11-30 164 0.420732
validation 2019-01-31 2021-10-31 34 0.411765
test 2021-12-31 2024-11-30 36 <NA>

Step 3: Feature Scaling

  • Neural networks are very sensitive to the scale of input features.

  • If different features have vastly different numerical ranges, the training process can become unstable.

  • Standardization, which scales all features to have a mean of 0 and a standard deviation of 1, is a crucial preprocessing step.

  • Note: We fit_transform only on the training set.

  • The test set must be transformed using the same scaling rules learned from the training set to avoid data leakage.

Code
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaled_training_features = scaler.fit_transform(training_features)
scaled_validation_features = scaler.transform(validation_features)  # Transforming Continuous Validation Periods Using Training Period Parameters
scaled_testing_features = scaler.transform(testing_features)  # Transform fixed test samples with the training-period scaler only
print('Pre-scaling train set means:', np.mean(training_features, axis=0).values.round(2))  # 展示当前步骤的结果。
print('Post-scaling train set means:', np.mean(scaled_training_features, axis=0).round(2))  # 展示当前步骤的结果。
print('Post-scaling train set std devs:', np.std(scaled_training_features, axis=0).round(2))  # 展示当前步骤的结果。
Pre-scaling train set means: [0.01 0.04 0.07 0.1 ]
Post-scaling train set means: [ 0.  0.  0. -0.]
Post-scaling train set std devs: [1. 1. 1. 1.]

Step 4: Building and Training the MLP Model

We use sklearn.neural_network.MLPClassifier to build the model.

  • hidden_layer_sizes=(50, 50): Defines a network with two hidden layers, each with 50 neurons.
  • activation='relu': Use the ReLU activation function for the hidden layers.
  • solver='adam': Adam is an efficient gradient descent optimization algorithm.
  • max_iter=500: The maximum number of training epochs.
Code
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(
    hidden_layer_sizes=(50, 50),
    activation='relu',
    solver='adam',
    max_iter=500,
    random_state=42
)
print('Starting model training...')  # 展示当前步骤的结果。
mlp.fit(scaled_training_features, y_train)
print(f'Iterations={mlp.n_iter_}; converged before cap={mlp.n_iter_ < mlp.max_iter}')  # Clarify whether this optimization is converging
Starting model training...
Iterations=500; converged before cap=False

Step 5: Choose the Cost Threshold on Validation Only

  • Cost rule: set missed-alert cost to four times false-alert cost before viewing any test output.

  • Validation choice: among thresholds 0.3, 0.5, and 0.7, select the operating point with minimum \(4FN+FP\) on validation data only.

Code
from sklearn.metrics import confusion_matrix  # Compare false-alert and missed-alert costs on validation data
y_validation_prob = mlp.predict_proba(scaled_validation_features)[:, 1]  # Generate probabilities only for the untouched validation window
threshold_cost_rows = []  # Save validation candidate costs
for decision_threshold in [0.3, 0.5, 0.7]:  # Compare the three stated operating points
    validation_prediction = (y_validation_prob >= decision_threshold).astype(int)  # Form validation alerts
    validation_confusion = confusion_matrix(y_validation, validation_prediction)  # Compute validation confusion counts
    validation_cost = 4 * validation_confusion[1, 0] + validation_confusion[0, 1]  # Make missed alerts four times as costly as false alerts
    threshold_cost_rows.append([decision_threshold, validation_cost])  # Retain each candidate's validation cost
threshold_cost_table = pd.DataFrame(threshold_cost_rows, columns=['threshold', 'validation cost'])  # Build pre-test selection evidence
selected_cost_threshold = threshold_cost_table.loc[threshold_cost_table['validation cost'].idxmin(), 'threshold']
display(threshold_cost_table)  # Show validation selection evidence
print(f'Threshold fixed before test access: {selected_cost_threshold:.1f}')  # Record the sole operating-point choice
threshold validation cost
0 0.3 52
1 0.5 47
2 0.7 49
Threshold fixed before test access: 0.5

Step 6: Open One Test check with the fixed Threshold

The validation-cost threshold is now fixed. Only now do we open the test set for one common check using a classification report and ranking metrics:

  • Precision: Of all months alerted as “next-month down,” how many actually fell? (TP / (TP + FP))
  • Recall: Of all months that actually fell, how many were alerted? (TP / (TP + FN))
  • F1-score: The harmonic mean of precision and recall.
Code
from sklearn.metrics import average_precision_score, classification_report, roc_auc_score  # Evaluating Categories and Sorting Performance at the Same Time
y_prob = mlp.predict_proba(scaled_testing_features)[:, 1]  # Generate held-out test decline probabilities for the first time
y_pred = (y_prob >= selected_cost_threshold).astype(int)  # Apply the threshold fixed before test access
test_cost_confusion = confusion_matrix(y_test, y_pred)  # Save the cost confusion matrix in the same check
print('Classification Report (Test Set):')  # Mark the classification indicators from the test window that never participated in parameter tuning
print(classification_report(y_test, y_pred, target_names=['Up/Flat', 'Down']))  # 展示当前步骤的结果。
print(f'Validation ROC-AUC: {roc_auc_score(y_validation, y_validation_prob):.3f}')  # Report Validation Window ranking performance
print(f'Test ROC-AUC: {roc_auc_score(y_test, y_prob):.3f}')
print(f'Test AP (average precision): {average_precision_score(y_test, y_prob):.3f}')  # Report Metrics More Sensitive to Downstream Categories
print(f'fixed-threshold test cost: {4 * test_cost_confusion[1, 0] + test_cost_confusion[0, 1]}')  # Report the complete cost within the same check
Classification Report (Test Set):
              precision    recall  f1-score   support

     Up/Flat       0.36      0.71      0.48        14
        Down       0.50      0.18      0.27        22

    accuracy                           0.39        36
   macro avg       0.43      0.45      0.37        36
weighted avg       0.44      0.39      0.35        36

Validation ROC-AUC: 0.343
Test ROC-AUC: 0.412
Test AP (average precision): 0.566
fixed-threshold test cost: 76

Baselines First: This MLP Underperforms Simple References

Code
from sklearn.dummy import DummyClassifier  # Establish a priori probability baseline for the training period
from sklearn.linear_model import LogisticRegression  # Establish linear probability baseline for same field
from sklearn.metrics import brier_score_loss, recall_score  # Evaluation Probability Error and decline recall
comparison_models = {'Prior baseline': DummyClassifier(strategy='prior'), 'Logit': LogisticRegression(max_iter=1000, random_state=42), 'MLP': mlp}  # Fixed Three Comparable Models
comparison_rows = []
for model_name, comparison_model in comparison_models.items():  # Compare on Same Training Sample
    if model_name != 'MLP':  # Avoid fitting the trained network repeatedly
        comparison_model.fit(scaled_training_features, y_train)  # Fit Baseline by Training Period Only
    comparison_probability = comparison_model.predict_proba(scaled_testing_features)[:, 1]  # Generate Down Probability Next Month
    comparison_prediction = (comparison_probability >= .5).astype(int)  # Use common default thresholds
    comparison_rows.append([model_name, roc_auc_score(y_test, comparison_probability), average_precision_score(y_test, comparison_probability), recall_score(y_test, comparison_prediction), brier_score_loss(y_test, comparison_probability)])  # Summarize sort, recall, and probability error
baseline_table = pd.DataFrame(comparison_rows, columns=['model', 'ROC-AUC', 'AP (average precision)', 'down recall', 'Brier'])  # Generate Comparison Table
display(baseline_table.round(3))  # Display executed evidence
model ROC-AUC AP (average precision) down recall Brier
0 Prior baseline 0.500 0.611 0.000 0.274
1 Logit 0.360 0.531 0.045 0.292
2 MLP 0.412 0.566 0.182 0.451
  • Executed result:
    • the test set has only 36 months and downside prevalence 0.611.

    • Prior baseline ROC-AUC/AP (average precision)=0.500000/0.611111; Logit=0.360390/0.531419; MLP=0.412338/0.566124.

    • Neither fitted model beats the PR prevalence baseline.

    • The MLP reaches the 500-iteration cap without convergence; Brier=0.451003, worse than the freshly executed purge-aware prior baseline’s 0.273899.

Baseline Decision: Do Not Deploy

  • Evidence: this is an honest failure case, not successful prediction.

  • Limits: small samples, regime drift, reversed or unstable ranking, and non-convergence constrain inference.

  • Boundary: the test set is never reused for training, tuning, or threshold choice.

Calibration and Uncertainty: Do Not Take Probabilities at Face Value

Code
from sklearn.metrics import confusion_matrix  # Read Four Frame Count of Same Test Forecast
calibration_data = pd.DataFrame({'predicted_probability': y_prob, 'observed_down': y_test.to_numpy()})  # Aligning Test Probability and Real Drops
calibration_data['probability_bin'] = pd.qcut(calibration_data['predicted_probability'], q=3, duplicates='drop')  # Avoid empty boxes with three equal-frequency groups
calibration_table = calibration_data.groupby('probability_bin', observed=True).agg(mean_predicted=('predicted_probability', 'mean'), observed_rate=('observed_down', 'mean'), n=('observed_down', 'size'))  # Compare predicted and actual frequencies
true_negative, false_positive, false_negative, true_positive = confusion_matrix(y_test, y_pred).ravel()  # Read Same Test Confusion Matrix
positive_count = true_positive + false_negative  # Count the number of months of true fall
recall_estimate = true_positive / positive_count  # Calculate Point Estimated Recall
wilson_denominator = 1 + 1.96 ** 2 / positive_count  # Constructing 95% Wilson Interval Denominator
wilson_center = (recall_estimate + 1.96 ** 2 / (2 * positive_count)) / wilson_denominator  # Calculate the center of the interval
wilson_half_width = 1.96 * np.sqrt(recall_estimate * (1 - recall_estimate) / positive_count + 1.96 ** 2 / (4 * positive_count ** 2)) / wilson_denominator  # Calculate the half-width of the interval
display(calibration_table.round(3))  # Demonstrate Reliability instead of AUC
print(f'Down recall={recall_estimate:.3f}; 95% Wilson interval=[{wilson_center-wilson_half_width:.3f}, {wilson_center+wilson_half_width:.3f}]')  # Report Limited Sample Uncertainty
mean_predicted observed_rate n
probability_bin
(-0.000999871, 0.0968] 0.032 0.667 12
(0.0968, 0.353] 0.230 0.667 12
(0.353, 0.876] 0.580 0.500 12
Down recall=0.182; 95% Wilson interval=[0.073, 0.385]
  • The three mean predicted probabilities are about 0.032, 0.230, and 0.580, while observed downside rates are 0.667, 0.667, and 0.500, indicating weak reliability.

  • Downside recall is 0.182 with a 95% Wilson interval [0.073, 0.385].

  • The interval ignores temporal dependence, so it is a small-sample warning rather than a formal confidence interval.

Visualizing the Confusion Matrix

A confusion matrix provides a clear visual breakdown of the model’s performance across different classes.

  • Top-left (TN): actual up/flat and no downside alert.
  • Bottom-right (TP): actual down and a correct downside alert.
  • Top-right (FP): actual up/flat but an alert was issued; the cost is unnecessary risk reduction or missed upside.
  • Bottom-left (FN): actual down but no alert; the cost is unprotected downside exposure.

fixed-Test Confusion Matrix: Executed Counts

Code
import matplotlib.pyplot as plt
from sklearn.metrics import ConfusionMatrixDisplay  # Convert Same Forecast from Previous Page to Confusion Matrix
fig, ax = plt.subplots(figsize=(8, 6))  # Create teaching canvas for test set confusion matrix
confusion_display = ConfusionMatrixDisplay.from_predictions(
    y_test, y_pred, ax=ax, cmap='Blues',
    display_labels=['Up/Flat', 'Down']
)
ax.set_title('Next-Month Downside Alert: fixed Test Period', fontsize=42)
ax.tick_params(axis='both', labelsize=36)
ax.xaxis.label.set_size(40); ax.yaxis.label.set_size(40)
for label in confusion_display.text_.ravel(): label.set_fontsize(42)
confusion_display.im_.colorbar.ax.tick_params(labelsize=36)
plt.show()  # 展示当前步骤的结果。
A two-by-two confusion matrix reports counts for next-month up or flat versus down using the same fitted MLP on the fixed test period.
Figure 1: Test-period confusion matrix for the HS300 next-month downside alert

Expanding Windows: Weak Performance Is Not One Holdout Accident

Code
from sklearn.model_selection import TimeSeriesSplit  # Construct Training Window Expanding Only the Fold Not Looked Back
development_mask = (analysis_frame.index < test_start_date) & (analysis_frame['target_date_t1'] < test_start_date)  # Keep only labels realized before final test
development_features = input_feature_matrix.loc[development_mask]  # Diagnose stability on the purged development period
development_target = target_values.loc[development_mask]  # Keep target aligned with feature dates
time_splitter = TimeSeriesSplit(n_splits=5, test_size=12, gap=1)  # Purge one month for the next-month horizon
fold_rows = []  # save break dates and metrics
for fold_number, (fold_train, fold_test) in enumerate(time_splitter.split(development_features), 1):  # Extend training period in sequence
    assert analysis_frame.loc[development_features.index[fold_train], 'target_date_t1'].max() < development_features.index[fold_test].min()  # Verify each fold's label boundary
    fold_scaler = StandardScaler()  # Estimate scaling individually per fold Avoid leaks
    fold_train_scaled = fold_scaler.fit_transform(development_features.iloc[fold_train])  # Only fitting the current training month
    fold_test_scaled = fold_scaler.transform(development_features.iloc[fold_test])  # Transform a continuous test block with a training parameter
    fold_model = MLPClassifier(hidden_layer_sizes=(50, 50), max_iter=500, random_state=42)  # Reuse the classroom MLP specification
    fold_model.fit(fold_train_scaled, development_target.iloc[fold_train])  # Train from scratch per fold
    fold_probability = fold_model.predict_proba(fold_test_scaled)[:, 1]  # Generate probability of declineout
    fold_rows.append([fold_number, development_features.index[fold_train[-1]], development_features.index[fold_test[0]], development_features.index[fold_test[-1]], roc_auc_score(development_target.iloc[fold_test], fold_probability), average_precision_score(development_target.iloc[fold_test], fold_probability)])  # Record Date and Metric
fold_table = pd.DataFrame(fold_rows, columns=['fold', 'train end', 'test start', 'test end', 'ROC-AUC', 'AP (average precision)'])  # Form a complete answer
display(fold_table.round(3))  # Demonstrate All Folds instead of Best Folds
fold train end test start test end ROC-AUC AP (average precision)
0 1 2016-09-30 2016-11-30 2017-10-31 0.444 0.498
1 2 2017-09-30 2017-11-30 2018-10-31 0.694 0.622
2 3 2018-09-30 2018-11-30 2019-10-31 0.406 0.371
3 4 2019-09-30 2019-11-30 2020-10-31 0.314 0.395
4 5 2020-09-30 2020-11-30 2021-10-31 0.444 0.604

Executed output

  • fold ROC-AUC values are 0.444, 0.694, 0.406, 0.314, and 0.444; AP (average precision) values are 0.498, 0.622, 0.371, 0.395, and 0.604.

  • Results vary widely and several folds rank below 0.5; every network reaches the 500-iteration cap.

  • Never select only the best fold or deploy from this evidence.

Core review: An Executable Selective Decision

  • Given this evidence, the selective action is do not use MLP probabilities for automated trading or formal risk limits.

  • Keep the model as a classroom diagnostic until it beats prior/Logit baselines across multiple time folds, improves Brier and reliability, and locks a cost-based threshold on validation data.

  • The complete index file is large, so this example uses the 1.48MB hs300_index_only.h5 / hs300, containing only datetime, close, total_turnover for 2005–2024.

  • It runs directly on an ordinary computer.

  • To study another index, download a single-index file with the same fields and change the file name.

Core learners now jump to leakage check and transfer to close the learning path. Extension learners continue below and follow the return link at the end.

Optional Extension: Convolutional Neural Networks (CNNs)

The MLPs we’ve discussed are fully-connected, meaning every neuron in a layer is connected to every neuron in the previous layer.

When processing data with spatial or temporal structure, like images or time series, the number of parameters in a fully-connected network explodes, and it fails to leverage the local structure of the data.

A Convolutional Neural Network (CNN) is a special type of feedforward network that addresses these issues through local connectivity and weight sharing.

The Core Idea of CNNs: Analyzing Data Like a Visual System

CNNs are inspired by the biological visual cortex.

  1. Receptive Field: Each neuron focuses only on a small region of the input (local connectivity).
  2. Feature Map: A ‘filter’ or ‘kernel’ slides across the entire input, searching for a specific pattern (like an edge or corner) and generating a feature map (weight sharing).

This is like how we look at a photo: we don’t process every pixel at once, but rather identify local lines and shapes first, then combine them into more complex objects.

The Key Layer of a CNN: The Convolutional Layer

At each position, a kernel computes an element-wise product sum (plus bias) to extract a local feature.

CNN Convolution Operation A 3x3 kernel slides over a 5x5 input, computing and generating one pixel value for the feature map. Input Data (5x5) 11100 01110 0011 100110 01100 Kernel (3x3) 101 010 101 = 1*1 + 1*0 + 1*1 = 2 0*0 + 1*1 + 1*0 = 1 0*1 + 0*0 + 1*1 = 1 SUM = 4 Feature Map (3x3) 4

The Key Layer of a CNN: The Pooling Layer

A pooling layer (or downsampling layer) typically follows a convolutional layer.

Purpose:

  1. Downsampling: Reduces feature-map size. Pooling itself has no learned parameters and can reduce computation and parameters in downstream layers.
  2. Local translation tolerance: Makes responses less sensitive to small shifts within a pooling window. This is not rotation invariance and does not guarantee global translation invariance.

Common Methods:

  • Max Pooling: Takes the maximum value from a region.
  • Average Pooling: Calculates the average value of a region.

Visualizing Max Pooling

The diagram below shows a 2x2 max pooling operation on a 4x4 feature map.

Max Pooling Operation A 4x4 grid is downsampled to a 2x2 grid using a 2x2 max pooling operation. Input Feature Map 3824 5193 1367 2345 2x2 Max Pooling Output 8 9 7 5

CNN Applications in Economics?

Although CNNs were born from image recognition, their core idea of recognizing local patterns can be applied to economics:

  • Time Series Analysis: A financial time series (e.g., stock prices) can be treated as a 1D ‘image’. CNNs can be used to identify technical analysis patterns like ‘head and shoulders’ or ‘double bottoms’.
  • Textual Analysis: A matrix of word vectors from a sentence can be treated as a 2D image. CNNs can extract local semantic features for analyzing the sentiment or topics of financial reports and news articles.
  • Satellite Imagery Analysis: Using satellite data like nighttime lights or ships in ports to predict regional economic activity.

A Brief History of Neural Networks: A Tour of Famous Models

Since 2012, the field of deep learning has seen a surge of landmark CNN architectures. Understanding them helps us appreciate how networks have become progressively deeper and more powerful.

  • LeNet-5 (1998): The ancestor of modern CNNs.
  • AlexNet (2012): Popularized the combination of ReLU, dropout, and GPU training at ImageNet scale.
  • VGGNet (2014): Demonstrated the importance of network depth.
  • GoogLeNet (2014): Introduced the ‘Inception module’, improving network width and efficiency.
  • ResNet (2015): Introduced ‘residual connections’, solving the training problem for extremely deep networks.

LeNet-5 (1998): The Founder of a Classic Architecture

Proposed by Yann LeCun for recognizing handwritten digits on checks. Its classic architecture [CONV -> POOL -> CONV -> POOL -> FC -> OUTPUT] is still influential today.

LeNet-5 Simplified Architecture A simplified diagram showing the layered structure of LeNet-5, including convolutional, pooling, and fully-connected layers. Input 32x32 C1: Conv S2: Pool C3: Conv S4: Pool Fully Connected

AlexNet (2012): The ‘Big Bang’ of Deep Learning

AlexNet won the 2012 ImageNet competition by a massive margin, heralding the dawn of the deep learning era.

Key Contributions:

  • Successful training of a comparatively deep CNN at ImageNet scale.
  • Widespread use of ReLU, which accelerated training.
  • Dropout and data augmentation to reduce overfitting.
  • Multi-GPU computation that made large-scale training a reproducible major advance.

VGGNet (2014): Depth is Power

The VGG team explored a simple but profound question: does making the network deeper improve performance?

Core Idea:

  • Minimalism: Used only small 3x3 convolution kernels and 2x2 pooling layers.
  • Stacking: By repeatedly stacking these simple blocks, they built very deep networks (e.g., VGG16, VGG19).

VGG proved that, to a certain extent, increasing network depth can significantly boost performance.

VGGNet Simplified Structure A series of stacked blocks representing VGG's philosophy of building depth by repeating simple modules. ... Building depth by stacking simple modules [Conv x N -> Pool]

GoogLeNet (2014): Wider and More Efficient Networks

Inception module: run 1×1, 3×3, 5×5 convolutions and pooling in parallel, then concatenate their multi-scale features.

Efficiency: 1×1 convolutions reduce channels before expensive branches, sharply lowering parameter and compute cost.

GoogLeNet Inception Module A diagram of the Inception module, showing four parallel branches for multi-scale feature extraction (1x1, 3x3, 5x5 convolutions, and pooling) and their concatenation. GoogLeNet Inception Module Four parallel feature scales Input 1×1 Conv 1×1 3×3 Conv 1×1 5×5 Conv 3×3 Pool 1×1 Conv Concatenate Output

ResNet (2015): Bridging the Depth Gap

  • As networks get extremely deep, a ‘degradation’ problem emerges: the training error of a deeper network is higher than that of its shallower counterpart.

  • ResNet (Residual Network), proposed by Kaiming He et al. at Microsoft Research Asia, elegantly solved this problem.

Core Idea: The Shortcut/Skip Connection

  • It allows information to ‘skip’ one or more layers. The network no longer needs to learn an identity mapping from scratch; it only needs to learn the ‘residual’ between the input and the output.

\[ \large{H(x) = F(x) + x} \]

ResNet’s innovation made it possible to train ultra-deep networks of hundreds or even thousands of layers; extension learners then return to the common leakage check and transfer.

ResNet Residual Block Diagram

ResNet Residual Block Illustration of a residual connection (skip connection) where the input 'x' is added to the output of the weight layers 'F(x)' to produce the final output 'H(x)'. ResNet: The Residual Block x W₁ W₂ + Add Input F(x) Identity Shortcut (x)

Formative Check: Detect Time Leakage

  • Question: A random stratified split of 2005–2024 monthly data produces a higher test score. Does that establish better generalization?

Answer yes/no first and name the time boundary crossed.

  • Reveal and remediation: No. Later regimes enter training and adjacent months cross sets. If you answered yes, return to the practical use timeline; if you mentioned only a random seed, return to expanding windows.

Step-by-Step Exercise: Expanding-Window Evaluation

  • Task:
    • Before the final test period, use five expanding folds with consecutive 12-month test blocks.

    • The purge-aware 199-month development sample induces training windows of 138, 150, 162, 174, and 186 months.

    • Submit each training end, test start/end, ROC-AUC, and AP (average precision).

Step-by-Step Exercise: Complete Evidence

  • Complete answer:
    • on 199 eligible development months from 2005-04 through 2021-10, TimeSeriesSplit(n_splits=5, test_size=12, gap=1) produces training windows of 138/150/162/174/186 months.

    • The one-month gap purges the next-month label boundary; the core code refits scaler and MLP in every fold and prints each date boundary.

    • Fold ROC-AUC values are 0.444, 0.694, 0.406, 0.314, and 0.444; AP values are 0.498, 0.622, 0.371, 0.395, and 0.604.

    • A valid answer keeps every fold, non-convergence, and the “do not deploy” interpretation.

Independent check Reconstruction: One decision process

  • Task:
    • reconstruct the decision process from the analysis: state the 4:1 cost, the three validation thresholds, when the final threshold was chosen, and the single test evaluation.

    • Do not reread y_test to select a threshold or generate a second test prediction.

  • Reference implementation:
    • threshold_cost_table and selected_cost_threshold were saved before test access.

    • test_cost_confusion came from the subsequent sole test check.

    • This page displays saved objects without recomputing from test labels or probabilities.

Apply It to a New Case: Reference Implementation and Output

Code
display(threshold_cost_table)  # Show the validation evidence saved before test access
print(selected_cost_threshold, test_cost_confusion.ravel(), 4 * test_cost_confusion[1, 0] + test_cost_confusion[0, 1])  # Report Thresholds, Quads, and Costs
threshold validation cost
0 0.3 52
1 0.5 47
2 0.7 49
0.5 [10  4 18  4] 76
  • Complete reference output:
    • validation costs are 52, 47, and 49, so threshold 0.5 is fixed.

    • Test confusion is TN=10, FP=4, FN=18, TP=4, with total cost 76.

    • Even under this illustrative cost function, missed alerts remain high; the decision remains “no automated action.”

Apply It to a New Case: Answer Checklist

  • Complete-answer reminder:
    • identify the file, key and required fields;

    • align \(t\rightarrow t+1\) correctly;

    • choose the threshold with validation data and use the test period once;

    • report the confusion matrix and cost;

    • and conclude that weak evidence does not justify action.

Sources and Further Reading

  • Goodfellow, I., Bengio, Y., and Courville, A. (2016), Deep Learning, MIT Press.
  • Rumelhart, D. E., Hinton, G. E., and Williams, R. J. (1986), “Learning Representations by Back-propagating Errors,” Nature.
  • scikit-learn User Guide:
  • Data: local hs300_index_only.h5 / hs300; all evaluation and confusion-matrix results come from the same completed analysis.

Core Summary: Evidence for All Five Objectives

  1. Neuron: compute the weighted sum and bias, then apply the activation to obtain its output.
  2. Activation choice: select Sigmoid, Tanh, or ReLU from gradient risk and architecture constraints; a default is not a prohibition.
  3. Learning mechanism: the chain rule backpropagates loss gradients, which gradient descent uses to update parameters.
  4. Model choice: order train → validation → test in time; choose the threshold on validation only, then evaluate it once on the test period.
  5. Evidence decision: interpret ROC-AUC, AP, recall, and the confusion matrix together; high misses and weak evidence here mean do not deploy.

Extension Summary: CNNs and Model History

CNNs use local connectivity, shared weights, and pooling for spatial structure; model history shows how these components evolved into deeper architectures.

Conclusion: A New Paradigm for Economic Modeling

  • Capturing Non-linearity: The core strength of neural networks is their powerful ability to fit non-linear relationships, helping us understand complex economic phenomena that linear models cannot explain.
  • Data-Driven: They are highly data-driven models capable of automatically learning features and patterns from large-scale datasets.
  • A Powerful Toolkit: Core covers MLP training and evaluation; CNNs extend the same ideas to structured inputs in the optional section.

Future Outlook and Caveats

  • Explainability (XAI):
    • Neural networks are often called ‘black box’ models because their decision-making processes are not transparent.

    • This is a major hurdle for their application in high-stakes areas like policy advice and credit scoring, and it is a hot research topic.

  • Causal Inference:
    • Neural networks excel at prediction (finding correlations) but cannot be directly used for causal inference.

    • Combining neural networks with causal inference frameworks (like Diff-in-Diff or Instrumental Variables) is a frontier research area.

  • More Models: We only introduced feedforward networks today. For time series data, Recurrent Neural Networks (RNNs) and their variants (like LSTM, GRU) are a more natural choice.

Thank You!

Q & A