Categories
程式開發

编写复杂 TensorFlow 表达式的好工具:TF-Coder


当我们操作张量时,必须跟踪多维度、张量形状和 DType 的兼容性,当然还有数学方面的正确性。此外,还有数以百计的 TensorFlow 操作,要找到正确的操作,真不失为一项挑战。

与其直接编写张量操作代码,还不如通过一个说明性例子演示一下,然后就自动获得相应的代码,TensorFlow Coder(TF-Coder)使这成为可能。

TF-coder 是一款程序合成工具,可以帮助你编写 TensorFlow 代码。首先,该工具要求提供所需张量变换的输入输出示例。然后,它运行一个组合搜索来查找执行该转换的 TensorFlow 表达式。TF-Coder 的输出是真正的 TensorFlow 代码,可以将其包含在项目中。

下图介绍了 TF-Coder,这个Colab notebook允许使用 TF-Coder 来解决张量操作问题。

编写复杂 TensorFlow 表达式的好工具:TF-Coder 1

在本文中,我们将举例说明 TF-Coder 可以帮助编写 TensorFlow 代码的各种场景。

TensorFlow 编程示例

假设你想以广播的方式将一个 M-元素向量与一个 N-元素向量“相加”,产生一个包含所有对偶和的 M×N 矩阵。与其在 TensorFlow 文档中挖空心思地找出如何做这件事,不如提供一个输入输出的例子(使用 M=3 和 N=4):

输入张量,作为将输入变量名称映射到示例张量值的 dict。

inputs = {
'rows': [10, 20, 30],
'cols': [1, 2, 3, 4],
}

所需的输出张量,对应于所提供的输入张量:

output = [[11, 12, 13, 14],
[21, 22, 23, 24],
[31, 32, 33, 34]]

有了这些信息(默认情况下已输入到 TF-Coder Colab 中),TF-Coder 工具将在几分之一秒内自动找到合适的 TensorFlow 代码:

tf.add(cols, tf.expand_dims(rows, 1))

上面的问题很简单,只是为了通过示例来说明编程的思想。TF-Coder 对于较难的问题也很有用,我们将在下面说明。

TF-Coder 帮助找到要使用的正确函数

假设你正在处理一个数字特征,比如,一个物品的价格,在你的数据集中,价格有很大的范围,例如,从 10 美元以下到 1000 美元以上。如果直接将这些价格作为特征来使用,你的模型可能会对训练数据中的特定价格出现过拟合现象,而且在评估过程中也可能难以处理异常价格。

为了处理这些问题,你可能需要使用分桶(bucketing)方法将数字价格转换为分类特征。例如,使用桶(bucket)边界 [10,50,100,1000] 意味着 10 美元以下的价格应该归入 bucket 0,10~50 美元之间的价格归入 bucket 1,以此类推。

选择桶边界之后,要如何使用 TensorFlow 将数字价格映射到桶索引呢?例如,给定以下桶边界和物品价格:

# Input tensors
boundaries = [10, 50, 100, 1000]
prices = [15, 3, 50, 90, 100, 1001]

你需要计算每个项目的桶号:

# Output tensor
bucketed_prices = [1, 0, 2, 2, 3, 4]

虽然 TensorFlow 自带了各种各样的分桶操作,但要弄清楚哪些特定操作进行这种分桶处理,可能会很棘手。由于 TF-Coder 可以通过行为识别数百种张量操作,因此可以通过提供输入输出示例来查找正确的操作。

# Input-output example
inputs = {
'boundaries': [10, 50, 100, 1000],
'prices': [15, 3, 50, 90, 100, 1001],
}
output = [1, 0, 2, 2, 3, 4]

在几秒钟之内,TF-Coder 输出以下解决方案:

tf.searchsorted(boundaries, prices, side='right')

这给了我们一个有用的提示,并且tf.searchorsted的文档也证实这段代码确实按照预期执行了分桶操作。

TF-Coder 帮助你以巧妙的方式组合函数

现在,让我们考虑另一个问题:计算一个 0-1 张量,它标识输入张量每行的最大元素。

# Input tensor
scores = [[0.7, 0.2, 0.1],
[0.4, 0.5, 0.1],
[0.4, 0.4, 0.2],
[0.3, 0.4, 0.3],
[0.0, 0.0, 1.0]]
# Output tensor
top_scores = [[1, 0, 0],
[0, 1, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]

请注意,如果同一个最大的元素在一行内多次出现,比如在scores的第三行中,那么应该只标记第一个这样的最大元素,这样每一行的top_scores都有一个条目1

与上一个问题不同的是,没有单一的 TensorFlow 函数可以执行此计算。如果在文档中搜索“max”,你可能会发现tf.reduce_maxtf.argmaxtf.maximum相关,但是应该用哪一个呢?tf.reduce_max产生[0.7, 0.5, 0.4, 0.4, 1.0]tf.argmax产生[0, 1, 0, 1, 2]tf.maximum是不正确的,因为它需要两个参数。这些看起来距我们想要的输出相差甚远。

TF-Coder 可以帮助解决这类棘手的问题。你可以用输入输出示例的形式来编写问题:

# Input-output example
inputs = {
'scores': [[0.7, 0.2, 0.1],
[0.4, 0.5, 0.1],
[0.4, 0.4, 0.2],
[0.3, 0.4, 0.3],
[0.0, 0.0, 1.0]],
}
output = [[1, 0, 0],
[0, 1, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]

TF-Coder 在一个简短的解决方案中使用了tf.one_hottf.argmax的组合:

tf.cast(tf.one_hot(tf.argmax(scores, axis=1), 3), tf.int32)

通过对 TensorFlow 操作组合进行详细搜索,TF-Coder 经常会找到类似这样的优雅解决方案,这可能会简化并加快你的 TensorFlow 程序。

TF-Coder 可以帮助你编写调试更少的正确代码

考虑将整数列表归一化为概率分布,方法是将每一行除以该行之和。例如:

# Input tensor
counts = [[0, 1, 0, 0],
[0, 1, 1, 0],
[1, 1, 1, 1]]
# Output tensor
normalized = [[0.0, 1.0, 0.0, 0.0],
[0.0, 0.5, 0.5, 0.0],
[0.25, 0.25, 0.25, 0.25]]

即使你知道要使用的相关函数(tf.reduce_sum后跟tf.divide),编写正确的代码仍然是非常重要的。第一次尝试可能是这样的:

# First attempt
normalized = tf.divide(counts, tf.reduce_sum(counts, axis=1))

这是正确的吗?有许多潜在的陷阱需要加以考虑:

  • 求和轴是否正确?还是应该是axis=0
  • counts的形状和tf.reduce_sum(counts, axis=1)是否兼容除法,还是需要重塑或转置这两者中的任何一个?
  • countstf.reduce_sum(counts, axis=1)都是tf.int32张量。tf.int32可以用除法吗?还是需要首先将它们转换为 float DType?
  • 这两个参数的顺序是否正确,还是应该互换一下?
  • 输出类型是tf.int32tf.float32,还是别的什么?
  • 有没有尚未考虑的更简单或更好的方法?

你可以通过以下输入输出示例将此任务交给 TF-Coder:

# Input-output example
inputs = {
'counts': [[0, 1, 0, 0],
[0, 1, 1, 0],
[1, 1, 1, 1]],
}
output = [[0.0, 1.0, 0.0, 0.0],
[0.0, 0.5, 0.5, 0.0],
[0.25, 0.25, 0.25, 0.25]]

TF-Coder 的解决方案是:

tf.cast(tf.divide(counts, tf.expand_dims(tf.reduce_sum(counts, axis=1), axis=1)), tf.float32)

通过使用 TF-Coder 来解决这一问题,减轻了开发人员的心理负担。当 TF-Coder 生成上面的解决方案是,可以保证代码在示例输入上运行时正确地生成示例输出。TF-Coder 的解决方案还将避免任何不必要的步骤。隐私,你可以快速地推导出上述大部分问题的答案:为使形状与除法兼容,需要额外的tf.expand_dims步骤,并且tf.Divide的结果必须强制转换为tf.float32(实际上,tf.divide在除以两个tf.int32张量时返回tf.float64张量)。通过这种方式,TF-Coder 可以帮助你编写简单而正确的代码,而无需经历通过的调试周期。

注意事项

TF-Coder 有一些限制。它目前可以在一分钟内找到涉及 3~4 个操作的解决方案,但涉及 6 个或更多操作的解决方案对 TF-Coder 来说太过复杂,无法在合理的时间内找到。此外,TF-Coder 目前尚不支持复张量、字符串张量或不规则张量。支持的操作的完整列表可以在Colab notebook中找到。

此外,TF-Coder 只保证其解决方案对给定的输入输出示例有效。该工具会搜索与提供的输入输出示例匹配的简单 TensorFlow 表达式,但有时候这个解决方案过于简单,不能以语气的方式进行泛化。使示例尽可能清晰可能会有所帮助,这通常可以通过向输入和输出张良添加更多的数字来实现。请查看 TF-Coder 的解决方案,以确保它们正确地实施了预期的行为。

亲自尝试 TF-Coder

一定要亲自尝试TF-Coder!哪怕是 Google 有经验的 TensorFlow 用户,也可以在 TF-Coder 的帮助下学习新事物。

你可以使用这个Colab notebookd访问该工具,无需下载或者安装。按照本教程进行详细的演练。你也可以看看我们托管在 GitHub上的代码和文档,以及我们的研究论文

注意:在 Colab 工具中,我们希望记录 TF-Coder 的问题和由此产生的解决方案,这样我们就可以改进工具,并构建一个数据集来加速程序的综合研究,但是,这种数据收集是完全可选的。

原文链接

https://blog.tensorflow.org/2020/08/introducing-tensorflow-coder-tool.html