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。
1. 导入和设置
Section titled “1. 导入和设置”import theanoimport theano.tensor as ttimport numpy as np
print(f"Using Theano version: {theano.__version__}")2. 定义符号变量
Section titled “2. 定义符号变量”我们需要用于输入特征、目标值和权重的符号变量(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 机制进行更新。
3. 定义符号计算图
Section titled “3. 定义符号计算图”现在,构建模型的输出、损失函数和梯度的表达式。
# 模型输出: 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 返回一个代表梯度的符号变量4. 定义更新规则
Section titled “4. 定义更新规则”指定如何使用计算出的梯度更新共享变量 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)]5. 编译训练函数
Section titled “5. 编译训练函数”编译一个 Theano 函数,它接受输入 x 和 target,计算输出 y(可选,但有助于查看进度),并对共享变量 W 应用指定的 updates。
# 编译函数# Inputs: 符号输入 x 和 target# Outputs: 符号输出 y (用于监控进度)# Updates: 定义如何更新共享变量的列表train_step = theano.function( inputs=[x, target], outputs=y, # 我们想在训练期间看到输出值 updates=updates)6. 运行训练循环
Section titled “6. 运行训练循环”使用样本数据重复调用编译好的 train_step 函数。在每次调用中,函数计算输出,内部计算梯度,并根据规则更新权重 W。
# 定义训练数据 (为简单起见,特征全部使用 1)training_x = np.array([1.0, 1.0, 1.0, 1.0], dtype='float32')training_target = 100.0num_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()}")完整程序列表
Section titled “完整程序列表”import theanoimport theano.tensor as ttimport 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.1W_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.0num_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}")预期输出分析
Section titled “预期输出分析”您应该观察到以下现象:
- 初始输出
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 计算梯度,为共享参数定义更新规则,以及编译一个高效函数以重复执行训练步骤。