Skip to content

Theano - 一个简单的训练示例

Theano - 基本训练示例(梯度下降)

Section titled “Theano - 基本训练示例(梯度下降)”

背景: 此示例演示了一个基本的机器学习概念:使用梯度下降更新模型参数(权重),以最小化损失函数(cost function)。虽然 Theano 对于此任务非常有效,但现代框架提供了更友好的 API 用于训练。

Theano 的优势在于定义计算图(computational graph),自动计算梯度(gradients)(theano.grad),以及指定参数更新(parameter updates)(在 theano.function 的 updates 参数中),然后它可以编译这些以实现高效执行,尤其是在多次训练迭代中。

让我们考虑一个非常简单的线性模型(linear model)。我们有一组输入特征(一个向量 x)和对应的权重(一个向量 W)。模型的输出 y 是特征和权重的逐元素乘积之和:y = sum(x * W)。

我们的目标是调整权重 W,使得对于给定的输入 x(例如,全为 1),输出 y 接近某个特定的 target 目标值(例如,100)。我们将使用梯度下降(gradient descent)来最小化平方误差损失函数(squared error cost function):cost = (target - y)^2。

import theano
import theano.tensor as tt
import numpy as np
print(f"Using Theano version: {theano.__version__}")

我们需要用于输入特征、目标值和权重的符号变量(symbolic variables)。权重的处理需要特殊方式,因为它们的值必须在多次调用训练函数时保持和更新。为此,Theano 使用了共享变量(shared variables)。

# 符号输入向量(例如,4 个特征,float32 类型)
x = tt.fvector('x')
# 符号目标值(标量,float32 类型)
target = tt.fscalar('target')
# 初始权重(作为 NumPy 数组)
initial_W = np.array([0.1, 0.25, 0.15, 0.3], dtype='float32')
# 为权重创建一个 Theano 共享变量。
# 共享变量具有可更新的持久值。
W = theano.shared(value=initial_W, name='W')
print(f"Initial weights (W): {W.get_value()}")

共享变量(theano.shared)是 Theano 中训练的核心。它们存储梯度下降将修改的模型参数。您可以使用 .get_value() 访问它们的当前数值,并通过 theano.function 中的 updates 机制进行更新。

现在,构建模型的输出、损失函数和梯度的表达式。

# 模型输出: y = sum(x * W)
y = (x * W).sum()
# 损失函数: 平方误差
cost = tt.sqr(target - y)
# 计算梯度: cost 相对于 W 如何变化
# theano.grad(cost, wrt) 计算 cost 相对于 wrt 的梯度
gradients = tt.grad(cost=cost, wrt=W)
# 注意: tt.grad 返回一个代表梯度的符号变量

指定如何使用计算出的梯度更新共享变量 W。这是梯度下降步骤的核心:W_new = W_old - learning_rate * gradient。

# 定义学习率
learning_rate = 0.1
# 定义共享变量 W 的更新规则
W_updated = W - (learning_rate * gradients)
# 为 theano.function 创建 'updates' 列表
# 它是一个元组列表: (要更新的共享变量, 新值的符号表达式)
updates = [(W, W_updated)]

编译一个 Theano 函数,它接受输入 x 和 target,计算输出 y(可选,但有助于查看进度),并对共享变量 W 应用指定的 updates。

# 编译函数
# Inputs: 符号输入 x 和 target
# Outputs: 符号输出 y (用于监控进度)
# Updates: 定义如何更新共享变量的列表
train_step = theano.function(
inputs=[x, target],
outputs=y, # 我们想在训练期间看到输出值
updates=updates
)

使用样本数据重复调用编译好的 train_step 函数。在每次调用中,函数计算输出,内部计算梯度,并根据规则更新权重 W。

# 定义训练数据 (为简单起见,特征全部使用 1)
training_x = np.array([1.0, 1.0, 1.0, 1.0], dtype='float32')
training_target = 100.0
num_iterations = 10
print(f"\nStarting training for {num_iterations} iterations...")
print(f"Target value: {training_target}")
for i in range(num_iterations):
# 执行一步训练
current_output = train_step(training_x, training_target)
# 打印进度
print(f"Iteration: {i}")
print(f" Current Output (y): {current_output:.4f}")
print(f" Updated Weights (W): {W.get_value()}")
import theano
import theano.tensor as tt
import numpy as np
print(f"Using Theano version: {theano.__version__}")
# 1. 定义符号变量
x = tt.fvector('x') # 输入特征 (float32)
target = tt.fscalar('target') # 目标值 (float32)
# 初始权重
initial_W = np.array([0.1, 0.25, 0.15, 0.3], dtype='float32')
# 权重的共享变量 (持久且可更新)
W = theano.shared(value=initial_W, name='W')
print(f"Initial weights (W): {W.get_value()}")
# 2. 定义符号计算图
y = (x * W).sum() # 模型输出
cost = tt.sqr(target - y) # 损失函数 (平方误差)
gradients = tt.grad(cost=cost, wrt=W) # 自动求导
# 3. 定义更新规则 (梯度下降)
learning_rate = 0.1
W_updated = W - (learning_rate * gradients)
updates = [(W, W_updated)] # theano.function 的更新列表
# 4. 编译训练函数
train_step = theano.function(
inputs=[x, target],
outputs=y, # 返回当前输出以便监控
updates=updates # 应用权重更新
)
# 5. 运行训练循环
training_x = np.array([1.0, 1.0, 1.0, 1.0], dtype='float32')
training_target = 100.0
num_iterations = 10
print(f"\nStarting training for {num_iterations} iterations...")
print(f"Target value: {training_target}")
for i in range(num_iterations):
current_output = train_step(training_x, training_target)
print(f"Iteration: {i}")
print(f" Current Output (y): {current_output:.4f}")
# 在步骤后访问更新后的权重
print(f" Updated Weights (W): {W.get_value()}")
print("\nTraining finished.")
print(f"Final weights: {W.get_value()}")
print(f"Final output for input {training_x}: {train_step(training_x, training_target):.4f}")

您应该观察到以下现象:

  • 初始输出 y 将是 initial_W 的总和(0.1 + 0.25 + 0.15 + 0.3 = 0.8)。
  • 在每次迭代中,Current Output (y) 将逐渐接近 target 目标值 100.0。
  • Updated Weights (W) 将在每次迭代中发生变化。由于输入 x 全部为 1,目标是 100,理想情况下权重应该收敛到总和接近 100 的值(例如,每个权重大约为 25,尽管确切值取决于学习率和迭代次数)。

这个示例虽然简单,但概括了 Theano 用于机器学习优化(optimization)的核心机制:符号化地定义模型和损失,让 Theano 计算梯度,为共享参数定义更新规则,以及编译一个高效函数以重复执行训练步骤。