原文:Machine Learning for Economics and Finance in TensorFlow 2
一、TensorFlow 2
TensorFlow 是谷歌大脑团队制作的机器学习开源库。它最初于 2015 年向公众发布,并迅速成为最受欢迎的深度学习库之一。2019 年,谷歌发布了 TensorFlow 2,与 TensorFlow 1 有了实质性的背离。在本章中,我们将介绍 TensorFlow 2,解释它在经济学和金融学中的应用,然后回顾理解后面章节中的内容所必需的预备材料。如果您没有使用 TensorFlow 1,您可能希望跳过“TensorFlow 2 中的变化”部分。
安装 TensorFlow
为了使用 TensorFlow 2,您需要安装 Python。由于 2020 年 1 月 1 日起不再支持 Python 2,所以我推荐通过 Anaconda 安装 Python 3,它捆绑了 Python 7500+个数据科学常用模块: www.anaconda.com/distribution/
。一旦安装了 Anaconda,就可以在操作系统的命令行中配置虚拟环境。下面的代码将使用 Python 3.7.4 安装一个名为tfecon
的 Anaconda 虚拟环境,这就是我们将在本书中使用的:
conda create -n tfecon python==3.7.4
您可以使用以下命令激活环境:
conda activate tfecon
在该环境中,您可以使用以下命令安装 TensorFlow:
(tfecon) pip install tensorflow==2.3.0
当您想要停用虚拟环境时,可以使用以下命令:
conda deactivate
我们将在整本书中使用 TensorFlow 2.3 和 Python 3.7.4。为了确保与示例兼容,您应该相应地配置您的虚拟环境。
TensorFlow 2 的变化
TensorFlow 1 是围绕静态图形构建的。为了执行计算,首先需要定义一组张量和一系列操作。这形成了计算图,它在运行时是固定的。静态图为构建优化的产品代码提供了一个理想的环境,但也阻碍了实验,增加了调试的难度。
在清单 1-1 中,我们提供了一个在 TensorFlow 1 中构造和执行静态计算图的例子。我们将考虑一种常见的情况,即我们希望使用一组回归变量(特征),X
,通过普通的最小二乘(OLS)回归来预测因变量,Y
。这个问题的解决方案是系数向量,它使回归残差平方和最小。方程 1-1 给出了它的解析表达式。
方程式 1-1。最小二乘问题的解法。
)
import tensorflow as tf
print(tf.__version__)
'1.15.2'
# Define the data as constants.
X = tf.constant([[1, 0], [1, 2]], tf.float32)
Y = tf.constant([[2], [4]], tf.float32)
# Matrix multiply X by X's transpose and invert.
beta_0 = tf.linalg.inv(tf.matmul(tf.transpose(X), X))
# Matrix multiply beta_0 by X's transpose.
beta_1 = tf.matmul(beta_0, tf.transpose(X))
# Matrix multiply beta_1 by Y.
beta = tf.matmul(beta_1, Y)
# Perform computation in context of session.
with tf.Session() as sess:
sess.run(beta)
print(beta.eval())
[[2.]
[1.]]
Listing 1-1Implement OLS in TensorFlow 1
TensorFlow 1 的语法很麻烦,这就是为什么我们将系数向量的计算分成多个步骤以保持可读性。此外,我们必须通过构建图来执行计算,然后在tf.Session()
的上下文中执行它。我们还必须在一个会话中打印系数向量的元素。否则,打印beta
将简单地返回对象的名称、形状和数据类型。
清单 1-2 重复了相同的练习,但是针对 TensorFlow 2。
import tensorflow as tf
print(tf.__version__)
'2.3.0
# Define the data as constants.
X = tf.constant([[1, 0], [1, 2]], tf.float32)
Y = tf.constant([[2], [4]], tf.float32)
# Matrix multiply X by X's transpose and invert.
beta_0 = tf.linalg.inv(tf.matmul(tf.transpose(X), X))
# Matrix multiply beta_0 by X's transpose.
beta_1 = tf.matmul(beta_0, tf.transpose(X))
# Matrix multiply beta_1 by Y.
beta = tf.matmul(beta_1, Y)
# Print coefficient vector.
print(beta.numpy())
[[2.]
[1.]]
Listing 1-2Implement OLS in TensorFlow 2
虽然从代码中看不出这一点,但 TensorFlow 2 使用了命令式编程,这意味着 Python 调用操作时会执行这些操作。例如,这意味着beta_0
不是一个将在静态图中执行的操作,而是该计算的实际输出。我们可以通过在 TensorFlow 1 和 TensorFlow 2 代码中打印相同的对象来看到这一点,正如我们在清单 1-3 和 1-4 中所做的那样。
# Print the feature matrix.
print(X)
tf.Tensor("Const_11:0", shape=(2, 2), dtype=float32)
# Print the coefficient vector.
print(beta)
tf.Tensor("MatMul_20:0", shape=(2, 1), dtype=float32)
Listing 1-3Print tensors in TensorFlow 1
在 TensorFlow 1(清单 1-3 )中,X
是定义常数张量的运算,beta
是执行矩阵乘法的运算。Printing 返回输出的操作类型、形状和数据类型。在 TensorFlow 2(清单 1-4 )中,打印X
或beta
将返回一个tf.Tensor()
对象,该对象由包含在一个数组中的输出值及其形状和数据类型组成。为了检索 TensorFlow 1 中操作的输出值,我们必须在会话的上下文中应用eval()
方法。
# Print the feature matrix.
print(X)
tf.Tensor(
[[1\. 0.]
[1\. 2.]], shape=(2, 2), dtype=float32)
# Print the coefficient vector.
print(beta.numpy())
[[2.]
[1.]]
Listing 1-4Print tensors in TensorFlow 2
虽然 TensorFlow 1 最初是围绕静态图的构造和执行而构建的,但它后来引入了通过使用渴望执行来强制执行计算的可能性,这是在 2017 年 10 月发布的。 1 TensorFlow 2 通过默认启用急切执行,在这条开发路径上走得更远。这就是为什么我们不需要在一个会话中执行计算。
转向急切执行的一个结果是 TensorFlow 2 不再默认构建静态计算图。在 TensorFlow 1 中,这样的图形可以很容易地从日志中获得,比如清单 1-5 中生成的那些,然后使用 TensorBoard 可视化。图 1-1 显示了 OLS 问题的图表。节点代表操作,例如矩阵乘法和转置,以及tf.Tensor()
对象的创建。图形的边表示在运算之间传递的张量的形状。
# Export static graph to log file.
with tf.Session() as sess:
tf.summary.FileWriter('/logs', sess.graph)
Listing 1-5Generate logs for a TensorBoard visualization in TensorFlow 1
TensorFlow 2 中的另一个变化是,您可能已经在清单 1-1 和 1-2 中注意到了,我们不再需要评估张量来公开它们的元素。我们可以通过应用numpy()
方法来做到这一点,顾名思义,该方法提取一个tf.Tensor()
对象的元素作为一个numpy
数组。
图 1-1
张量板生成的 OLS 计算图
虽然 TensorFlow 2 在默认情况下不再使用静态图,但它确实为用户提供了通过使用@tf.function
来构建静态图的选项。这个装饰器可以用来以一种与 TensorFlow 1 完全不同的方式将静态图合并到代码中。我们可以通过在函数之前加入@tf.function
装饰器,将函数转换成静态图,而不是显式地构造一个图,然后使用tf.Session()
来执行它。
使用@tf.function
生成静态图形的主要优势是,函数将被编译,并且可能在 GPU 或 TPU 上运行得更快。此外,在@ tf.function
decorator 下定义的函数中调用的任何函数也将被编译。清单 1-6 给出了一个在 TensorFlow 2 中使用静态图的例子。这里,我们回到 OLS 的例子,定义一个函数,根据特征矩阵X
和估计的系数向量beta
进行预测。注意ols_predict()
定义上方@tf.function
的使用。
# Define OLS predict function as static graph.
@tf.function
def ols_predict(X, beta):
y_hat = tf.matmul(X, beta)
return y_hat
# Predict Y using X and beta.
predictions = ols_predict(X, beta)
Listing 1-6Generate OLS predictions with static graphs in TensorFlow 2
除了我们到目前为止提到的,TensorFlow 2 还引入了大量的名称空间变化。这是为了清理 TensorFlow 1,它有许多冗余的端点。TensorFlow 2 还消除了tf.contrib()
名称空间,该名称空间用于容纳 TensorFlow 1 中尚不完全支持的杂项操作。在 TensorFlow 2 中,这段代码现在被重新定位到各种相关的名称空间中,更容易找到。 2
最后,TensorFlow 2 围绕许多高级 API 进行了重新定位。特别是,更多的重点放在 Keras 和估计 API。Keras 简化了神经网络模型的构建和训练。和估计器提供了一组有限的模型,这些模型可以用一小组参数来定义,然后部署到任何环境中。特别是,估算器模型可以在多服务器设置中,以及在 TPU 和 GPU 上进行训练,而无需修改代码。
在清单 1-7 中,我们展示了在 Keras 中定义和训练 OLS 模型的过程。我们使用估算器库在清单 1-8 中做同样的事情。请注意,Keras 和估计器都需要较少的代码行来定义和训练 OLS 模型。然而,与清单 1-2 中给出的低级 TensorFlow 示例相反,他们通过最小化数字误差平方和来求解模型,而不是利用其解析解。
# Define sequential model.
ols = tf.keras.Sequential()
# Add dense layer with linear activation.
ols.add(tf.keras.layers.Dense(1, input_shape = (2,),
use_bias = False, activation = 'linear'))
# Set optimizer and loss.
ols.compile(optimizer = 'SGD', loss = 'mse')
# Train model for 500 epochs.
ols.fit(X, Y, epochs = 500)
# Print parameter estimates.
print(ols.weights[0].numpy())
[[1.9754077]
[1.0151987]]
Listing 1-7Solve an OLS model with tf.keras()
使用 Keras 方法,我们首先使用tf.keras.Sequential()
定义了一个序列神经网络模型。顺序模型可用于通过以下方式建立和训练神经网络:( 1)将层依次堆叠在彼此之上;(2)通过指定选项来编译模型,例如优化器、损失和学习率;(3)应用fit()
方法。请注意,该模型由具有线性激活的单个密集层组成,因为我们正在执行线性回归。此外,use_bias
被设置为False
,因为X
的第一列是一个向量,我们用它来估计常数(偏差)项。我们在编译模型时使用了均方误差损失,因为我们使用的是普通的最小二乘法,它可以使误差平方和最小化。最后,我们将epochs
——我们跳过整个样本的次数——设置为 500。一旦模型被训练,我们就可以打印参数估计值,这些参数估计值在ols.weights
属性中以列表的形式提供。在这种情况下,列表包含一个对象,模型参数,我们将使用numpy()
方法恢复它。
# Define feature columns.
features = [
tf.feature_column.numeric_column("constant"),
tf.feature_column.numeric_column("x1")
]
# Define model.
ols = tf.estimator.LinearRegressor(features)
# Define function to feed data to model.
def train_input_fn():
features = {"constant": [1, 1], "x1": [0, 2]}
target = [2, 4]
return features, target
# Train OLS model.
ols.train(train_input_fn, steps = 100)
Listing 1-8Solve an OLS model with tf.estimator()
使用估计器方法,我们首先定义特性列,以及它们的名称和类型。在清单 1-8 给出的例子中,我们有两个特征,其中之一是常数项(或者机器学习中的“偏差”)。然后,我们通过将特性列从tf.estimator
传递到LinearRegressor()
模型来定义模型。最后,我们定义了一个向模型提供数据的函数,然后应用了train()
方法,将train_input_fn
指定为第一个参数,将时期数指定为第二个参数。
为了用tf.estimator
进行预测,我们可以使用我们定义的模型ols
的predict()
方法。与训练例程类似,我们需要定义一个生成输入数据集的函数,我们称之为test_input_fn()
,如清单 1-9 所示。将它传递给ols.predict()
将产生一个用于模型预测的生成器函数。然后我们可以使用 list comprehension 收集所有的预测,使用next()
遍历所有的生成器输出。
# Define feature columns.
def test_input_fn():
features = {"constant": [1, 1], "x1": [3, 5]}
return features
# Define prediction generator.
predict_gen = ols.predict(input_fn=test_input_fn)
# Generate predictions.
predictions = [next(predict_gen) for j in range(2)]
# Print predictions.
print(predictions)
[{'predictions': array([5.0000067], dtype=float32)},
{'predictions': array([7.000059], dtype=float32)}]
Listing 1-9Make predictions with an OLS model with tf.estimator()
经济和金融 TensorFlow
如果你不熟悉机器学习,你可能想知道为什么通过使用 TensorFlow 来学习它是有意义的。用现在提供机器学习工具箱的 MATLAB 不是更简单吗?一些监督学习方法不能使用 Stata 或 SAS 来执行吗?TensorFlow 不是以具有挑战性而闻名吗,即使是在机器学习框架中?我们将在这一部分探讨这些问题,并讨论 TensorFlow 和机器学习能为经济学家提供什么。
我们将从学习 TensorFlow 的论点开始,而不是使用更熟悉的工具或其他机器学习框架。使用 TensorFlow 的一个好处是,它是一个开源库,可以用 Python 编写,由 Google 维护。这意味着没有许可成本,它受益于庞大的 Python 开发人员社区,并且它可能会得到良好的维护,因为它是机器学习领域商业领导者之一的首选工具。使用 TensorFlow 的另一个好处是,自发布以来,它一直是最受欢迎的机器学习框架之一。
图 1-2 显示了九个最受欢迎的机器学习框架获得的 GitHub 星级数。该图表明 TensorFlow 的受欢迎程度大约是第二大受欢迎框架的四倍。总的来说,这将使您更容易为您的项目找到用户创建的库、代码示例和预训练的模型。最后,虽然 TensorFlow 1 相对于其他机器学习框架具有挑战性,但 TensorFlow 2 要简单得多。大部分挑战来自 TensorFlow 提供的灵活性,这将提供相对于更有限的框架的实质性优势。
TensorFlow 在经济和金融应用中至少有两种使用方式。第一个与机器学习有关,机器学习刚刚开始在经济和金融领域获得广泛应用。TensorFlow 非常适合这种应用,因为它是一个机器学习框架。TensorFlow 的第二种用途是求解理论经济和金融模型。相对于其他机器学习库,TensorFlow 的优势在于允许使用高级和低级 API。低级 API 可用于构建和求解任何任意的经济或金融模型。在本节的剩余部分,我们将提供这两个用例的概述。
图 1-2
GitHub stars by machine learning framework(2015–2019)。来源:GitHub 和 Perrault 等人(2019 年)
机器学习
经济学家最初抵制采用机器学习的方法,但后来开始接受它们。这种不情愿的部分原因是计量经济学和机器学习的方向不同。计量经济学以简约的线性模型中的因果推理为中心,而机器学习则以使用具有许多参数的非线性模型进行预测为中心。
然而,经济学和机器学习之间存在某种程度的重叠。例如,经济和金融预测与机器学习有着相同的目标:准确的样本外预测。此外,计量经济学中常用的许多线性模型也用于机器学习。然而,机器学习在经济学中有更大的应用潜力,我们将在第二章详细讨论。
当涉及到机器学习在经济学中的应用时,TensorFlow 具体提供了什么?TensorFlow 至少有五个优点可能对经济和金融应用有益:(1)灵活性,(2)分布式培训,(3)生产质量,(4)高质量的文档,以及(5)扩展。
灵活性
正如我们将在第二章中详细讨论的,经济学中机器学习的许多应用不允许使用现成的例程(Athey,2019)。因此,熟悉允许灵活性的机器学习框架将是有用的。当然,这是有代价的。对于许多现成的应用程序,更简单和更严格的框架,如sklearn
或keras
,通常会允许更快和更不容易出错的开发。然而,对于将因果推理与机器学习相结合或需要非标准模型架构的工作,除了在灵活的机器学习框架中开发之外,将没有其他选择。TensorFlow 特别适合这项任务,因为它允许混合使用高级和低级 API 进行开发。例如,我们可以使用tensorflow
构建一个算法,该算法将深度神经网络(DNN)嵌入到经济计量估计例程中,其中使用tensorflow
中的高级keras
API 处理 DNN,使用低级tensorflow
操作构建外部算法。
分布式培训
经济学中的许多机器学习应用不需要使用分布式训练过程。例如,CPU 训练对于具有几百个回归量和几万个观察值的惩罚线性回归模型来说通常是足够的。但是,如果您想要微调 ResNet 模型,以便从船舶交通的卫星图像中预测贸易流量,您将需要利用分布式培训。TensorFlow 2 自动检测图形处理单元(GPU)和张量处理单元(TPU),并可以在训练过程中使用它们。清单 1-10 提供了一个过程示例,通过该示例,我们可以列出所有可用的设备,并选择一个设备(如 GPU 或 CPU)用于培训。
在某些情况下,您可能希望将计算分布在一个设备的两个内核上,如 GPU 或 TPU,以及多个设备上。例如,您可能可以访问一个带有两个 GPU 的工作站。如果您没有使用 TensorFlow 或其他为分布式计算提供功能的框架,您将无法有效地利用这两个 GPU。或者,您可能希望将计算分布在云中的多个 GPU 上,以避开内存瓶颈。或者,如果您从事工业,您可能有一个应用程序,该应用程序必须使用大型模型实时执行分类,并将信息返回给用户。同样,在多个 GPU 或 TPU 上的分布式计算可能是实现这一点同时保持低延迟的唯一选择。
TensorFlow 通过tf.distribute.Strategy()
为多设备分布式计算提供接口。TensorFlow 的方法的优点是简单,无需修改就能很好地执行。您可以简单地指定将要使用的设备和分配策略,而不必决定如何将计算分配到底层细节。TensorFlow 支持同步策略和异步策略,同步策略可在设备间保持相同的参数值和梯度,异步策略可在单个设备上进行本地更新。
import tensorflow as tf
# Print list of devices.
devices = tf.config.list_physical_devices()
print(devices)
[PhysicalDevice(name='physical:device:CPU_0',
Device_type='CPU'),
PhysicalDevice(name='physical_device:XLA_CPU:0',
Device_type='XLA_CPU'),
PhysicalDevice(name='physical_device:XLA_GPU:0',
Device_type='XLA_GPU'),
PhysicalDevice(name='physical_device:GPU:0',
Device_type='GPU')
# Set device to CPU.
tf.config.experimental.set_visible_devices(
devices[0], 'CPU')
# Change device to GPU.
tf.config.experimental.set_visible_devices(
devices[3], 'GPU')
Listing 1-10List all available devices, select CPU, and then switch to GPU
生产质量
对于在工业中工作并使用机器学习来创造产品或提供服务的经济学家来说,代码最终从“实验”或“开发”阶段进入生产质量是至关重要的。这降低了最终用户遇到错误或稳定性问题的可能性。TensorFlow 的另一个优势是,它提供了生产和提供生产质量代码的功能。
对于生产质量代码的创建,TensorFlow 提供了高级评估者 API。例如,这可以用于在实施最佳实践并删除开发过程中容易出错的部分的环境中训练神经网络。Estimators API 允许开发人员既可以利用预先制作的模型,其中模型架构可以用少量参数完全指定,也可以开发自己的模型。
除了用于开发模型的 Estimators API 之外,TensorFlow Serving 还可用于为最终用户开发和部署生产质量的应用程序。例如,使用 TensorFlow 服务,我们可以允许用户以数据、文本或图像的形式提交查询,然后输入到模型中,为用户生成分类或预测。
高质量的文档
TensorFlow 1 最初有不透明和不完整的文档,这是它让新来者望而生畏的部分原因。对于经常使用记录良好的计量经济学和计算商业软件(如 MATLAB、Stata 和 SAS)的经济学家来说尤其如此。然而,当谷歌开始研究 TensorFlow 2 时,这种情况发生了变化。从那以后,它已经过渡到高质量和详细的文档,这现在是它作为机器学习框架的主要资产之一。
TensorFlow 文档的一个优势是,它经常与谷歌合作实验室(Colab)笔记本配对使用。如果你对 Google Colab 不熟悉,它是托管 Jupyter 笔记本的免费服务。它还允许用户免费使用 GPU 和 TPU 在谷歌的服务器上执行笔记本。将文档与 Colab 笔记本配对使用户能够立即启动一个最小的代码示例,如果需要可以修改它,并在最先进的硬件上执行它。
扩展ˌ扩张
将 TensorFlow 用于机器学习的经济和金融应用的另一个优势是,它有许多扩展。在接下来的小节中,我们将只强调四个这样的扩展,但是还有其他几个扩展可能会引起经济学家的兴趣。
TensorFlow Hub
位于 https://tfhub.dev/
的 TensorFlow Hub 提供了一个可搜索的预训练模型库,可将其导入 TensorFlow,然后按原样用于分类和回归任务,或针对相关任务进行微调。例如,您可以使用 TensorFlow Hub 导入在 ImageNet 数据集上训练的 EfficientNet 模型,删除分类头,然后训练模型使用替代数据集执行不同的分类任务。
TensorFlow 概率
TensorFlow probability 专为统计学家和机器学习研究人员设计,提供了一组扩展的概率分布和工具,用于开发概率模型,包括神经网络模型中的概率层。它还支持变分推理、马尔可夫链蒙特卡罗(MCMC)和计量经济学中常用的一组扩展的优化器,如 BFGS。对于希望用机器学习模型进行因果推断的学院派经济学家来说,TensorFlow 概率将是不可或缺的工具。
TensorFlow 联邦
在某些情况下,训练模型所需的数据将是分散的,这使得用标准方法完成任务变得不可行。对于学术界和公共部门的经济学家来说,当法律或隐私问题阻止数据共享时,这个问题经常出现。对于行业经济学家来说,当数据分布在移动电话等用户设备上,但无法集中时,可能会出现这种情况。在前面的所有案例中,联邦学习提供了在不集中数据的情况下训练模型的可能性。这可以使用 TensorFlow 联邦扩展来完成。
TensorFlow Lite
从事工业的经济学家通常使用多个 GPU 或 TPU 来训练模型,只是为了将它们部署到具有严重计算资源限制的环境中。TensorFlow Lite 可以在这种情况下使用,以避免资源限制并提高性能。它的工作原理是将 TensorFlow 模型转换为另一种格式,压缩权重,然后输出一个. tflite 文件,该文件可以部署到移动环境中。
理论模型
虽然 TensorFlow 主要是为构建和解决深度学习模型而设计的,但它提供了各种各样的计算工具,可用于解决任何任意模型。这与较窄的机器学习框架不同,后者不够灵活,无法在定义明确的家族之外构建模型。
特别是 TensorFlow 可以用来求解经济学和金融学中的理论模型。这可以通过(1)定义表示模型的计算图和(2)定义相关的损失函数来完成。然后,我们可以在 TensorFlow 中应用标准优化程序,如随机梯度下降(SGD ),以最小化损失函数。
TensorFlow 最先进的自动微分库,以及执行并行和分布式计算的便利性,使其成为解决经济和金融理论模型的现有软件的强大替代品。我们将在第十章中详细讨论这个问题。
张量介绍
TensorFlow 主要是为了用神经网络执行深度学习而设计的。由于神经网络由张量在张量上执行的操作组成,TensorFlow 是这个名称的自然选择。
虽然张量在某些上下文中有特定的数学定义,如物理,但我们将采用与机器学习最相关的定义,摘自深度学习(古德费勒、本吉奥和库维尔,2016 年):
在一般情况下,排列在具有可变轴数的规则网格上的数字阵列被称为张量。
实际上,我们经常用张量的秩和形状来描述张量。索引为k)的矩形阵列被称为秩为- k 。你也可以看到这样一个数组,它被描述为具有顺序或维度 k 。张量的形状是由它的每个维度的长度决定的。
例如,考虑我们在清单 1-2 中描述的 OLS 问题,其中我们使用了三个张量: X 、 Y 和 β 。它们分别是特征矩阵、目标向量和系数向量。在一个具有 m 特征和 n 观测值的回归问题中, X 是形状为 (n,m) 的秩 2 张量,Y 是形状为 n 的秩 1 张量, β 是形状为 m 的秩 1 张量。
更一般地,秩 0 张量是标量,秩 1 张量是向量,秩 2 张量是矩阵。我们将秩为- k 的张量称为 k-张量,其中 k ≥ 3。图 1-3 显示了一批具有三个颜色通道的图像的定义。
在图 1-3 的左上方,我们有来自蓝色通道的单个像素,它将由单个整数表示。这是一个标量或秩为 0 的张量。在右边,我们有一个像素集合,它构成了图像绿色通道的边界。这些构成了秩 1 张量或向量。如果我们把整个红色通道本身,这是一个矩阵或秩 2 张量。此外,如果我们组合三个颜色通道,这形成了一个彩色图像,这是一个 3-张量;如果我们将多个图像堆叠成一个训练批次,我们会得到一个 4 张量。
值得强调的是,张量的定义通常假定为矩形。也就是说,如果我们正在处理一批图像,每个图像都应该具有相同的长度、宽度和颜色通道数。如果每个图像都有不同的形状,我们如何指定批量张量的形状就不明显了。此外,许多机器学习框架将无法以充分利用 GPU 或 TPU 的并行化能力的方式处理非矩形张量。
图 1-3
将一批彩色图像分解成张量
对于我们在本书中考虑的大多数问题,数据要么自然地是矩形的,要么可以在性能没有实质性损失的情况下被重新整形为矩形。然而,在有些情况下它不能。幸运的是,TensorFlow 提供了一种称为“粗糙张量”的数据结构,可以作为tf.ragged
使用,它与 100 多种 TensorFlow 操作兼容。还有新一代的卷积神经网络(CNN ),它利用掩蔽,这是一种识别图像重要部分的过程,允许使用可变的输入形状图像。
TensorFlow 中的线性代数与微积分
与计量经济学例程类似,机器学习算法广泛使用线性代数和微积分。然而,在标准的机器学习框架中,这其中的大部分仍然对用户隐藏。相反,TensorFlow 允许用户从高级和低级 API 构建模型。例如,使用低级 API,他们可以构建非线性最小二乘估计例程或算法,在线性代数和微积分运算级别训练神经网络。在本节中,我们将讨论如何使用 TensorFlow 执行线性代数和微积分中的常见运算。然而,在我们这样做之前,我们将首先讨论 TensorFlow 中的常数和变量,它们是描述线性代数和微积分运算的基础。
常量和变量
TensorFlow 将张量对象分为常量和变量。术语“常量”和“变量”的含义与编程中的标准用法一致。也就是说,常数是固定的,而变量可能会随时间而变化。为了说明这一点,我们回到清单 1-11 中的 OLS 例子。我们不需要解析地解决这个问题,而是简单地计算一个剩余项,它可以用来构造一个损失函数。
特征矩阵X
和目标Y
被定义为常数张量,因为它们不会随着模型的训练而改变。参数向量beta
被定义为使用tf.Variable()
的变量,因为它将被优化算法改变以试图最小化残差的变换。 3
import tensorflow as tf
# Define the data as constants.
X = tf.constant([[1, 0], [1, 2]], tf.float32)
Y = tf.constant([[2], [4]], tf.float32)
# Initialize beta.
beta = tf.Variable([[0.01],[0.01]], tf.float32)
# Compute the residual.
residuals = Y - tf.matmul(X, beta)
Listing 1-11Define constants and variables for OLS
一般来说,我们将对输入数据和模型产生的中间数据(如残差)使用常数张量。我们还将使用常数张量来捕捉模型超参数。例如,对于神经网络和惩罚回归模型,我们将在训练过程之外选择正则化参数,并使用tf.constant()
来定义它们。
一般来说,我们会使用tf.Variable()
来初始化可训练模型参数。例如,这包括神经网络中的权重、线性回归的系数向量,或者使用参数矩阵进行线性变换的模型中的中间步骤。
线性代数
由于 TensorFlow 以深度学习模型为中心——利用张量输入,产生张量输出,并应用线性变换——它的设计具有相当大的能力来执行线性代数计算,并将这些计算分布在 GPU 和 TPU 上。在本节中,我们将讨论如何使用 TensorFlow 执行线性代数中的常见运算。
标量加法和乘法
虽然标量可以被认为是秩为 0 的张量,并在 TensorFlow 中被定义为张量对象,但我们通常会将它们用于与向量、矩阵和 k-张量不同的目的。此外,可以在向量和矩阵上执行的某些操作不能在标量上执行。
在清单 1-12 中,我们研究了如何在 TensorFlow 中执行标量加法和乘法。我们将使用两个标量s1
和s2
来做这件事,我们将使用tf.constant()
来定义它们。如果我们想让这些标量成为模型中的可训练参数,我们可以使用tf.Variable()
。注意,我们首先使用tf.add()
执行加法,使用tf.multiply()
执行乘法。然后我们利用操作符重载,使用+
和*
执行相同的操作。最后,我们打印我们计算的总和和乘积。注意,两者都是类型为float32
的tf.Tensor()
对象,因为我们将每个常量定义为一个tf.float32
。
张量加法
我们接下来检查张量加法,因为它只有一种形式,并推广到 k-张量。对于 0-张量(标量),我们看到可以应用tf.add()
操作,它将作为参数的两个标量相加。如果我们将此扩展到秩为 1 的张量(向量),加法就像等式 1-2 一样工作:也就是说,我们对每个向量中的相应元素求和。
方程式 1-2。矢量加法的例子。
)
import tensorflow as tf
# Define two scalars as constants.
s1 = tf.constant(5, tf.float32)
s2 = tf.constant(15, tf.float32)
# Add and multiply using tf.add() and tf.multiply().
s1s2_sum = tf.add(s1, s2)
s1s2_product = tf.multiply(s1, s2)
# Add and multiply using operator overloading.
s1s2_sum = s1+s2
s1s2_product = s1*s2
# Print sum.
print(s1s2_sum)
tf.Tensor(20.0, shape=(), dtype=float32)
# Print product.
print(s1s2_product)
tf.Tensor(75.0, shape=(), dtype=float32)
Listing 1-12Perform scalar addition and multiplication in TensorFlow
此外,我们可以将其扩展到秩为 2 的张量(矩阵),如等式 1-3 所示,以及秩为 k 的张量,其中 k > 2。在所有情况下,操作都以相同的方式执行:对两个张量中相同位置的元素求和。
方程式 1-3。矩阵加法的例子*。*
)
请注意,张量加法只能使用两个相同形状的张量来执行。 4 两个形状不同的张量不会总是在相同的位置定义两个元素。此外,注意张量加法一般满足交换律和结合律。??
在清单 1-13 中,我们演示了如何对秩为 4 的张量执行张量加法。我们将使用两个四维张量,images
和transform
,它们已经作为numpy
数组导入。images
张量是一批 32 色图像,transform
张量是加法变换。
我们首先打印出images
和transform
的形状,检查它们是否相同,这是张量加法所需要的。我们可以看到,这两个对象的形状都是(32,64,64,3)。也就是说,它们由一批 32 个图像组成,这些图像为 64x64,具有三个颜色通道。接下来,我们使用tf.constant()
将两个numpy
数组转换成 TensorFlow 常量对象。然后我们分别使用tf.add()
和重载的+
操作符来应用加法变换。请注意,+
操作符将在 TensorFlow 中执行计算,因为我们将两个张量都转换为 TensorFlow 中的常量对象。
import tensorflow as tf
# Print the shapes of the two tensors.
print(images.shape)
(32, 64, 64, 3)
print(transform.shape)
(32, 64, 64, 3)
# Convert numpy arrays into tensorflow constants.
images = tf.constant(images, tf.float32)
transform = tf.constant(transform, tf.float32)
# Perform tensor addition with tf.add().
images = tf.add(images, transform)
# Perform tensor addition with operator overloading.
images = images+transform
Listing 1-13Perform tensor addition in TensorFlow
张量乘法
与张量加法相反,我们只考虑在两个相同形状的张量上执行的元素运算,我们将考虑三种不同类型的张量乘法:
-
逐元素乘法
-
点积
-
矩阵乘法
逐元素乘法
与张量加法一样,元素乘法仅针对具有相同维数的张量定义。例如,如果我们有两个秩为 3 的张量 A 和 B,每个都有索引 I、J 和 R,其中 i ∈ {1、…、 I }、 j ∈ {1、…、 J }、和 r ∈ {1、…、 R },那么它们的元素乘积就是张量 C,其中每个元素 C 【T
方程式 1-4。初等张量乘法。
)
等式 1-5 提供了两个矩阵的初等张量乘法的例子。请注意,⊙表示元素级乘法。
方程式 1-5。初等张量乘法。
)
清单 1-14 中给出了元素张量乘法的 TensorFlow 实现。我们将乘上两个 6-张量,A
和B
,它们是通过从正态分布中抽取而生成的。我们提供给tf.random.normal()
的整数列表是 6 张量的形状。注意A
和B
都是形状的 6 张量(5,10,7,3,2,15)。为了执行元素乘法,两个张量必须具有相同的形状。此外,我们可以使用 TensorFlow 乘法运算符tf.multiply()
或重载乘法运算符*
来执行元素乘法,因为我们使用 TensorFlow 运算生成了A
和B
。
点积
两个向量 A 和 B 之间可以进行点积,元素个数相同,n .是 A 和 B 中对应元素的乘积之和.设A=A0…An和B=[B0…B 它们的点积 c 表示为c=A**B,并在等式 1-6 中定义。
方程式 1-6。 矢量的点积 。
![ c = ∑ i = 0 n a i b i c=\sum \limits_{i=0}^n{a}_i{b}_i c=i=0∑naibi
import tensorflow as tf
# Generate 6-tensors from normal distribution draws.
A = tf.random.normal([5, 10, 7, 3, 2, 15])
B = tf.random.normal([5, 10, 7, 3, 2, 15])
# Perform elementwise multiplication.
C = tf.multiply(A, B)
C = A*B
Listing 1-14Perform elementwise multiplication in TensorFlow
注意,点积将两个向量转换成一个标量,c
。清单 1-15 演示了如何在 TensorFlow 中执行点积。我们首先定义两个向量,A
和B
,每个向量有 200 个元素。然后我们应用tf.tensordot()
操作,它将两个张量参数axes
作为自变量。为了计算两个向量的点积,我们将使用 1 作为axes
参数。最后,我们提取c
的numpy
属性,它给出了常量对象的一个numpy
数组。打印出来,我们可以看到点积的输出确实是一个标量。 6
import tensorflow as tf
# Set random seed to generate reproducible results.
tf.random.set_seed(1)
# Use normal distribution draws to generate tensors.
A = tf.random.normal([200])
B = tf.random.normal([200])
# Perform dot product.
c = tf.tensordot(A, B, axes = 1)
# Print numpy argument of c.
print(c.numpy())
-15.284362
Listing 1-15Perform dot product in TensorFlow
矩阵乘法
接下来我们考虑矩阵乘法,我们将专门讨论秩为 2 的张量的情况。这是因为我们将只对矩阵应用这个操作。在我们对 k>2 的 k 个张量执行矩阵乘法的情况下,我们实际上将执行“批量”矩阵乘法。例如,这用于卷积神经网络(CNN)的训练和预测任务,其中我们可能希望将同一组权重乘以一批图像中的所有图像。
让我们再次考虑这样的情况,我们有两个张量,A
和B
,但是这一次,它们不需要具有相同的形状,但是需要是矩阵。如果我们希望将A
乘以B
,那么A
的列数必须等于B
的行数。A
和B
乘积的形状将等于A
中的行数乘以B
中的列数。
现在,如果我们让 A i : 表示矩阵A
中的第 I 行,B:j表示矩阵B
中的第 j 列,C
表示A
和B
的乘积,那么对所有行都定义了矩阵乘法, j ∈ {1,…,C 中的 J },如等式 1-7。
方程式 1-7。 矩阵乘法 。
)
也就是说,每个元素Cij被计算为矩阵A
的行 I 和矩阵B
的列 j 的点积。等式 1-8 为 2x2 矩阵提供了一个例子。此外,清单 1-16 演示了如何在 TensorFlow 中执行矩阵乘法。
方程式 1-8。矩阵乘法示例。
)
我们首先从正态分布中随机抽取两个矩阵。矩阵A
的形状为(200,50),矩阵B
的形状为(50,10)。然后我们使用tf.matmul()
将A
乘以B
,将结果赋给C
,其形状为(200,10)。
如果我们将B
乘以A
会发生什么?从A
和B
的形状我们可以看出这是不可能的,因为B
的列数是 50,而A
的行数是 200。的确,矩阵乘法不是可换的,但它是结合律。 7
import tensorflow as tf
# Use normal distribution draws to generate tensors.
A = tf.random.normal([200, 50])
B = tf.random.normal([50, 10])
# Perform matrix multiplication.
C = tf.matmul(A, B)
# Print shape of C.
print(C.shape)
(200, 10)
Listing 1-16Perform matrix multiplication in TensorFlow
广播
在某些情况下,您可能想要利用广播,这涉及到使用两个形状不兼容的张量执行线性代数运算。当您想要将一个标量添加到一个张量,将一个标量乘以一个张量,或者执行批量乘法时,这种情况最常见。我们将考虑每一种情况。
标量张量加法和乘法
当处理图像数据时,通常对矩阵、3-张量和 4-张量应用标量变换。我们将从标量张量加法和标量张量乘法的定义开始。在这两种情况下,我们将假设我们有一个标量, γ ,和一个秩为 k 的张量, A 。等式 1-9 定义了标量张量加法,等式 1-10 定义了标量张量乘法。
方程式 1-9。 标量-张量加法 。
)
方程式 1-10。 标量-张量相乘 。
)
标量-张量相加是通过将标量项加到张量中的每个元素上来实现的。类似地,标量-张量乘法是通过将标量乘以张量中的每个元素来执行的。也就是说,我们对所有的 i 1 ∈ {1、…、 I 1 }、 i 2 ∈ {1、…、2}、…、 i 、k∈{ 1、…、I重复等式 1-9 和 1-10 中指定的操作清单 1-17 为形状为(64,256,256,3)的图像(称为图像)的 4-张量提供了标量张量加法和乘法的 TensorFlow 实现。
我们首先定义两个常量,gamma
和mu
,它们是我们将在加法和乘法运算中使用的标量。因为我们已经使用tf.constant()
定义了它们,所以我们可以使用重载操作符*
和+
,而不是tf.multiply()
和tf.add()
。我们现在已经将一批 64 个图像中的元素从[0,255]区间中的整数转换为[–1,1]区间中的实数。
import tensorflow as tf
# Define scalar term as a constant.
gamma = tf.constant(1/255.0)
mu = tf.constant(-0.50)
# Perform tensor-scalar multiplication.
images = gamma*images
# Perform tensor-scalar addition.
images = mu+images
Listing 1-17Perform scalar-tensor addition and multiplication
批量矩阵乘法
我们要考虑的广播的最后一个例子是批量矩阵乘法。考虑这样一种情况,我们有一批名为images
的形状为(64,256,256)的 3 张量灰度图像,并且想要对它们中的每一个应用名为transform
的形状为(256,256)的相同线性变换。为了便于说明,我们将对images
和transformation
使用随机生成的张量,它们在清单 1-18 中定义。
import tensorflow as tf
# Define random 3-tensor of images.
images = tf.random.uniform((64, 256, 256))
# Define random 2-tensor image transformation.
transform = tf.random.normal((256, 256))
Listing 1-18Define random tensors
清单 1-19 展示了我们如何使用我们定义的 3-张量和 2-张量在 TensorFlow 中执行批量矩阵乘法。
# Perform batch matrix multiplication.
batch_matmul = tf.matmul(images, transform)
# Perform batch elementwise multiplication.
batch_elementwise = tf.multiply(images, transform)
Listing 1-19Perform batch matrix multiplication
我们用tf.matmul()
进行批量矩阵乘法。也可以执行批量元素乘法,如清单 1-19 所示。
微分学
经济学和机器学习都大量使用微分学。在经济学中,微分学用于求解分析模型、估计计量经济学模型,以及求解被构造为微分方程系统的计算模型。在机器学习中,微分学通常用于应用于训练模型的例程中。随机梯度下降(SGD)及其许多变体依赖于梯度的计算,梯度是导数的向量。事实上,微分学在经济学和机器学习中的所有应用都是为了同一个目的:找到一个最优值——也就是最大值或最小值。在这一节,我们将讨论微分学,它在机器学习中的使用,以及它在 TensorFlow 中的实现。
一阶和二阶导数
微分学以导数的计算为中心。导数告诉我们一个变量 Y 随着另一个变量 X 的变化而变化。如果 X 和 Y 之间的关系是线性的,那么 Y 相对于 X 的导数就是一条直线的斜率,计算起来很繁琐。例如,考虑一个带有一个独立变量 β 的确定性线性模型,其形式为等式 1-11。
方程式 1-11。一个 带一个 回归量 的线性模型。
)
这个模型中 Y 相对于 X 的导数是多少?它是 Y ,δY的变化,相对于 X ,δX的变化。对于线性函数,我们可以使用两点( X 1 、 Y 1 )和( X 2 、 Y 2 )来计算,如等式 1-12 所示。
方程式 1-12。计算 Y 相对于 x 的变化。
)
)
将等式两边除以δX得到相对于 X 变化的 Y 变化的表达式。这只是导数 X ,如等式 1-13 所示。
方程式 1-13。Y 相对于 x 的导数
)
当然,这只是线性函数的斜率,如图 1-4 所示。请注意,我们选择的点并不重要。无论选择( X 1 、 Y 1 )还是( X 2 、 Y 2 ),导数(或斜率)总是相同的。这是线性函数的一个性质。
图 1-4
线性函数的斜率
但是如果我们是非线性关系呢?图 1-5 显示了两个此类功能的示例。我们可以看到,我们用来恢复 X 的导数的方法对于 X 2 或X2—X不太适用。
图 1-5
X 的非线性函数
为什么不呢?因为 X 2 和X2—X的斜率不是常数。X?? 的斜率在 X 中增加。X2—X的斜率开始下降,然后在 X 2 项开始占优势时上升。不管( X 1 、 Y 1 )和( X 2 、 Y 2 )的选择如何, Y 相对于 X 的导数总是在其计算的区间内变化。事实上,只有在一个点上计算,而不是在一个区间上计算,它才会是常数,这正是微分学告诉我们的。
等式 1-14 给出了一元任意一般函数的导数的定义, f ( X ),包括非线性函数。因为导数本身取决于我们在哪里对它求值,我们将使用函数f’(X)来表示它。
方程式 1-14。f(X)关于 X 的导数的定义
)
请注意这个定义和我们之前用于线性函数导数(斜率)的定义之间的相似性。我们可以看到δX=h和δY=f(X+h)f(X)。唯一改变的是增加了极限项,我们还没有定义。
非正式地说,极限告诉我们,当我们接近某个参数的某个值时,函数的行为如何。在这种情况下,我们缩小了计算导数的区间 h 。也就是说,我们正在将 X 1 和 X 2 移得更近。
在图 1-5 中,我们绘制的函数之一是 Y = X 2 。我们将把它代入方程 1-15 中对一般函数的导数的定义中。
方程式 1-15。一个导数的例子为 Y = X 2 。
)
)
)
当 h 接近 0 时,我们如何计算 2 X + h 的极限?由于我们不再有在 h = 0 处未定义的f’(X)的表达式,例如在分母中包含 h 的原始表达式,我们可以简单地将 h = 0 代入表达式,得到 2 X 。
我们学到了什么? Y = X 2 的导数是 2 X ,也是 X 的函数。你可能已经有了直觉,在 X 中X2 的斜率在增加。计算导数会精确地告诉你它增加了多少:也就是说, X 增加一个单位会使 f ( X )的斜率增加两个单位。此外,我们可以计算某一点的斜率。例如,在 X = 10 时,斜率为 20。
我们现在可以计算任意点的斜率,但是我们能做什么呢?让我们回到图 1-5 。这次我们来看函数f(X)=X2—X。我们可以看到图中的曲线在区间上是碗状的。在数学优化中,这样的函数被称为“凸的”,这意味着通过图上两点绘制的任意线段将总是位于图本身的上方或上面。
正如我们从等式 1-16 的导数以及图 1-5 中看到的,函数的斜率最初是负的,但随着我们在[0,1]区间内从 0 移动到 1,最终变为正的。导数由负变正的点是区间内 f ( X )的最小值。如图所示,函数的斜率在最小值为零。
方程式 1-16。Y = X2*-X .*的导数的例子
)
)
)
这暗示了导数的另一个重要性质:我们可以用它们来寻找函数的最小值。特别的,我们知道f’(X)= 0 最小值。我们可以利用这一点,如等式 1-17 所示,来确定可能是最小值的点,即“候选”最小值。
方程式 1-17。寻找候选最小值 Y = X2-X .
)
)
计算导数,将其设置为零,然后求解 X 得到最小值的候选值:0.5。为什么它只是一个候选最小值,而不仅仅是最小值?原因有二。首先,导数在最大值时也将为零。第二,可能有许多局部最小值和最大值。因此,它可能是[0,1]区间中的最小值,这将是一个“局部最小值”,但不清楚它是否是我们函数感兴趣的域中的最小值,它可能是实数。这样的最小值被称为“全局最小值”
由于前面的原因,我们称导数为零的要求为局部最优的一阶条件(FOC)。我们总是有一个在函数最小值处为零的导数,但是全局最大值和局部最优值也有一个为零的导数。因此,也可以说它是最小值的必要条件,但不是充分条件。
我们将利用所谓的二阶条件(SOC)来处理不足问题,这涉及到二阶导数的计算。到目前为止,我们已经计算了两个导数,都是“一阶导数”也就是说,它们是某个函数的导数。如果我们对这些导数求导,我们得到“二阶导数”,记为f′′(X)。正的二阶导数表明一个函数的导数在它被求值的点上是递增的。在等式 1-18 中,我们计算了Y=X2-X的二阶导数。
方程式 1-18。二阶导数的例子为 Y = X2-X .
)
在这种情况下,二阶导数是常数。也就是说,它总是 2,不管我们在哪里计算它。这意味着导数也在 X = 0.5 处增加,这是候选的局部最小值,我们已经证明导数为零。如果导数既是零又是递增的,那么它一定是局部最小值。这是因为我们在 X = 0.5 附近处于最低点,对于 X > 0.5,我们知道 f ( X )正在增加,因此不会产生低于 f (0.5)的值。
我们现在可以提供一个关于局部最小值的充分必要条件的正式陈述。即,如果等式 1-19 中的陈述为真,则候选局部最小值X∫满足作为局部最小值的必要和充分条件。
方程式 1-19。 局部最小值 的充要条件。
)
)
类似地,如果等式 1-20 中的陈述为真,则满足局部最大值的条件。
方程式 1-20。局部极大值的充要条件。
)
)
一般来说,我们可以通过最小化 overf(X)将最大化问题转化为最小化问题。为此,讨论函数的最小化就足够了。
我们现在已经讨论了一阶导数、二阶导数及其在优化中的应用,这主要是我们在经济学和机器学习中遇到它们的方式。在下一节中,我们将概述如何计算一个变量的常见函数的导数。
多项式的公共导数
在上一节中,我们介绍了一阶和二阶导数的概念。我们也给出了导数计算的例子,但是用一种相对不方便的方式进行计算。在每种情况下,我们都计算了 f ( X )相对于 X 的变化,因为 X 的变化在极限中变为零。对于我们考虑的两个例子,这很简单;然而,对于更复杂的表达式,这种方法可能会变得非常麻烦。此外,由于我们还没有正式引入极限的概念,当我们不能简单地计算表达式的极限值时,我们很可能会遇到问题。
幸运的是,衍生品采取可预测的形式,这使得使用简单的规则计算它们成为可能,而不是评估限制。你们可能已经注意到了一些这样的规则,它们适用于我们之前计算的导数。回想一下,我们取了四个导数(一阶和二阶),它们在方程 1-21 中给出。
方程式 1-21。导数的例子。
)
)
)
)
方程 1-21 中函数与导数之间有哪些常见的关系?第一个叫做幂律:f(X)=Xn→f’(X)=nXn—1。我们可以看到这一点,比如下面这个变换:f(X)=X2→f’(X)= 2X。另一个是乘法法则。也就是说,如果我们有一个变量的乘幂,乘以一个常数,那么导数就是这个变量的乘幂的导数,乘以常数:f(X)= 2X→f’(X)= 2。我们还可以看到多项式的每一项都是独立微分的:f(X)=X2-X→f’(X)= 2X-1。这是微分线性的结果,被称为和或差法则,取决于它是加法还是减法。
为了简洁起见,我们将在表 1-1 中列出一元多项式导数的规则。请注意,有几种不同形式的符号可用于区分。到目前为止,我们已经使用了f’(X)来表示我们正在对 f ( X )关于 X 求导,我们也可以将微分表示为 df / dx 。而如果我们有一个表达式,比如X2—X,我们可以用d/dx X2—X来表示它的导数。出于表格的目的,我们将使用 f ( X )和 g ( X )来表示变量 X 和 c 的两个不同的函数来表示一个常数项。
表 1-1
多项式的微分规则
| 常数法则 |  | | 乘法法则 |  | | 权力规则 |  | | 求和规则 |  | | 乘积规则 |  | | 链式法则 |  | | 互惠法则 |  | | 商数法则 |  |记住前面的规则将使你能够计算单个变量的几乎任何函数的解析导数。然而,在某些情况下,函数将是超越的,这意味着它不能用代数来表示。在下一节中,我们将考虑这些情况。
超越函数
对多项式求导最初看起来令人生畏且麻烦,但最终归结为记住八个简单的规则。超越函数也是如此,比如 sin(X),不能用代数表示。表 1-2 提供了我们会经常遇到的四个超越函数的规则。
表 1-2
超越函数的微分规则
| 指数法则 |  | | 自然对数规则 |  | | 正弦规则 |  | | 余弦规则 |  |请注意,到目前为止,我们所做的所有微分都是针对单变量函数的,这种函数有时被称为“单变量”函数。无论是机器学习还是经济学,我们都很少会遇到单个变量的问题。在下一节中,我们将讨论将单变量微分规则扩展到机器学习中通常会遇到的多变量对象。
多维导数
你可能想知道,在经济学和机器学习中,什么才算“变量”。答案是,这取决于所考虑的问题。当我们通过使用最小化误差平方和的 OLS 来解决回归问题时,变量将是回归系数,输入数据可以被视为常数。同样,当我们训练一个神经网络时,网络中的权重将是变量,数据将是常数。
不难看出,我们在经济学和机器学习中遇到的几乎所有问题本质上都是多元的。求解模型、估计回归方程和训练神经网络都需要找到使目标函数最小化或最大化的一组变量值。在这一节中,我们将讨论在做这件事时会遇到的一些多元对象。
梯度
梯度是导数概念的多元扩展。我们需要导数的多元扩展,因为我们遇到的大多数问题都有很多变量。举个例子,我们想估计一个经济计量模型。我们将通过最小化一些损失函数来做到这一点,损失函数通常是变量(模型参数)和常数(数据)的变换。设 L ( X 1 ,…, X n )表示损失函数, X 1 ,…, X n 表示感兴趣的 n 参数值。在此设置中,梯度,记为∇l(x1,…, X n ),被定义为一个向量值函数,以 X 1 ,…, X n 为输入,输出一个向量
方程式 1-22。n 变量损失函数的梯度。
)
注意,我们使用符号∂l/∂xI来表示 L 相对于 X i 的“偏导数”。也就是说,我们对 L 相对于 X i 求导,将所有其他变量视为常数。计算梯度无异于计算损失函数的所有偏导数,然后将它们叠加到一个向量中。
我们在经济学和机器学习中特别重视梯度的原因是因为它在许多优化例程中被采用。随机梯度下降(SGD)等算法包括以下与梯度相关的步骤:
-
计算损失函数的梯度,∇l(x1,…, X n )。
-
更新变量的值,xj=xj—1—α∇l(x1,…, X n )。
在前面的步骤中, X j 是迭代次数, α 是“步长”重复该例程,直到收敛:即,直到我们到达一个 j ,其中∣xjxxj1∣小于某个容差参数。如果我们希望缓慢移动以避免超过最优值,我们可以将 α 设置为一个小数值。
为什么这样的算法行得通?考虑一个我们有清晰直觉的可变情况。要有一个候选最小值,导数必须为零。我们可以从随机抽取的变量值开始,计算该点的导数,从而找到导数为零的点。如果它是负的,我们向前迈进,也就是说,增加 X 的值,因为这将使损失函数更负。如果它是正的,我们减少 X ,因为它也将降低损失函数。在某一点上,当我们接近最小值时,梯度的大小将开始下降,向零移动。如果我们足够缓慢地接近它,接近零的梯度将导致对 X j 的非常小的更新,直到它们小到不超过容差,从而终止算法。
一般来说,当我们使用基于梯度的优化方法时,我们会将这些步骤背后的直觉扩展到数百、数千甚至数百万个变量。
数学家雅可比的理论的
雅可比矩阵将梯度的概念扩展到一个由 n 个变量和 m 个函数组成的系统。雅可比矩阵的定义在等式 1-23 中给出。
方程式 1-23。n 元 m 函数的雅可比矩阵。
)
为了使这一点具体化,让我们计算两个函数和两个变量的雅可比,它们在等式 1-24 中给出。
方程式 1-24。一个 两个函数两个变量的系统。
)
)
回想一下我们之前说过的关于计算偏导数的内容:除了我们要微分的变量之外,所有其他变量都可以被视为常数。例如,如果我们要计算∂f1/∂x1,那么我们可以将 X 2 视为常数。方程 1-25 给出了该系统的雅可比矩阵。
方程式 1-25。2x2 系统的雅可比矩阵示例。
)
当解方程组或优化向量值函数时,雅可比矩阵将被证明是有用的。例如,在机器学习中,具有分类目标变量的神经网络可以被视为向量值函数,因为网络输出每个类别的预测值。为了训练这样的网络,我们将应用利用雅可比矩阵的优化算法。
打包麻布
我们之前讨论了一阶和二阶导数及其在优化中的作用。我们已经把一阶导数的概念扩展到梯度和雅可比矩阵。我们还将把二阶导数的概念扩展到多变量的标量值函数。我们将把所有这样的导数排列成一个称为海森矩阵的矩阵,它在方程 1-26 中给出。
方程式 1-26。 海森矩阵 为一个 n 变量函数。
)
关于黑森有两件事值得注意。首先,它是在标量值函数上计算的,类似于梯度。第二,它由二阶偏导数组成。在使用的符号中,)是对 X * i * 的二阶偏导数,而不是对
)的偏导数。
最后,让我们考虑一个二元函数的 Hessian。这个函数在方程 1-27 中给出,然后在方程 1-28 中给出它的 Hessian 值。
方程式 1-27。海森矩阵计算的示例函数。
)
方程式 1-28。二元函数的 Hessian 矩阵。
)
在实践中,我们会在机器学习的两个地方遇到 Hessian 矩阵。首先是检查最优性条件。这需要一些矩阵性质的额外知识,所以我们将对此说得相对较少。另一种使用 Hessians 的方式是用优化算法训练模型。在某些情况下,这种算法会要求我们使用一阶和二阶导数来近似一个函数。海森矩阵将是组织二阶导数的有用结构。
TensorFlow 中的微分
TensorFlow 使用一种叫做“自动微分”的东西来计算导数(Abadi 等人,2015)。这是一种既不是纯符号也不是纯数字的微分形式,在训练深度学习模型的背景下特别有效。在这一节中,我们将讨论自动微分的概念,并解释它与符号微分和数值微分有何不同。然后我们将演示如何在 TensorFlow 中计算导数。重要的是,虽然 TensorFlow 确实有这个功能,但大多数非研究应用程序不会要求用户显式编程导数的计算。
自动微分
假设你要计算 f ( g ( x ))的导数,其中f(y)= 5y2和g(x)=x3。从上一节你知道,这可以用链式法则来实现,如方程式 1-29 所示。
方程式 1-29。 链式法则 的例子。
)
方程 1-29 所示的叫做“符号”微分。这里,我们手动或通过计算进行微分,最终得到导数的精确代数表达式。
虽然对导数的整洁、精确的表达确保了高效和精确的计算,但是计算符号导数可能是相当具有挑战性的。首先,如果我们手动完成,这个过程很可能既耗时又容易出错,尤其是对于具有数百万个参数的神经网络。第二,如果我们通过计算来做,我们很可能会遇到高阶导数表达式的复杂性和没有闭合形式表达式的导数的计算的问题。
在经济学中,数值微分通常被用作符号微分的替代方法,它依赖于我们最初的基于极限的导数定义,并在等式 1-30 中给出。 8
方程式 1-30。用向前差分法定义数值导数。
)
事实上,有几种方法可以做到这一点。我们在等式 1-30 中使用的方法被称为“向前差分”方法,因为我们计算在 x 处评估的函数与大于 x 的某个值之间的差,即 x + h 。我们可以看到转向数值微分的两个直接影响。首先,我们不再计算导数的精确代数表达式。事实上,我们甚至没有尝试去做。相反,我们只是在不同的点上评估函数。第二, h 的大小将决定我们对f’(x)的近似的质量。
等式 1-31 显示了在我们用于符号微分的例子中导数是如何计算的。
方程式 1-31。使用前向差分法的数值导数示例。
)
相比之下,自动微分既不是完全符号化的,也不是完全数值化的。相对于数值微分,它的优点是提高了精度。在深度学习设置中,它也比数值微分更稳定,在深度学习设置中,模型通常有数千甚至数百万个参数。此外,它不受符号微分的要求,为导数提供一个单一的表达式。这将再次证明在深度学习设置中特别有用,其中我们必须计算损失函数相对于嵌套在函数序列深处的参数的导数。
自动微分如何改善这个过程?首先,它将导数的符号计算划分为基本部分。第二,它在单个点上计算导数,向前或向后扫描整个偏导数链。
我们再来重温一下嵌套函数的例子,这里f(y)= 5y2 和g(x)=x3,这里我们要计算d/DXF(g(x我们可以通过有限差分来使用数值微分,或者使用符号微分来计算导数的单个表达式,但是让我们尝试使用自动微分来代替。**
我们将从把计算分解成基本部分开始。在这种情况下,他们是 x 、 y 、 ∂f / ∂y 、 ∂y / ∂x 。然后我们用符号计算偏导数的表达式。即∂f/∂y= 10y和∂y/∂x= 3x2。接下来我们构造偏导数的链条,简单来说就是∂f/∂y∫∂y/∂x。链式法则告诉我们,这是 ∂f / ∂x 。我们不是象征性地执行乘法运算,而是用数字方式遍历整个链。
我们将通过设置 x = 2 从 ∂y / ∂x 开始,因为我们必须在一个点执行自动微分。这立即产生了 ∂y / ∂x = 12 和 y = 8。我们现在可以遍历这个链,插入 y = 8 得到 ∂f / ∂y = 80。这允许我们通过简单地乘以偏导数链来计算 ∂f / ∂x ,得到 960。
在这种情况下,我们已经通过从前面(输入值)到后面(输出值)的移动扫过了偏导数链。对于神经网络,我们将做完全相反的事情:我们将在反向传播步骤中反向移动。
虽然我们不需要自己实现自动微分算法,但了解它们的工作原理会让您对 TensorFlow 的工作原理有更好的理解。有关自动微分的文献综述,请参见 Baydin 等人(2018)。
TensorFlow 中的导数计算
在本节的前面,我们使用了一个嵌套函数的例子,并演示了如何使用自动微分来计算它。让我们在 TensorFlow 中做同样的事情,并验证我们的手动计算是正确的。清单 1-20 将提供详细信息。
像往常一样,我们首先在别名tf
下导入tensorflow
。接下来,为了与本节前面的例子相匹配,我们将x
定义为一个等于 2 的tf.constant()
对象。然后,我们在渐变磁带实例的上下文中定义嵌套函数f(g(x))。我们首先对x
应用watch()
方法,以指示GradientTape()
应该记录x
发生的事情。默认情况下,不会,因为x
是一个常量。注意,为了简单起见,我们可以将x
定义为一个tf.Variable()
对象;然而,对于这个问题,我们一直将x
视为输入,因此它将被定义为常数。
import tensorflow as tf
# Define x as a constant.
x = tf.constant(2.0)
# Define f(g(x)) within an instance of gradient tape.
with tf.GradientTape() as t:
t.watch(x)
y = x**3
f = 5*y**2
# Compute gradient of f with respect to x.
df_dx = t.gradient(f, x)
print(df_dx.numpy())
960.0
Listing 1-20Compute a derivative in TensorFlow
最后,我们应用GradientTape()
的gradient()
方法来区分f
和x
。然后我们打印结果,应用numpy()
方法提取值。同样,我们发现它是 960,与我们之前手动执行的自动微分相匹配。
TensorFlow 的自动微分方法从根本上不同于经济学中的标准计算包,后者通常提供导数的数值或符号计算,但不提供自动微分。这将为我们在求解理论经济模型时提供优势。
加载在 TensorFlow 中使用的数据
在本章中,我们介绍了 TensorFlow,讨论了版本 1 和版本 2 之间的差异,并提供了初步主题的扩展概述。我们将通过解释如何在 TensorFlow 中加载数据来结束本章。如果您熟悉 TensorFlow 1,您可能还记得静态图形需要将所有固定输入数据导入或转换为tf.constant()
。否则,数据将不会包含在计算图中。
由于 TensorFlow 2 默认使用急切执行,因此不再需要在静态计算图的限制内工作。这意味着您现在可以直接使用numpy
数组,而无需先将它们转换成tf.constant()
对象。这也意味着我们可以在numpy
和pandas
使用标准的数据导入和预处理流水线。
清单 1-21 为神经网络的 4 阶图像张量输入提供了加载和预处理流水线。我们将假设张量已经以npy
格式存储,它可以用来保存任意的numpy
数组。
注意,我们通过将张量的每个元素除以 255 来变换张量。这是图像数据的常见预处理步骤,如果以红绿蓝(RGB)格式给出,图像数据由 0 到 255 之间的整数的秩 3 张量组成。最后,我们打印形状,产生(32,64,64,3),这表明我们在张量中有一批 32 个形状(64,64,3)的图像。
注意,预处理步骤是使用numpy
执行的。如果我们想用 TensorFlow 来执行呢?我们可以使用清单 1-22 或清单 1-23 中的方法来做到这一点。清单 1-23 在执行除法之前将images
转换成一个tf.constant()
对象。由于分割中涉及的对象之一是 TensorFlow 对象,因此将使用 TensorFlow 执行该操作。
import numpy as np
# Import image data using numpy.
images = np.load('images.npy')
# Normalize pixel values to [0,1] interval.
images = images / 255.0
# Print the tensor shape.
print(images.shape)
(32, 64, 64, 3)
Listing 1-21Import image data with numpy
相比之下,清单 1-23 中的方法明确利用了 TensorFlow 运算tf.division()
,而不是用除法符号/
重载运算。这是必要的,因为images
和255.0
都不是 TensorFlow 对象。因为我们没有使用静态图,所以我们没有必要指定这一点。然而,如果我们不小心,我们将最终使用numpy
执行操作,而不是 TensorFlow。
在许多情况下,我们会希望加载平面格式的数据,比如一个特性表,它可能存储在一个csv
文件中。如清单 1-24 所示,我们可以使用pandas
中的read_csv()
函数来实现。然而,在我们可以在 TensorFlow 操作中使用数据之前,我们必须首先将它转换成一个numpy
数组或一个tf.constant()
对象。
import tensorflow as tf
# Import image data using numpy.
images = np.load('images.npy')
# Normalize pixel values to [0,1] interval.
images = tf.division(images, 255.0)
Listing 1-23Perform division in TensorFlow using the division operation
import tensorflow as tf
# Import image data using numpy.
images = np.load('images.npy')
# Convert the numpy array into a TensorFlow constant.
images = tf.constant(images)
# Normalize pixel values to [0,1] interval.
images = images / 255.0
Listing 1-22Perform division in TensorFlow using constant tensors
重申一下,关于在 TensorFlow 中加载数据需要记住两件事。首先,您可以使用任何您喜欢的模块来加载数据,包括numpy
和pandas
。TensorFlow 还提供了导入数据的功能。第二,一旦数据被导入,它必须被转换成一个numpy
数组或一个 TensorFlow 对象,比如一个常量或变量,然后才能在 TensorFlow 操作中包含它。此外,如果您更喜欢使用运算符重载,比如除法符号,而不是tf.division()
,那么至少有一个对象必须是 TensorFlow 张量。
import pandas as pd
# Import data using pandas.
data = np.load('data.csv')
# Convert data to a TensorFlow constant.
data_tensorflow = tf.constant(data)
# Convert data to a numpy array.
data_numpy = np.array(data)
Listing 1-24Load data in pandas for use in TensorFlow
摘要
本章对 TensorFlow 2 进行了广泛的介绍,不仅涵盖了 TensorFlow 本身的基础知识,包括如何加载和准备数据,还对机器学习算法中常用的微积分和线性代数运算进行了数学描述。我们还解释了 TensorFlow 是将机器学习例程应用于经济问题的有用工具,也可用于解决理论经济模型,这使其成为经济学家的理想选择。此外,我们还讨论了它如何提供高水平的灵活性、分布式培训选项和有用扩展的深度库。
文献学
Abadi,m .等人,2015 年。"TensorFlow:异构分布式系统上的大规模机器学习."初步白皮书。
艾希,S. 2019。“机器学习对经济学的影响。”Joshua gans 和 Avi Goldfarb Ajay Agrawal 在《人工智能经济学:议程》中写道。芝加哥大学出版社。
Baydin、a . g . b . a . pearl mutter、A.A. Radul 和 J.M. Siskind。2018."机器学习中的自动微分:综述."机器学习研究杂志18(153):1–43。
古德费勒,我,y .本吉奥,和 a .库维尔。2016.*深度学习。*麻省理工出版社。
贾德法学会,1998 年。经济学中的数值方法。马萨诸塞州剑桥:麻省理工学院出版社。
Perrault、Y. Shoham、E. Brynjolfsson、J. Clark、J. Etchemendy、B. Grosz、T. Lyons、J. Manyika、S. Mishra 和 J.C. Niebles。2019.*AI 指数 2019 年度报告。*人工智能指数指导委员会,以人为中心的人工智能研究所,加利福尼亚州斯坦福:斯坦福大学。
谷歌大脑团队通过谷歌人工智能博客上的一篇文章介绍了渴望执行: https://ai.googleblog.com/2017/10/eager-execution-imperative-define-by.html
。
2
有关 TensorFlow 1 过渡到 TensorFlow 2 的命名空间设计决策的概述,请参见 < RefSource > https://github.com/tensorflow/community/blob/master/rfcs/20180827-api-names.md
。
3
如果您在 Jupyter 笔记本中连续运行本章中的清单,您可以通过在单独的 Python 会话中执行清单来避免运行时错误。特别是,您可能希望在运行tf.estimator
列表后启动新的会话。
4
正如我们将在本章后面讨论的,这个规则有两种例外:广播和标量张量加法。
5
设 A,B,C 为秩- k 张量。交换律表述为 A + B = B + A,结合律表述为(A + B) + C = A + (B + C)。
6
我们在使用 tf.tensordot()时指定一个axes
argument 的原因是,我们实际上是在执行一个称为“张量收缩”的操作,它比点积更通用。张量收缩采用两个任意秩的张量 A 和 B,以及 A 和 B 中的维度索引 I 和 j。然后,它通过在指定维度上执行元素乘法来收缩 A 和 B,然后对乘积求和。
7
假设我们有三个矩阵:X、Y 和 z。矩阵的形状是这样的,XY 定义,YZ 定义。通常不会出现 XY = YX 和 YX 不可定义的情况。然而,情况是(XY)Z = X(YZ)。
8
参见 Judd (1998)对数值微分方法的全面概述。
二、机器学习和经济学
机器学习主要面向预测,而经济学的大部分内容都与因果关系和平衡有关。虽然这两个学科在预测方面有着共同的兴趣,但他们往往以不同的偏好和目标来对待它。经济学学科倾向于支持可解释的、简洁的和稳定的预测模型,而机器学习使用经验过程来确定模型中包含的内容,优先考虑特征选择、正则化和测试而不是直觉。
由于这些看似难以解决的差异,经济学学科最初在采用机器学习方法方面进展缓慢。从那时起,经济学可以从整合机器学习的模型、方法和惯例中受益,这一点变得越来越明显。在这一章中,我们将考察那些主张将机器学习的元素引入经济学和金融学的工作。这项研究不仅确定了机器学习可以在哪里有效地用于解决经济学问题,还确定了这两个学科之间不太可能协调的真正冲突。
虽然这本书围绕使用 TensorFlow 构建、训练和测试模型展开,但本章有一个不同的目标:建立对经济学和机器学习之间关系的强有力的概念性理解。我们将通过浏览经济学和金融学中讨论机器学习及其在学科中的作用的里程碑式论文来做到这一点。
“大数据:计量经济学的新招”(瓦里安,2014 年)
瓦里安(2014)在一篇题为“大数据:计量经济学的新招”的论文中,最早尝试将机器学习方法引入经济学家他认为,经济学家可以从更好地理解 ML 的不确定性建模和验证方法中受益。
他指出,经济学家通常使用被认为是“真实”的单一模型,而机器学习科学家通常对许多小模型进行平均。关于验证,他解释了如何使用机器学习方法进行交叉验证。例如,图 2-1 中描述的 k-fold 交叉验证将数据集分成 k 个大小相等的折叠或子集。然后,它在每个 k 训练迭代中使用不同的折叠作为验证集。他认为 k 倍验证和其他 ML 交叉验证技术可以为拟合优度测量提供一种替代方法,如计量经济学中常用的 R 2 。
除了高层次的见解,Varian (2014)还讨论了机器学习中可以在计量经济学中使用的常用方法。这包括使用分类和回归树;随机森林;变量选择技术,如套索和钉板回归;以及用于将模型组合成集成的方法,例如打包、提升和引导。
Varian (2014)还提供了一些机器学习如何用于经济学的具体例子。他利用《住房抵押贷款披露法案》( HMDA)的数据,运用基于树的估计方法来衡量种族歧视对抵押贷款决策的影响。他认为,这种估计可以为经济学中更常用的二元分类方法(如 logit 和 probit 模型)提供一种替代方法。
瓦里安还使用了整合了特征选择的模型,包括套索、长钉和平板,来检验经济增长的不同决定因素的重要性。他使用了一个由 72 个国家和 42 个潜在增长决定因素组成的数据集,该数据集最初由 Sala-i-Martín (1997 年)提出。
图 2-1
k = 5 时的 k 倍交叉验证图
“预测政策问题”(Kleinberg 等人,2015 年)
Kleinberg 等人(2015)讨论了“预测政策问题”的概念,其中准确预测的产生比因果推断评估更重要。他们认为,围绕生成准确预测而组织的机器学习在这种应用中比传统的计量经济学方法更具优势。
Kleinberg 等人(2015 年)对两种类型的政策问题进行了说明性的比较。在第一种情况下,决策者面临干旱,正在决定是否使用一种技术,如人工降雨,来增加降雨量。在第二个例子中,一个人正在决定是否带着雨伞去上班,以避免下雨时被淋湿。在第一种情况下,决策者关心的是因果关系,因为政策的有效性将取决于播云是否会导致降雨。在第二种情况下,个人只关心预测下雨的可能性,对因果推断不感兴趣。在这两种情况下,降雨的强度都会影响相关的政策结果。
作者在等式 2-1 中概括了政策预测问题。
方程式 2-1。预测政策问题。
)
这里, π 是收益函数,X0 是采取的政策, Y 是结果变量。在雨伞选择例子中, π 是人上下班后淋湿的程度, Y 是下雨的强度,X0 是采取的政策(有没有雨伞)。在干旱的例子中, π 衡量干旱的影响, Y 是下雨的强度,X0 是采取的政策(是否播云)。
如果我们选择雨伞作为我们的政策选项,那么我们知道∂y/∂x0= 0,因为雨伞不能阻止雨落下。这就把问题归结为对 ∂π / ∂X 0 和 y 的一个评价,即伞对支付函数和降雨强度的影响。由于雨伞对防止潮湿的影响是已知的,我们只需要预测 Y 。因此,政策问题本身就变成了预测问题。
请注意,在干旱的例子中情况并非如此,我们试图通过使用人工降雨来增加降雨量。这里要估计一下方法本身对降雨量的影响, ∂Y / ∂X 0 。这两种情况在因果图中有所说明,如图 2-2 所示。
图 2-2
Kleinberg 等人(2017 年)的政策预测问题图解
Kleinberg 等人(2015)认为,重要的政策问题有时可以通过预测 Y 本身来解决,而不是进行因果推断。这开启了经济学中一个机器学习特别适合解决的子领域。这对包括公共和私营部门经济学家在内的从业者也有有益的启示:确定政策可以完全通过预测来确定的问题,允许你使用现成的 ML 技术,而无需进一步修改。 1
“机器学习:一种应用的计量经济学方法”(Mullainathan 和 Spiess,2017 年)
Mullainathan 和 Spiess (2017)研究了监督机器学习方法如何应用于经济学。他们认为,经济学中的问题通常围绕着恢复模型参数的估计,yˇ,而机器学习中的问题通常围绕着恢复拟合值或模型预测,yˇ。
虽然这种差异最初看起来微不足道,但由于两个原因,它变得非常重要。首先,它导致模型建立和估计的不同方向,这通常导致机器学习中不一致的参数估计。也就是说,随着样本规模的增长,在机器学习模型中,参数估计值和不一定以概率收敛到真实的参数值和。第二,通常很难或不可能为机器学习模型中的任何单个参数构建标准误差。
尽管存在这些实质性的差异,但 Mullainathan 和 Spiess (2017)认为,只要经济学家利用机器学习的优势,机器学习仍然对经济学有用。也就是说,他们认为经济学家应该考虑预测本身很重要的任务,而不是使用机器学习来进行参数估计和假设检验。他们为经济学家指出了三种这样的情况:
图 2-3
使用 ML 说明工具变量回归
-
测量经济活动:这可以通过使用图像或文本数据集来完成。模型参数不需要一致地估计,只要模型返回经济活动的准确预测。
-
具有预测步骤的推理任务:某些推理任务,如工具变量(IV)回归,涉及生成拟合值的中间步骤。由于参数估计中的偏差来自中间步骤中的过拟合,利用机器学习技术,如正则化,可以减少 IV 估计中的偏差。图 2-3 说明了我们有一个感兴趣的回归变量 X 的情况;一个混杂因素,C;一个因变量,Y;还有一套仪器, Z 。然后,我们使用 ML 将 Z 转换为 X 的拟合值。
-
政策应用:经济学中政策工作的最终目标是为决策者提供建议。例如,一所学校可能正在决定是否雇用一名额外的教师,或者一个刑事司法系统可能正在决定何时保释那些被逮捕的人。提出建议最终包括做出预测。机器学习模型比简单的线性模型更适合这项任务。
Mullainathan 和 Spiess (2017 年)还在论文中进行了一项实证应用,以评估机器学习在提高拟合度方面的有效性。这项练习包括从美国住房调查中抽取的 10,000 个随机样本中预测房价的自然对数。他们利用 150 个特征,并用 R 2 来评估结果。通过比较 OLS、回归树、套索回归、随机森林和模型集合,他们发现,总的来说,最大似然法比 OLS 法在 R 2 上有所改进。此外,这些改善存在异质性:对于某些五分位数的房价,收益很大,而其他五分位数的收益很小,甚至是负数。
最后,Mullainathan 和 Spiess (2017)认为,ML 在两个额外的维度上为经济学提供了附加值。首先,它提供了用于估计或训练模型的替代过程,该过程以正则化为中心,以防止基于经验反馈的过拟合和调整。第二,它可以用来测试关于可预测性的理论。例如,有效市场假说(EMH)暗示,经风险调整的超额回报不应该是可预测的。因此,使用最大似然模型来证明可预测性对理论有影响,即使预测中使用的所有参数都是不一致的估计。
“机器学习对经济学的影响”(Athey 2019)
与 Mullainathan 和 Spiess (2017)类似,Athey (2019)回顾了机器学习对经济学的影响,并对未来可能的发展进行了预测。她的工作集中在机器学习和传统计量经济学方法之间的比较,对经济学中使用的现成机器学习例程的评估,以及对 Kleinberg 等人(2015)中讨论的各种政策预测问题的评论。
机器学习和传统计量经济学方法
Athey (2019)认为,机器学习工具不适合进行因果推断,而因果推断是大多数计量经济学练习的目标。然而,它们对于改进半参数方法是有用的,并使研究人员能够利用大量的协变量。鉴于计量经济学模型的简约和“大数据”的日益可用性,采用机器学习的方法和模型似乎有很大的价值,因为机器学习通常更适合处理和建模大量数据。
Athey 指出的另一个优势是灵活函数形式的使用。计量经济学文献广泛地围绕着为一个单一的狭窄任务生产工具:在线性回归模型中进行因果推断。然而,在许多情况下,有充分的理由相信这种模型无法捕捉重要的非线性。机器学习提供了丰富多样的模型,允许特征之间以及特征和目标之间的非线性,这通常是计量经济学模型所缺乏的。
除了因果推断,Athey 还比较了执行经验分析、选择模型和计算参数值置信区间的过程。她得出的关于机器学习的结论将在下面的小节中介绍。
经验分析
Athey (2019)强调了经济学和机器学习之间的一个重要对比,这在他们对实证分析的不同方法中最为明显。经济学家通常使用一些原则来选择模型,并通过使用理论来确定其函数形式。然后,他们对模型进行一次评估。
机器学习采用不同的方法进行实证分析——即迭代方法。机器学习不是从由原理和理论确定的模型开始,而是从标准的模型架构和/或一组超参数开始。然后,它训练模型,使用交叉验证的形式评估性能,然后调整超参数和模型架构以提高性能。然后重复训练过程。
艾希认为,调整和交叉验证是机器学习提供给计量经济学家的一些最有用的工具。围绕一个迭代和实证过程重新定位经济学中的实证分析可能会导致在解释数据变化方面的实质性改进。
型号选择
虽然 Athey (2019)认为机器学习中的经验调整过程可以为经济学中的某些应用提供好处,但她也警告说,它不太可能有助于因果推理。这是因为机器学习应用通常涉及性能评估简单且可测量的情况。例如,在机器学习中,我们可能想要验证样本的高准确率,或者我们可能想要低均方误差。事实上,当我们在经济学中估计回归模型时,我们当然也在最小化一些损失函数,例如误差平方和。我们还可以查看性能指标,例如样本外预测误差的度量,如图 2-4 所示。
图 2-4
机器学习中模型评估过程的说明
然而,我们不能做的是测量“因果关系”,并训练我们的模型使其最大化。这是一个严峻的挑战,无论我们是使用计量经济学工具还是机器学习工具;然而,为机器学习工具指出这一点尤为重要,因为这是一个相信它们不会帮助我们沿着因果维度改进的理由。
置信区间
在经济学中使用机器学习方法的一个缺点是,这种模型通常不会产生有效的置信区间。事实上,置信区间通常不是机器学习感兴趣的对象,因为模型通常包含数千个参数。Athey (2019)认为,这对经济学研究来说是一个挑战,经济学研究通常涉及以单个参数的统计意义为中心的假设检验。然而,在某些情况下克服这种限制是可能的,但它需要使用先进的、最近开发的经济学和统计学方法,这些方法通常不能用现成的 ML 程序获得。
现成的 ML 程序
Athey (2019)评估了一组广泛的现成例程,以考虑它们在应用于经济和金融任务时的表现。她认为,无监督的机器学习方法,如聚类算法和主题建模,可以在经济学中发挥有价值的作用。它们的好处是不会产生虚假的关系,因为没有因变量,而且它们本身可以用来产生因变量。
然后,她评估有监督的机器学习方法,根据它们在社会科学中的广泛采用对这些方法进行分类。例如,神经网络在过去已经被用于社会科学的各种应用中,但是直到最近才被广泛使用和接受。因此,Athey (2019)将此类模型归类为“机器学习模型”举例来说,OLS 或罗吉模型就不一样了,它们长期以来被用于经济学和金融学。
Athey (2019)确定了以下模型,这些模型可以被归类为该方案下的“机器学习模型”:正则化回归,包括 LASSO、ridge 和 elastic net 随机森林和回归树;支持向量机(SVM)模型;神经网络;和矩阵平均。
正如 Mullainathan 和 Spiess (2017 年)最初提出的那样,使用这种模型的标准权衡是表现力与过拟合。使用更多的特性,允许更灵活的函数形式,以及减少正则化损失,都是以更高的过拟合概率为代价的。
Athey 认为这种方法在有大量协变量的环境中有很多优势。然而,有必要使用非标准程序来计算置信区间。评估结果是否虚假也很重要。
政策分析
除了因果推理,经济学还关心预测本身。例如,一个精确的经济预测模型对于规划仍然是有用的,即使这种准确性是由变量之间的非因果关系引起的。正如之前在 Kleinberg 等人(2015)的综述中所讨论的,这一概念也适用于政策问题。试图决定是否采取特定行动的政府和组织通常会在两种不同的情况下这样做。在第一种情况下,他们将采取的政策的效力是不确定的。第二,不确定性是关于一些外部事件。
例如,考虑一家小银行决定是否建立更大的资本缓冲以应对金融危机。他们可能会构建一个模型,根据世界的状态来指示缓冲区的目标大小。这将涉及构建和评估一个产生政策预测的模型。重要的是,因果关系在这个模型中是不相关的,因为小银行不会在任何明显的程度上影响金融部门的状态。相反,它只需要能够提前预测危机,以便采取正确的政策。
Athey (2019)对相关的政策预测问题文献进行了回顾。她认为,在这些文献中,有几个感兴趣的主题对于经济学家的评估仍然至关重要:
-
模型可解释性:经济模型趋向于简单和可解释,使得政策处方的起源可以理解。很多 ML 车型都不是这样。
-
公平和非歧视:机器学习模型的复杂性往往使得难以确定不公平或歧视性政策处方的来源。因此,过渡到 ML 模式将需要评估如何保持公平性和非歧视性。
-
稳定性:鉴于机器学习模型的复杂性,尚不清楚为一个群体估计的关系是否会对其他群体适用。还需要做更多的工作来评估结果的可推广性。
-
可操作性:ML 模型的规模和复杂性,以及它们较低的可解释性,为操作提供了可能性。这已经是经济模型中的一个问题,但它因许多 ML 模型的复杂性和黑箱性质而变得更加复杂。
这些仍然是有趣的研究课题,也是从业者重要的考虑因素。公共和私营部门的经济学家都需要评估在经济学中使用 ML 模型所产生的预测的可解释性、公平性、稳定性和可操作性。
积极的研究和预测
Athey (2019)总结了经济学中 ML 研究的活跃路线,以及对未来的预测。感兴趣的读者应该参考手稿本身了解详情。然而,我们将强调一些积极研究的领域和对未来发展的预测。
活跃的研究领域包括(1)使用最大似然估计平均治疗效果,【2】(2)估计异质治疗效果下的最优策略, 3 (3)使用最大似然进行补充分析,评估因果推断中混杂问题的程度,4(4)在面板和差异中差异方法中使用最大似然。 5
a 他们包括了一个广泛的预测列表,预测最大似然法在经济学中的采用和传播,从增加使用现成的方法开始,这些方法最初在最大似然法中用于它们的预期目的。从那里,ML 很可能被本地化,以执行经济学家和社会科学家特别感兴趣的任务。她预测,对经济学中因果推理的影响将会很小,但总体影响将会很大,这需要增加跨学科工作,与私营企业协调,并复兴专注于经济计量的陈旧文献。
“经济学家应该知道的机器学习方法”(Athey 和 Imbens 2019)
另外,Athey 和 Imbens 通过多项工作为经济学中机器学习方法的进步做出了重大贡献。在 Athey 和 Imbens (2019)中,他们概述了对经济学家有用的机器学习方法。
他们首先讨论了 ML 与经济学的结合,它最初面临的阻力,以及这些阻力背后的原因。最初最严重的反对意见是 ML 模型不能产生有效的现成置信区间。虽然对最大似然法本身并不重要,但这是在传统经济学问题中使用最大似然法的一个实质性障碍。
Athey 和 Imbens (2019)解释说,文献已经通过生产机器学习模型的修改版本来解决这个问题。特别是,他们认为经常有必要修改 ML 模型以利用特定经济问题的结构。这可能包括与因果关系、内生性、需求单调性或理论上的动机限制相关的问题。
本文旨在对每种方法进行简要介绍。特别是,他们确定了以下模型和方法家族,他们认为这些模型和方法对于那些想要使用最大似然法来探索经济学中的传统问题的人来说是必不可少的:
-
当地线性森林
-
神经网络
-
助推
-
树木和森林分类
-
基于 k-均值聚类和 GANs 的无监督学习
-
混杂假设下的平均治疗效果
-
正交化和交叉拟合
-
异质处理效果
-
实验设计和强化学习
-
矩阵完成和推荐系统
-
综合控制方法
-
文本分析
感兴趣的读者应该查阅 Athey 和 Imbens (2019)关于如何将每种方法整合到经济分析中的详细信息。我们将在本书的后面详细讨论其中的一些方法,并推迟到那些章节详细讨论。
“文本作为数据”(Gentzkow 等人,2019 年)
与我们报道的其他调查相比,Gentzkow 等人(2019 年)狭隘地专注于一个单一的主题:文本分析。他们提供了经济学中使用的文本分析方法的全面调查,以及对经济学中目前没有使用的方法的介绍,但他们认为如果采用这些方法将是有用的。
论文分为三个部分:(1)将文本表示为数据,(2)统计方法,和(3)应用。由于我们将在第六章中涵盖文本分析,包括 Gentzkow 等人(2019)的扩展覆盖,我们将在这里限制自己进行简要概述。
将文本表示为数据
本文以对文本数据集的标准预处理例程的扩展讨论开始。对于大多数经济学家来说,这样的程序是陌生的,但是学习如何执行它们对于进行文本分析是必不可少的。这些例程包括将文本文档转换成模型中可用的数字格式。这通常始于清洁过程,接着是特征选择过程。共同特征包括单词和短语。我们将在第六章中详细介绍这一过程。
统计方法
作者指出,经济学中的大多数文本分析都使用了基于词典的方法。基于字典的方法属于无监督学习方法的范畴。不是训练模型来学习特征和目标之间的关系,而是预先指定一个字典,然后将其应用于文档,产生文本的一些特征的度量。
基于字典的方法的一种常见形式是测量文档的情感。情感告诉我们文档中的文本是积极的还是消极的。这类词典最初是为了与经济学无关的目的而创建的。然而,经济学的早期工作产生了旨在提取经济学特有特征的词典。图 2-5 说明了一般情感词典在联邦公开市场委员会(FOMC)公告第一段中的应用。 6 阳性词用绿色突出显示,阴性词用红色突出显示。我们可以看到,在给定的上下文中,某些单词的情感没有被正确地识别。
图 2-5
通用情感词典在 FOMC 语句中的应用
作者认为,Baker 等人(2016)是经济学中基于字典的方法的理想使用。首先,他们想要提取的特征,即经济政策的不确定性,不太可能从应用于报纸文章的主题模型中出现。第二,他们用来提取特征的字典与人类读者进行了对比测试,产生了类似的结果。在这种情况下,基于字典的方法可能是理想的。选定国家的 EPU 指数如图 2-6 所示。 7
然而,他们确实指出,经济学目前严重依赖基于词典的方法,该学科可以从文本分析中扩展到其他方法中受益。它们涵盖了不同方法的组合,其中一些是经济学家不熟悉的,另一些是熟悉的,但只是在不同的背景下使用。
图 2-6
美国、英国、德国和日本的 EPU 指数
他们的报导包括基于文本的回归、惩罚线性回归、维数减少和非线性文本回归,包括回归树、深度学习、贝叶斯回归方法和支持向量机。
最后,它们还涵盖了单词嵌入,这在经济学的文本分析应用中可能使用不足。单词嵌入提供了一种在文本中表达特征的替代方法,它是连续的并且保留了单词的信息内容。这与经济学中常用的方法形成对比,后者通常将单词视为一次性编码向量,所有这些向量都是相互正交的。
应用程序
Gentzkow 等人(2019)以对经济学中文本分析方法的广泛文献综述结束。这些应用包括作者身份识别、股票价格预测、中央银行通信、临近预报、政策不确定性测量和媒体倾斜量化。我们将在第六章中回到该文献和相关应用的细节。
“机器学习如何对宏观经济预测有用”(库隆贝等人,2019 年)
无论是对经济学中机器学习的回顾,还是为经济学中机器学习开发的方法,都倾向于忽略宏观经济学领域。这可能是因为宏观经济学家通常使用非平稳时间序列数据集,其中包含相对较少的观察值。因此,尽管预测(预报)是私人和公共部门宏观经济学家的一项常见任务,但宏观经济学往往被视为受益于采用机器学习方法的糟糕候选人。
Coulombe 等人(2019 年)通过将机器学习方法与宏观计量分析的标准工具进行比较,检验了这种情况是否属实。他们确定了最大似然法可以为宏观经济计量预测提供改进的四个领域:
-
非线性:宏观经济学本质上是非线性的。在经济扩张期间,失业率往往会缓慢下降,只有在经济衰退时才会突然飙升。此外,如果衰退影响到金融部门,导致信贷紧缩,衰退可能会变得更加严重和持久。捕捉这些要素对于做出准确的宏观经济预测至关重要。至少在原则上,ML 提供了一个工具集,允许灵活的功能形式,包括非线性,可以用于这样的目的。
-
规则化:在大数据时代,现在有很多时间序列可供宏观经济预测模型使用。例如,圣路易斯美联储银行的 FRED 系统目前包含 70 多万个时间序列。考虑到常见预测序列(如 GDP 和通货膨胀)的低频率,传统模型的观测值太少,无法在不过拟合的情况下利用大量协变量。ML 建议这样的问题可以通过正则化技术的应用来解决,正则化技术惩罚附加变量的包含。
-
交叉验证:和 ML 一样,一个好的预测模型的测试是它的样本外性能。然而,与 ML 不同,这通常不是一个好模型的唯一测试。因此,不太强调交叉验证技术,交叉验证技术通常在 ML 文献中得到更好的发展。经济学和金融学有可能通过同时采用技术和最佳实践而受益。
-
替代损失函数:经济学中使用的方法的一致性导致了对所有问题广泛采用相同的损失函数。然而,有可能不是所有的预测误差都应该使用相同的方案来加权;因此,检查 ML 文献可能会有所收获,在 ML 文献中,用奇异损失函数训练模型是常见的。
作者在一个固定效应回归环境中进行了比较练习。关于 ML 方法,他们考虑惩罚回归和随机森林。他们还利用超参数调谐和损失函数选择。他们就 ML 在宏观经济计量预测中的应用得出了四个广泛的结论:
-
拥有更多的数据和利用非线性可以提高对真实变量的长期预测。
-
已经在宏观经济学中普遍使用的因子模型是正则化的合适来源。
-
在评估过拟合时,k 倍交叉验证与贝叶斯信息准则(BIC)一样有用。
-
在宏观经济学中已经很普遍的 L 2 损失函数被证明对他们的预测练习是足够的。
总的来说,作者发现 ML 方法可以改善宏观经济预测;然而,正如我们所预料的那样,相对于经济学中的其他问题来说,收益可能很小。例如,金融序列的时间序列预测可能比宏观经济预测受益更多,因为数据通常可以以更高的频率获得。
摘要
在这一章中,我们涵盖了最大似然法及其在经济学中的应用的概念概述。我们研究了它们在历史上是如何被使用的,以及对 ML 进行研究的经济学家认为它们在未来会如何被使用。我们遇到了几个反复出现的主题,列举如下:
-
现成的机器学习方法,如果应用于政策预测问题或经济预测,可以对现有的计量经济学方法产生改进。
-
现成的 ML 方法不太可能对因果推断有用。修改最大似然算法使其本地化以用于经济学将是必要的。
-
与经济学模型不同,最大似然模型通常不会产生单个参数值的有效置信区间。
-
经济学使用理论驱动的方法来建模,并且只执行一次估计,而 ML 基于经验和通过调整的迭代改进。
-
大数据,加上 ML 方法,如正则化和交叉验证,可能会对哪些经济问题可以回答以及如何回答产生实质性影响。
-
机器学习可能有助于测量经济活动,使用具有预测步骤的模型进行推理,以及解决政策预测问题。
在接下来的章节中,我们将主要关注使用 TensorFlow 将本章讨论的方法和策略应用于经济和金融问题。
文献学
艾希,S. 2019。“机器学习对经济学的影响。”约书亚·甘斯和阿维·戈德法布·阿杰·阿格拉瓦尔合著的《人工智能经济学:一项议程》。芝加哥大学出版社。
阿西和 G.W .因本斯。2019.“经济学家应该了解的机器学习方法。”年度经济学评论11:685–725。
阿西和 G.W .因本斯。2017."应用计量经济学的现状:因果关系和政策评估."经济透视杂志31(2):3–32。
Athey,s .,G.W. Imbens 和 S. Wager2016.“近似残差平衡:高维平均治疗效果的去偏推断.” arXiv。
Athey,s .,J. Tibshirani 和 S. Wager。2019.“广义随机森林。”统计年鉴47(2):1148–1178。
贝克,S.R .,n .布鲁姆,S.J .和戴维斯。2016.《衡量经济政策的不确定性》经济学季刊第 131 卷第 4 期第 1593-1636 页。
Chernozhukov,v .,C. Hansen 和 M. Spindler。2015."具有许多控制和工具的线性模型中的后选择和后正则化推理."美国经济评论:论文&会议录105(5):486–490。
Chernozhukov,v .,D. Chetverikov,M. Demirer,E. Duflo,C. Hansen,W. Newey 和 J. Robins。2017."用于治疗和结构参数的双/去偏置机器学习."计量经济学杂志 21 卷 1 期。
库隆贝,P.G .,m .勒鲁,d .斯蒂凡诺维奇和 s .苏普雷南特 2019.“机器学习对宏观经济预测有什么用?” CIRANO 工作底稿。
Doudchenko 和 G.W. Imbens。2016.“平衡、回归、差异中的差异和综合控制方法:综合.” NBER 工作底稿 22791。
Friedberg,r .,J. Tibshirani,S. Athey 和 S. Wager。2018.“本地线性森林。” arXiv。
根茨科,m . b .凯利和 m .塔迪。2019."文本作为数据。"经济文献杂志57(3):535–574。
Glaeser,E.L .,A. Hillis,S.D. Kominers 和 M. Luca。2016.“众包市政府:利用锦标赛提高检查准确性。”美国经济评论:论文&会议录106(5):114–118。
古德费勒,我,y .本吉奥,和 a .库维尔。2016.*深度学习。*麻省理工出版社。
Kleinberg,J . J . Ludwig,S. Mullainathan 和 Z. Obermeyer。2015.“预测政策问题。”美国经济评论:论文&会议录105(5):491–495。
Kleinberg,j .,H. Lakkaraju,J. Leskovec,J. Ludwig 和 S. Mullainathan。2017.“人类决策和机器预测。”经济学季刊 133(1):237–293。
mullainathan s .和 J. Spiess。2017.“机器学习:一种实用的计量经济学方法.”(《经济学透视杂志》)31 卷 2 期:87–106 页。
Perrault、Y. Shoham、E. Brynjolfsson、J. Clark、J. Etchemendy、B. Grosz、T. Lyons、J. Manyika、S. Mishra 和 J.C. Niebles。2019.*AI 指数 2019 年度报告。*人工智能指数指导委员会,以人为中心的人工智能研究所,加利福尼亚州斯坦福:斯坦福大学。
泽维尔·萨拉·马丁。1997.“我刚刚运行了两百万次回归。”美国经济评论87(2):178–183。
哈尔·瓦里安,2014 年。"大数据:计量经济学的新招."经济透视杂志28(2):3–28。
韦杰、s .和 s .阿西。2018."使用随机森林的异质处理效果的估计和推断."美国统计协会杂志 113(532):1228–1242。
参见 Kleinberg 等人(2017)关于涉及保释决定的政策预测问题的示例。
2
见 chernozhkov 等人(2015 年)、Athey 等人(2016 年)和 chernozhkov 等人(2017 年)。
3
参见 Athey 和 Imbens (2017 年),Wager 和 Athey (2018 年),以及 Athey 等人(2019 年)。
4
参见 Athey 和 Imbens (2017 年)。
5
参见 Doudchenko 和 Imbens (2016 年)。
6
FOMC 声明全文见以下链接:www.federalreserve.gov/newsevents/pressreleases/monetary20190918a.htm
。
7
以下链接提供 20 多个国家的最新 EPU 指数:www.policyuncertainty.com/
。
三、回归
术语“回归”在计量经济学和机器学习之间的常见用法不同。在计量经济学中,回归涉及将因变量与自变量相关联的参数值的估计。计量经济学中最常见的回归形式是多元线性回归,它涉及对连续因变量和多个自变量之间线性关联的估计。然而,在计量经济学中,该术语还包括非线性模型和因变量为离散变量的模型。相反,机器学习中的回归指的是具有连续因变量(目标)的线性或非线性监督学习模型。在本章中,我们将采用回归的更广泛的计量经济学定义,但将介绍机器学习中常用的方法。
线性回归
在这一节中,我们将介绍“线性回归”的概念,这是计量经济学中最常用的经验方法。当因变量是连续的,并且因变量和自变量之间的真实关系被假定为线性时,使用它。
概观
线性回归对因变量 Y 和一组自变量{X0,…, X k }之间的关系进行建模,假设系数是线性的。线性要求每个 X j 和 Y 之间的关系可以建模为一个常数斜率,用一个标量系数 β j 来表示。等式 3-1 提供了独立变量为 k 的线性模型的一般形式。
方程式 3-1。一个 线性模型。
)
在许多情况下,我们将采用方程 3-2 中给出的符号,它明确地为每个观测值指定一个指数。 Y i 例如,表示实体 i 的变量 Y 的值。
方程式 3-2。具有实体指数的 线性模型。
)
除了实体指数,我们在经济问题中还会经常用到时间指数。在这种情况下,我们通常会使用一个 t 下标来表示变量被观测的时间段,就像我们在方程 3-3 中所做的那样。
方程式 3-3。一个 带有实体和时间索引的线性模型。
)
在线性回归中,模型参数{α,β 1 ,…, β k }不会随时间或实体而变化,因此也不会被任何实体索引。此外,不允许参数的非线性变换。例如,密集神经网络层具有类似的函数形式,但对系数可变乘积的和应用非线性变换,如等式 3-4 所示,其中 σ 表示 sigmoid 函数。
方程式 3-4。具有 sigmoid 激活函数的神经网络的 密集层。
)
虽然线性可能看起来是一个严重的函数形式限制,但它并不妨碍我们对独立变量应用变换,包括非线性变换。例如,我们可以将 X 0 重新定义为其自然对数,并将其作为独立变量。线性回归也允许两个变量之间的相互作用,如X0∑X1或指标变量,如)。另外,在时序和面板设置中,我们可以包含变量的滞后,例如Xt—1j和Xt—2j。
变换和重新定义变量使线性回归成为一种灵活的方法,可用于以任意高的精度近似非线性函数。例如,考虑这样的情况,其中 X 和 Y 之间的真实关系由等式 3-5 中的指数函数给出。
方程式 3-5。指数模型。
)
如果我们取 Y i 的自然对数,就可以在方程 3-6 中进行线性回归,恢复出模型参数,{ α , β }。
方程式 3-6。一个 转换后的指数模型。
)
在大多数情况下,我们不知道底层的数据生成过程(DGP)。此外,因变量和自变量之间没有确定的关系。相反,会有一些噪声, ϵ i ,与每个观察相关联,这可能是由于未观察到的、实体间的随机差异或测量误差而引起的。
作为一个例子,假设我们从一个已知为非线性的过程中提取数据,但其确切的函数形式未知。图 3-1 显示了数据的散点图,以及两个线性回归模型的曲线图。第一个是在假设 X 和 Y 之间的关系在[0,10]区间上用一条直线很好地近似的情况下训练的,如等式 3-7 所示。第二种是在假设需要五条线段的情况下训练的,如等式 3-8 所示。
方程式 3-7。一个 线性近似一个非线性模型。
)
等式 3-8。 一种非线性关系的线性近似。
)
图 3-1
非线性函数的两种线性近似
图 3-1 表明使用单一斜率和截距的线性回归模型是不够的;然而,即使我们完全在线性回归的框架内工作,以分段多项式样条的形式使用多个线段也足以近似非线性函数。
普通最小二乘法(OLS)
正如我们所看到的,线性回归是一种通用的方法,可以用来模拟因变量和自变量之间的关系。即使这种关系是非线性的,我们也看到了使用指示函数、变量交互或变量转换在线性模型中近似它的可能性。在某些情况下,我们甚至能够通过变量转换准确地捕捉到它。
在本节中,我们将讨论如何在 TensorFlow 中实现线性回归。我们这样做的方式将取决于我们对损失函数的选择。在经济学中,最常见的损失函数是误差平方和或均值,这是我们首先要考虑的。出于这个例子的目的,我们将把所有的独立变量堆叠在一个 n x k 矩阵、 X 中,其中 n 是观察值的数量, k 是独立变量的数量,包括常数(偏差)项。
我们将让)表示独立变量上的估计系数的向量,我们将其与真实参数值 β 区分开来。我们用来构造损失函数的“误差”项在方程 3-9 中给出。它通常有不同的名称,如误差项、残差项或扰动项。
方程式 3-9。线性回归中的扰动项。
)
注意, ϵ 是一个 n 元素的列向量。这意味着我们可以通过预乘其转置来平方和求和每个元素,如等式 3-10 所示,这给出了误差平方和。
方程式 3-10。误差平方和。
)
使用误差平方和作为损失函数(也称为执行“普通最小二乘法”(OLS))的一个好处是,它允许解析解,如方程 3-11 所示,这意味着我们不需要使用耗时且容易出错的优化算法。我们通过选择)使误差平方和最小来获得这个解。
方程式 3-11。最小化误差平方和。
)
)
)
)
唯一需要检查的是)是最小值还是最大值。每当 X 拥有“满秩”时,它将是最小值如果 X 的任何一列都不是 X 的一个或多个其他列的线性组合,这将成立。清单 3-1 演示了我们如何在 TensorFlow 中为一个玩具问题执行普通最小二乘法(OLS)。
import tensorflow as tf
# Define the data as constants.
X = tf.constant([[1, 0], [1, 2]], tf.float32)
Y = tf.constant([[2], [4]], tf.float32)
# Compute vector of parameters.
XT = tf.transpose(X)
XTX = tf.matmul(XT,X)
beta = tf.matmul(tf.matmul(tf.linalg.inv(XTX),XT),Y)
Listing 3-1Implementation of OLS in TensorFlow 2
为了方便起见,我们将 X 的转置定义为 XT 。我们还将 XTX 定义为 XT 乘以 X 。我们可以通过反相 XTX ,后乘 XT ,然后再后乘 Y 来计算)。
我们计算的参数向量),使误差平方和最小。虽然计算
)很简单,但我们可能不清楚为什么要使用 TensorFlow 来完成这样的任务。如果我们使用 MATLAB,编写线性代数运算的语法应该是紧凑的和可读的。或者,如果我们使用了 Stata 或 Python 或 R 中的任何统计模块,我们将能够自动计算参数向量的标准误差和置信区间,以及回归拟合度。
当然,如果一项任务需要并行或分布式计算,TensorFlow 确实有天然的优势;然而,当分析性地执行 OLS 时,这种需要可能是次要的。当我们想要最小化没有解析解的损失函数时,或者当我们无法在内存中保存所有数据时,TensorFlow 的价值将变得显而易见。
最小绝对偏差
虽然 OLS 是经济学中最常用的线性回归形式,并且具有许多吸引人的特性,但我们有时会希望使用另一种损失函数。例如,我们可能希望最小化误差的绝对值之和,而不是平方和。这种形式的线性回归被称为最小绝对偏差(LAD)或最小绝对误差(LAE)。
对于所有模型,包括 OLS 和拉德,参数估计对异常值的敏感性是由损失函数驱动的。由于 OLS 最小化了误差的平方,它高度重视设置参数值来解释异常值。也就是说,OLS 将更加重视消除一个单一的大误差,而不是两个误差的一半。相反,LAD 会对较大的误差和两个较小的误差给予同等的重视。
OLS 和 LAD 之间的另一个区别是,我们不能解析地表达 LAD 回归的解,因为绝对值阻止我们获得封闭形式的代数表达式。这意味着我们必须通过“训练”或“估计”模型来寻找最小值。
虽然 TensorFlow 对求解 OLS 并不特别有用,但在执行 LAD 回归或训练另一种没有解析解的模型时,它具有明显的优势。我们将在 TensorFlow 中了解如何做到这一点,同时评估 TensorFlow 识别真实参数值的准确性。更具体地说,我们将执行蒙特卡罗实验,在该实验中,我们在某些假定的参数值下随机生成数据。然后,我们将使用这些数据来估计模型,从而允许我们比较真实参数和估计参数。
清单 3-2 显示了数据是如何生成的。我们首先定义观察值的数量和样本的数量。由于我们想要评估 TensorFlow 的性能,我们将在 100 个单独的样本上训练模型参数。我们还将使用 10,000 次观察来确保有足够的数据来训练模型。
接下来,我们定义模型参数alpha
和beta
的真实值,它们对应于常数(偏差)项和斜率。我们将常数项设置为 1.0,斜率设置为 3.0。由于这些是参数的真实值,不需要训练,我们将使用tf.constant()
来定义它们。
我们现在从正态分布中画出X
和epsilon
。对于X
,我们使用标准正态分布,其均值为 0,标准差为 1。这些是tf.random.normal()
的默认参数值,因此我们不需要指定样本数和观察数之外的任何内容。对于ε,我们使用标准偏差 0.25,这是我们使用stddev
参数指定的。最后,我们计算因变量Y
。
我们现在可以使用生成的数据通过 LAD 来训练模型。我们需要完成几个步骤,这些步骤在 TensorFlow 中的所有模型构建和训练流程中都是通用的。我们将首先用一个例子来说明它们,这个例子只利用了随机抽取的数据的第一个样本。然后,我们将对 100 个样本中的每一个重复这一过程。
import tensorflow as tf
# Set number of observations and samples
S = 100
N = 10000
# Set true values of parameters.
alpha = tf.constant([1.], tf.float32)
beta = tf.constant([3.], tf.float32)
# Draw independent variable and error.
X = tf.random.normal([N, S])
epsilon = tf.random.normal([N, S], stddev=0.25)
# Compute dependent variable.
Y = alpha + beta*X + epsilon
Listing 3-2Generate input data for a linear regression
清单 3-3 提供了 TensorFlow 中模型训练过程第一步的代码。我们首先从平均值为 0、标准偏差为 5.0 的正态分布中提取值,然后用它们来初始化alphaHat
和betaHat
。5.0 的选择是任意的,但是旨在模拟一个问题,其中我们对真实参数值的先验知识有限。我们使用后缀“Hat”来表示这些不是真实值,而是估计值。由于我们想要训练参数以最小化损失函数,我们将使用tf.Variable()
而不是tf.constant()
来定义它们。
下一步是定义一个函数来计算损失。LAD 回归最小化绝对误差的总和,这相当于最小化平均绝对误差。我们将最小化平均绝对误差,因为这有更好的数值特性。 1
为了计算平均绝对误差,我们定义了一个名为maeLoss
的函数,它将参数和数据作为输入,并输出损失函数的相关值。该函数首先计算每个观测值的误差。然后使用tf.abs()
将这些值转换成绝对值,然后使用tf.reduce_mean()
返回所有观察值的平均值。
# Draw initial values randomly.
alphaHat0 = tf.random.normal([1], stddev=5.0)
betaHat0 = tf.random.normal([1], stddev=5.0)
# Define variables.
alphaHat = tf.Variable(alphaHat0, tf.float32)
betaHat = tf.Variable(betaHat0, tf.float32)
# Define function to compute MAE loss.
def maeLoss(alphaHat, betaHat, xSample, ySample):
prediction = alphaHat + betaHat*xSample
error = ySample – prediction
absError = tf.abs(error)
return tf.reduce_mean(absError)
Listing 3-3Initialize variables and define the loss
最后一步是执行优化,我们在清单 3-4 中进行了优化。为此,我们将首先使用tf.optimizers.SGD()
创建一个名为opt
的随机梯度下降优化器实例。然后,我们将使用该实例来执行最小化。这包括将minimize()
方法应用于opt
。为了对整个样本执行单步优化,我们将把损失作为lambda
函数返回给minimize
操作。此外,我们将参数alphaHat
和betaHat
以及输入数据的第一个样本X[:,0]
和Y[0:]
传递给maeLoss().
,最后,我们还需要将可训练变量列表var_list
传递给minimize()
。循环的每个增量执行一个最小化步骤,该步骤更新优化器的参数和状态。在这个例子中,我们已经重复最小化步骤 1000 次。
# Define optimizer.
opt = tf.optimizers.SGD()
# Define empty lists to hold parameter values.
alphaHist, betaHist = [], []
# Perform minimization and retain parameter updates.
for j in range(1000):
# Perform minimization step.
opt.minimize(lambda: maeLoss(alphaHat, betaHat,
X[:,0], Y[:,0]), var_list = [alphaHat,
betaHat])
# Update list of parameters.
alphaHist.append(alphaHat.numpy()[0])
betaHist.append(betaHat.numpy()[0])
Listing 3-4Define an optimizer and minimize the loss function
在我们对剩余的 99 个样本重复这个过程之前,让我们看看我们在第一个样本中识别真实参数值有多成功。图 3-2 显示了最小化过程中每一步alphaHat
和betaHat
值的曲线图。生成该图的代码如清单 3-5 所示。请注意,我们没有将样本分成小批量,因此每一步都被标记为一个时期,其中一个时期是样本的一次完整传递。正如我们前面看到的,初始值是从一个方差很大的正态分布中随机产生的。然而,alphaHat
和betaHat
似乎在大约 600 个时期后收敛到它们的真实参数值。
# Define DataFrame of parameter histories.
params = pd.DataFrame(np.hstack([alphaHist,
betaHist]), columns = ['alphaHat', 'betaHat'])
# Generate plot.
params.plot(figsize=(10,7))
# Set x axis label.
plt.xlabel('Epoch')
# Set y axis label.
plt.ylabel('Parameter Value')
Listing 3-5Plot the parameter training histories
此外,alphaHat
和betaHat
在它们收敛到它们的真实参数值后似乎不再进一步调整。这表明训练过程是稳定的,我们将在本章后面详细讨论的随机梯度下降算法能够确定一个明确的局部最小值,在这种情况下,它被证明是全局最小值。 2
现在我们已经测试了一个样本的求解方法,我们将用不同的初始参数值和不同的样本重复这个过程 100 次。然后,我们将评估我们的解决方法的性能,以确定它是否对初始值的选择或提取的数据样本敏感。图 3-3 显示了每个样本在第 1000 个时期的参数值估计直方图。大多数估计似乎紧紧围绕着真实的参数值;然而,由于初始值或抽取的样本,存在一些偏差。如果我们计划在属性类似于我们在蒙特卡罗实验中生成的数据集上使用 LAD,我们可能会考虑使用更多的历元来增加我们收敛到真实参数值的概率。
图 3-2
超过 1000 个训练时期的参数值历史
除了改变历元的数量,我们可能还想考虑调整优化算法的超参数,而不是使用默认选项。或者,我们可以考虑完全使用不同的优化算法。正如我们将在本章后面讨论的,这在 TensorFlow 中是相对简单的。
图 3-3
蒙特卡罗实验的参数估计计数
其他损失函数
正如我们所讨论的,OLS 有一个解析解,但拉德没有。由于大多数机器学习模型不允许解析解,因此 LAD 可以提供一个有指导意义的示例。我们用于构建模型、定义损失函数和执行 LAD 最小化的相同过程将在本章和本书中重复。实际上,通过简单地修改损失函数,用于执行 LAD 的步骤可以应用于任何形式的线性回归。
当然,除了 OLS 有一个封闭的解决方案之外,还有其他支持它的理由。例如,如果满足高斯-马尔可夫定理的条件,那么 OLS 估计量在所有线性和无偏估计量中具有最低的方差。 3 还有大量基于 OLS 及其变体的计量经济学文献,这使其成为相关工作的自然选择。
然而,在经济学和金融学的许多机器学习应用中,目标通常是执行预测,而不是假设检验。在这些情况下,使用不同形式的线性回归可能是有意义的;而使用 TensorFlow 会让这个任务变得更简单。
部分线性模型
在许多机器学习应用中,我们希望以一种使用线性回归模型无法令人满意地实现的方式对非线性进行建模,即使使用我们之前概述的策略也是如此。这将需要我们使用不同的建模技术。在本节中,我们将扩展线性模型,以允许包含非线性函数。
我们将从所谓的“部分线性模型”开始,而不是构建一个纯粹的非线性模型这种模型允许某些独立变量线性进入,而允许其他变量通过非线性函数进入模型。
在标准计量经济学应用的背景下,目标通常是统计推断,部分线性模型通常由线性输入的单个感兴趣变量和允许非线性输入的一组控制组成。这种练习的目的是对线性输入的参数进行推断。
然而,用部分线性模型进行有效的统计推断存在计量经济学的挑战。首先,当感兴趣的变量和控制共线时,存在参数一致性的问题。 4 这在 Robinson (1988)中有所论述,他为这种情况构造了一个一致的估计量。 5 当我们将正则化应用于控制的非线性函数时,另一个问题出现了。如果我们简单地应用 Robinson (1988)的估计量,感兴趣的参数将是有偏的。Chernozhukov 等人(2017)演示了如何通过使用正交化和样本分割来消除偏倚。
出于本章的目的,我们将专门关注用于预测目的的部分线性模型的构建和训练,而不是用于统计推断。在此过程中,我们将回避与一致性和偏差相关的问题,并将重点放在 TensorFlow 中训练程序的实际实施上。
我们将从定义我们希望在等式 3-12 中训练的模型开始。这里, β 是线性进入模型的系数向量, g ( Z )是控制的非线性函数。
方程式 3-12。一个 部分线性模型。
)
与 LAD 的示例类似,我们将使用蒙特卡罗实验来评估我们是否在 TensorFlow 中正确构建和训练了模型,并确定在给定样本大小和模型规格的情况下,我们是否可能会遇到数值问题。
为了执行蒙特卡洛实验,我们需要对线性参数的值以及 g ()的函数形式做出具体假设。为了简单起见,我们假设只有一个感兴趣的变量, X ,和一个控制, Z ,它以函数形式 exp(θZ)进入。此外,真实参数值假定为 α = 1、 β = 3、 θ = 0.05。
我们将通过生成数据来开始清单 3-6 中的蒙特卡洛实验。和前面的例子一样,我们将使用 100 个样本和 10,000 个观察值,并使用tf.constant()
定义真实的参数值。接下来,我们将绘制回归量X
和Z
以及误差项epsilon
的实现。最后,我们使用随机生成的数据来构建因变量Y
。
import tensorflow as tf
# Set number of observations and samples
S = 100
N = 10000
# Set true values of parameters.
alpha = tf.constant([1.], tf.float32)
beta = tf.constant([3.], tf.float32)
theta = tf.constant([0.05], tf.float32)
# Draw independent variable and error.
X = tf.random.normal([N, S])
Z = tf.random.normal([N, S])
epsilon = tf.random.normal([N, S], stddev=0.25)
# Compute dependent variable.
Y = alpha + beta*X + tf.exp(theta*Z) + epsilon
Listing 3-6Generate data for partially linear regression experiment
清单 3-7 中显示的下一步是定义和初始化模型参数:alphaHat0
、betaHat0
和thetaHat0
。然后,我们稍微偏离前面的例子:不是立即计算损失函数,我们将首先为部分线性模型定义一个函数,它将参数和数据样本作为输入,然后输出每个观察的预测。
# Draw initial values randomly.
alphaHat0 = tf.random.normal([1], stddev=5.0)
betaHat0 = tf.random.normal([1], stddev=5.0)
thetaHat0 = tf.random.normal([1], mean=0.05,
stddev=0.10)
# Define variables.
alphaHat = tf.Variable(alphaHat0, tf.float32)
betaHat = tf.Variable(betaHat0, tf.float32)
thetaHat = tf.Variable(thetaHat0, tf.float32)
# Compute prediction.
def plm(alphaHat, betaHat, thetaHat, xS, zS):
prediction = alphaHat + betaHat*xS + \
tf.exp(thetaHat*zS)
return prediction
Listing 3-7Initialize variables and compute the loss
我们现在已经生成了数据,初始化了参数,并定义了部分线性模型。下一步是定义一个损失函数,我们在清单 3-8 中就是这么做的。和前面的例子一样,我们可以使用最适合我们问题的损失函数。在这种情况下,我们将使用平均绝对误差(MAE)。此外,我们将使用 TensorFlow 运算,而不是像以前那样自己计算 MAE。tf.losses.mae()
操作的第一个参数是一个真值数组,第二个是一个预测值数组。
# Define function to compute MAE loss.
def maeLoss(alphaHat, betaHat, thetaHat, xS, zS, yS):
yHat = plm(alphaHat, betaHat, thetaHat, xS, zS)
return tf.losses.mae(yS, yHat)
Listing 3-8Define a loss function for a partially linear regression
最后一步是执行最小化,这是我们在清单 3-9 中做的。与在 LAD 示例中一样,我们将通过实例化一个优化器,然后应用 minimize 方法来实现这一点。每次我们执行 minimize 方法,我们将完成一个完整的训练周期。
# Instantiate optimizer.
opt = tf.optimizers.SGD()
# Perform optimization.
for i in range(1000):
opt.minimize(lambda: maeLoss(alphaHat, betaHat,
thetaHat, X[:,0], Z[:,0], Y[:,0]),
var_list = [alphaHat, betaHat, thetaHat])
Listing 3-9Train a partially linear regression model
优化过程结束后,我们可以评估结果,就像我们对 LAD 示例所做的那样。图 3-4 显示了 1000 个训练时期的参数值估计历史。请注意,alphaHat
、betaHat
和thetaHat
在大约 800 个时期的训练后都收敛到它们的真实值。此外,随着训练过程的继续,他们似乎没有偏离他们的真实值。
图 3-4
超过 1000 个训练时期的参数值历史
除此之外,我们还将检查所有 100 个样本的估计值,看看结果对初始化和数据有多敏感。每个样本的最终历元参数值在图 3-5 的直方图中显示。从图中可以清楚地看出,alphaHat
和betaHat
的估计值都紧紧围绕着它们各自的真实值。虽然thetaHat
看起来是无偏的,但由于直方图以theta
的真实值为中心,估计值中似乎有更多的变化。这表明我们可能想要对训练过程进行调整,可能通过使用更高数量的纪元。
执行 LAD 回归和部分线性回归证明 TensorFlow 能够处理任意模型的构建和训练,包括那些包含非线性的模型。在下一节中,我们将看到 TensorFlow 也可以处理离散的因变量。然后,我们将通过讨论调整培训过程以改善结果的各种方法来结束本章。
图 3-5
部分线性回归的蒙特卡罗实验结果
非线性回归
在上一节中,我们讨论了部分线性模型,它既有线性部分,也有非线性部分。求解完全非线性模型可以使用与部分线性模型相同的工作流程来完成。我们首先生成或加载数据。接下来,我们定义模型和损失函数。最后,我们实例化一个优化器并执行损失函数的最小化。
我们将利用美元(USD)和英镑(GBP)每日汇率的自然对数,而不是使用生成的数据,如图 3-6 所示。 6
图 3-6
每日频率下美元对英镑汇率的自然对数(1970-2020)。资料来源:美国联邦储备理事会
由于汇率很难预测,随机游走经常被用作预测练习中的基准模型。如等式 3-13 所示,随机游走将下一期的汇率建模为本期的汇率加上一些随机噪声。
方程式 3-13。一个 名义汇率的随机游走模型 。
)
20 世纪 90 年代出现的一系列文献认为,门限自回归(TAR)模型可以产生对随机游走模型的改进。提出了这种模型的几种变体,包括平滑过渡自回归模型(STAR)和指数平滑自回归模型(ESTAR)。 7
我们的练习将集中于在 TensorFlow 中实施 TAR 模型,并通过使用名义汇率而非实际汇率等方式偏离文献。此外,我们将再次通过关注预测来从与统计推断相关的问题中抽象出来。
自回归模型假设序列中的运动可以用序列的过去值和噪声来解释。例如,随机游走是一阶自回归模型——因为它包含一个滞后——自回归参数为 1。自回归参数是因变量滞后值的系数。
TAR 模型通过允许参数值根据预定义的阈值变化来修改自回归。也就是说,参数被假定为在特定的制度内是固定的,但是可以在不同的制度之间变化。我们将使用方程 3-14 中给出的状态。如果出现超过 2%的大幅贬值,那么我们处于一种状态,与一个自回归参数值相关联。否则,我们就另当别论了。
方程式 3-14。一个具有两种状态的 门限自回归(TAR )模型 。
)
TensorFlow 实现的第一步是准备数据。为了做到这一点,我们需要加载名义汇率的日志,计算一个滞后,并计算一个滞后一阶差。我们将加载并转换pandas
和numpy
中的数据。然后我们将它们转换成tf.constant()
物体。对于阈值变量,我们还需要将其类型从布尔值更改为 32 位浮点数。所有步骤如清单 3-10 所示。
import pandas as pd
import numpy as np
import tensorflow as tf
# Define data path.
data_path = '../data/chapter3/'
# Load data.
data = pd.read_csv(data_path+'exchange_rate.csv')
# Convert log exchange rate to numpy array.
e = np.array(data["log_USD_GBP"])
# Identify exchange decreases greater than 2%.
de = tf.cast(np.diff(e[:-1]) < -0.02, tf.float32)
# Define the lagged exchange rate as a constant.
le = tf.constant(e[1:-1], tf.float32)
# Define the exchange rate as a constant.
e = tf.constant(e[2:], tf.float32)
Listing 3-10Prepare the data for a TAR model
of the USD-GBP exchange rate
现在数据已经准备好,我们将在清单 3-11 中定义可训练模型参数rho0Hat
和rho1Hat
。
# Define variables.
rho0Hat = tf.Variable(0.80, tf.float32)
rho1Hat = tf.Variable(0.80, tf.float32)
Listing 3-11Define parameters for a TAR model of the USD-GBP exchange rate
我们接下来在清单 3-12 中定义模型和损失函数。然后,我们将自回归系数乘以制度的虚拟变量de
。最后,这要乘以汇率的滞后值le
。为了简单起见,我们将使用平均绝对损失函数和 TensorFlow 运算。
# Define model.
def tar(rho0Hat, rho1Hat, le, de):
# Compute regime-specific prediction.
regime0 = rho0Hat*le
regime1 = rho1Hat*le
# Compute prediction for regime.
prediction = regime0*de + regime1*(1-de)
return prediction
# Define loss.
def maeLoss(rho0Hat, rho1Hat, e, le, de):
ehat = tar(rho0Hat, rho1Hat, le, de)
return tf.losses.mae(e, ehat)
Listing 3-12Define model and loss function for TAR model of USD-GBP exchange rate
最后一步是定义一个优化器并执行优化,这是我们在清单 3-13 中所做的。
图 3-7 显示了培训历史。“正常”状态的自回归参数——前一天没有出现大幅贬值——迅速收敛到大约 1.0。这表明,在正常时期,汇率最好被建模为随机游走。然而,当我们观察前一天发生大幅贬值的情况时,我们发现自回归系数为 0.993,表明汇率将高度持续,但将倾向于向其均值漂移,而不是永久保持较低水平。
图 3-7
美元对英镑汇率 TAR 模型的培训历史
# Define optimizer.
opt = tf.optimizers.SGD()
# Perform minimization.
for i in range(20000):
opt.minimize(lambda: maeLoss(
rho0Hat, rho1Hat, e, le, de),
var_list = [rho0Hat, rho1Hat]
)
Listing 3-13Train TAR model of the USD-GBP exchange rate
我们现在已经了解了如何在 TensorFlow 中使用不同的损失函数执行线性回归、部分线性回归和非线性回归。在下一节中,我们将研究另一种类型的回归,它有一个离散的因变量。
逻辑回归
在机器学习中,监督学习模型通常根据它们是否具有离散或连续的因变量而分为“回归”和“分类”类别。如前所述,我们将使用计量经济学中回归的定义,它也适用于分类模型,如逻辑回归。
逻辑回归或“logit”预测因变量的类别。在微观经济环境中,logit 可以用来模拟两种交通方式的选择。在金融环境中,它可能被用来模拟我们是否处于危机之中。
由于构建和训练逻辑回归的过程涉及许多与线性、部分线性和非线性回归相同的步骤,因此我们将专门关注不同之处。
首先,该模型采用特定的函数形式,即逻辑曲线形式,如等式 3-15 所示。
方程式 3-15。逻辑曲线。
)
请注意,模型的输出是一个连续的概率,而不是一个离散的结果。由于概率范围从 0 到 1,大于 0.5 的概率通常被视为结果 1 的预测。虽然这种函数形式不同于我们在本章之前处理的任何形式,但它可以使用 TensorFlow 中所有相同的工具和操作来处理。
最后,逻辑模型和我们在本章前面定义的模型的另一个区别是它需要不同的损失函数。具体来说,我们将使用二元交叉熵损失函数,它在方程 3-16 中定义。
方程式 3-16。二元交叉熵损失函数。
)
我们使用这种特殊的函数形式,因为结果是离散的,而预测是连续的。请注意,二元交叉熵损失的总和是结果变量与每次观察的预测概率的自然对数的乘积。例如,如果 Y i 的真实类别是 1,并且模型预测类别 1 的概率是 0.98,那么该观察将会给损失增加 0.02。相反,如果预测值为 0.10,这与真实分类相差甚远,那么损失的增加将改为 2.3。
虽然计算二元交叉熵损失函数相对简单,但 TensorFlow 通过提供操作tf.losses.binary_crossentropy()
进一步简化了它,该操作将真实标签作为其第一个参数,将预测概率作为其第二个参数。
损失函数
每当我们在 TensorFlow 中求解一个模型时,我们都需要定义一个损失函数。最小化操作将利用该函数来确定如何调整参数值。幸运的是,并不总是需要定义一个定制的损失函数。相反,我们通常能够使用 TensorFlow 提供的预定义损失函数之一。
TensorFlow 目前有两个子模块包含损失函数:tf.losses
和tf.keras.losses
。第一个子模块包含损失函数的本地 TensorFlow 实现。第二个子模块包含损失函数的 Keras 实现。Keras 是一个用于执行深度学习的库,既可以作为 Python 中的独立模块,也可以作为 TensorFlow 中的高级 API。
TensorFlow 2.3 在tf.losses
子模块中提供了 15 个标准损失函数。这些损失函数中的每一个都采用了tf.loss_function(y_true, y_pred)
的形式。也就是说,我们将因变量y_true
作为第一个参数,将模型的预测y_pred
作为第二个参数。然后它返回损失函数的值。
当我们在后面的章节中使用 TensorFlow 中的高级 API 时,我们将直接使用损失函数。然而,为了本章的目的,即围绕使用低级 TensorFlow 操作的优化,我们需要将这些损失函数包含在模型的可训练参数和数据的函数中。优化器将需要利用外部函数来执行最小化。
离散因变量
子模块tf.losses
为回归设置中的离散因变量提供了两个损失函数:tf.binary_crossentropy()
、tf.categorical_crossentropy()
和tf.sparse_categorical_crossentropy()
。我们之前已经介绍过用于逻辑回归的二元交叉熵函数。当我们有一个二元因变量时,这为我们提供了一个损失的衡量标准,如经济是否衰退的指标,以及一个连续的预测,如处于衰退的概率。为了方便起见,我们在方程 3-17 中重复二元交叉熵的公式。
方程式 3-17。 二元交叉熵损失函数 。
)
分类交叉熵损失是二元交叉熵损失的简单扩展,适用于因变量有两个以上分类的情况。这种模型通常用于离散选择问题,如决定乘地铁、自行车、汽车或步行上下班的模型。在机器学习中,分类交叉熵是具有两个以上类别的分类问题的标准损失函数,并且通常用于执行图像和文本分类的神经网络中。分类交叉熵的等式在等式 3-18 中给出。注意(Y i ==k)是二进制变量,如果 Y i 是 k 类,则等于 1,否则等于 0。另外,pk(XI)是模型赋给 X i 为 k 类的概率
方程式 3-18。分类交叉熵损失函数。
)
最后,如果我们有一个因变量可能属于多个类别的问题,即“多标签”问题,我们将使用稀疏分类交叉熵损失函数,而不是分类交叉熵。请注意,正常的交叉熵损失函数假设因变量只能有一个类。
连续因变量
对于连续因变量,最常见的损失函数是平均绝对误差(MAE)和均方误差(MSE)。在 OLS,MAE 用于 LAD 和 MSE。等式 3-19 定义了平均平均误差损失函数,等式 3-20 定义了平均误差损失。回想一下)是模型对观察值 i 的预测值。
方程式 3-19。 表示绝对误差损失 。
)
方程式 3-20。 均方差损失 。
)
注意,我们可以使用tf.losses.mae()
和tf.losses.mse()
来计算损耗。
线性回归的其他常见损失函数包括平均绝对百分比误差(MAPE)、均方对数误差(MSLE)和休伯误差,它们在方程 3-21、3-22 和 3-23 中定义。分别有tf.losses.MAPE()
、tf.losses.MSLE()
和tf.losses.Huber()
三种。
方程式 3-21。平均绝对百分比误差。
)
方程式 3-22。均方对数误差。
)
方程式 3-23。胡贝尔错误。
)
图 3-8 提供了所选损失函数的比较。对于每个损失函数,损失值相对于误差值绘制。请注意,MAE 损耗与误差成线性比例关系。相反,MSE 损失在接近 0 时增长缓慢,但在远离 0 时增长更快,导致对异常值应用大量惩罚。最后,Huber 损失类似于接近零的 MSE 损失,但随着误差大小的增加,类似于 MAE 损失。
图 3-8
常见损失函数的比较
优化者
本章中我们要考虑的最后一个主题是 TensorFlow 中优化器的使用。当我们在线性回归的上下文中应用优化器时,我们已经看到了它们是如何工作的。在每种情况下,我们都使用随机梯度下降(SGD)优化器,它简单且可解释,但在最近的机器学习工作中不太常用。在这一节中,我们将扩展我们讨论的优化器集。
随机梯度下降
随机梯度下降(SGD)是一种通过使用梯度来更新参数值的最小化算法。在这种情况下,梯度是损失函数相对于每个参数的偏导数的张量。
方程 3-24 给出了参数更新过程。为了确保与等效 TensorFlow 操作兼容,我们使用文档中提供的定义。注意 θ t 是迭代 t , lr 是学习率, g t 是迭代 i 计算的梯度。
方程式 3-24。TensorFlow 中的随机梯度下降。
)
你可能想知道 SGD 在什么意义上是“随机的”随机性来自用于更新参数的采样过程。这不同于梯度下降,在梯度下降中,在每次迭代中使用整个样本。梯度下降的随机版本的好处是,它提高了迭代速度,减轻了内存限制。
我们来看一个带有截距项和单变量的线性回归的单个 SGD 步骤,其中θt=【αt, β t 】。我们将从迭代 0 开始,并假设我们已经为该批数据计算出梯度g0【0.25,0.33】。此外,我们将学习率 lr 设置为 0.01。这对θ1意味着什么?利用等式 3-24,我们可以看到θ1=[α0+0.025,β0—0.033]。也就是说,我们将 α 0 减少 0.025,将 β 0 增加 0.033。
为什么偏导数为负时我们增加一个参数值,偏导数为正时我们减少它?因为偏导数告诉我们,损失函数是如何随着给定参数的变化而变化的。如果损失函数在增加,我们离最小值越来越远,所以我们想改变方向;然而,如果损失函数是减少的,我们正在向最小值移动,所以我们想继续在相同的方向上。此外,如果损失函数既不增加也不减少,这意味着我们处于最小值,算法将自然终止。
图 3-9 显示了损失函数相对于截距项的偏导数。我们关注截距真实值附近的一个狭窄窗口,并绘制损失函数及其导数。我们可以看到,导数最初是负的,但在截距的真值处增加到 0。然后它变成正值,并在此后增加。
图 3-9
损失函数及其对截距的导数
回到方程 3-24,注意学习率的选择也是相当重要的。如果我们选择一个高的学习率,我们将在每次迭代中迈出更大的步伐,这将使我们更快地接近最小值。然而,迈出更大的步伐也可能导致我们跳过最小的,完全错过它。学习率的选择应该考虑这种折衷。
最后,值得一提的是,我们确定的“最小值”是局部的,因此可能高于全局最小值。也就是说,SGD 不区分区域中的最低点和损失函数的最小值。因此,对于几组不同的初始参数值重新运行该算法,以查看我们是否总是收敛到相同的最小值,这可能是值得的。
现代优化者
虽然 SGD 很容易理解,但它很少以原始形式用于机器学习应用程序。这是因为现代扩展通常提供更多的灵活性和健壮性,并且在基准测试任务中表现更好。SGD 最常见的扩展是均方根传播(RMSProp)、自适应矩估计(Adam)和自适应梯度方法(Adagrad 和 Adadelta)。
使用 SGD 的现代扩展有几个优点。首先,从最老的 RMSProp 开始,它们允许对每个参数应用单独的学习率。在许多优化问题中,梯度中的偏导数之间会有数量级的差异。因此,例如,应用 0.001 的学习率对于一个参数可能是合理的,但对于另一个参数可能是不合理的。RMSProp 允许我们克服这个问题。它还允许使用“动量”,即梯度在小批量上累积,使算法有可能突破局部最小值。
Adagrad、Adadelta 和 Adam 都提供了使用动量的变体,并对每个单独的参数进行自适应更新。Adam 倾向于使用其默认参数很好地处理许多优化问题。Adagrad 的核心是梯度的累积和学习速率对单个参数的适应。并且 Adadelta 通过引入保留累积梯度的窗口来修改 Adagrad。 8
在所有情况下,优化器的使用将遵循一个熟悉的两步过程。我们将首先实例化一个优化器,并使用tf.optimizer
子模块在流程中设置它的参数值。其次,我们将迭代应用最小化函数,并将损失函数作为 lambda 函数传递给它。
因为我们已经多次执行了第二步,所以我们将只关注清单 3-14 中的第一步。在这里,我们已经实例化了 SGD、RMSProp、Adagrad 和 Adadelta 优化器,并强调了如何设置它们各自的参数值。
# Instantiate optimizers.
sgd = tf.optimizers.SGD(learning_rate = 0.001,
momentum = 0.5)
rms = tf.optimizers.RMSprop(learning_rate = 0.001,
rho = 0.8, momentum = 0.9)
agrad = tf.optimizers.Adagrad(learning_rate = 0.001,
initial_accumulator_value = 0.1)
adelt = tf.optimizers.Adadelta(learning_rate = 0.001,
rho = 0.95)
adam = tf.optimizers.Adam(learning_rate = 0.001,
beta_1 = 0.9, beta_2 = 0.999)
Listing 3-14Instantiate optimizers
对于SGD
,我们设置学习率和momentum
。如果我们担心有很多局部最小值,我们可以增加momentum
到一个更高的值。对于RMSProp
,我们不仅设置了一个momentum
参数,还设置了rho
,这是关于梯度的信息衰减的速率。在一段时间内保持梯度的Adadelta
参数也具有相同的衰减参数rho
。对于Adagrad
,我们设置一个初始累加器值,该值与梯度随时间累积的强度相关。最后,对于 Adam 优化器,我们为关于梯度的平均值和方差的信息的累积设置衰减率。在这种情况下,我们使用 Adam 优化器的默认值,它通常在大型优化问题中表现良好。
我们现在已经介绍了我们将在整本书中使用的主要优化器。当我们将它们应用于训练模型时,我们将再次详细讨论它们。当我们训练具有数千个参数的大型模型时,SGD 的现代变体将特别有用。
摘要
经济学中最常用的实证方法是回归。在机器学习中,术语回归指的是具有连续目标的监督学习模型。在经济学中,术语“回归”的定义更广泛,可能指二元或分类因变量的情况,如逻辑回归。出于本书的目的,我们采用经济学术语。
在这一章中,我们介绍了回归的概念,包括线性、部分线性和非线性变量。我们看到了如何在 TensorFlow 中定义和训练这样的模型,这将最终形成在 TensorFlow 中求解任何任意模型的基础,我们将在后面的章节中看到。
最后,我们讨论了培训过程的细节。我们看到了如何构建损失函数,以及 TensorFlow 中有哪些预定义的损失函数。我们还看到了如何使用各种不同的优化例程来执行最小化。
文献学
Chernozhukov,v .,D. Chetverikov,M. Demirer,E. Duflo,C. Hansen,W. Newey 和 J. Robins。2017."用于治疗和结构参数的双/去偏置机器学习."计量经济学杂志 21 卷 1 期。
古德费勒,我,y .本吉奥,和 a .库维尔。2017.深度学习。麻省剑桥:麻省理工学院出版社。
罗宾逊,下午 1988。"根 N 一致的半参数回归."计量经济学56(4):931–954。
泰勒议员地方检察官皮尔和萨尔诺。2001."实际汇率的非线性均值回归:购买力平价难题的解决方案."国际经济评论42(4):1015–1042。
因为平均值是总和除以观察值的数量(即,由常数缩放),所以最小化平均值将等同于最小化总和。在实践中,我们通常会最小化平均值,因为计算大的和会导致溢出,当一个数超过其数据类型允许的范围时就会发生溢出。
2
局部最小值是函数在给定区域的最低值,而全局最小值是函数的最低整体值。在实践中,损失函数通常具有许多局部最小值,使得确定全局最小值具有挑战性。
3
高斯-马尔可夫定理做了五个假设:(1)真实模型在参数上是线性的;(2)数据是随机抽样的;(3)自变量之间没有一个是完全相关的(没有完全共线性);(4)误差项是外生的(与自变量不相关);和(5)误差项的方差是常数和有限的。
4
如果两个回归量 X 和 Z 在统计上不独立,则称它们是“共线的”。
5
当观测值趋于无穷大时,一致估计量以概率收敛于真实参数值。
6
raw 系列可在 https://fred.stlouisfed.org/series/DEXUSUK
下载。
7
参见 Taylor 等人(2001 年)对 STAR 和 e STAR 模型的概述。
8
有关优化器理论属性的详细讨论,请参见 Goodfellow 等人(2017)。