表格数据:在不求助于迭代的情况下实现自定义张量层

Tabular data: Implementing a custom tensor layer without resorting to iteration

我有一个通过迭代不难实现的张量操作的想法,批量大小为 1。但是我想尽可能地并行化它。

我有两个形状为 (n, 5) 的张量,称为 X 和 Y。X 实际上应该表示形状为 (n, 1) 的 5 个一维张量:(x_1, ... , x_n). Y 同上

我想计算一个形状为 (n, 25) 的张量,其中每一列代表张量运算 f(x_i, y_j) 的输出,其中 f 对所有对象都是固定的1 <= i, j <= 5。操作 f 的输出形状为 (n, 1),就像 x_i 和 y_i.

我觉得有必要澄清一下,f 本质上是一个来自串联 [...x_i, ...y_i] 张量的全连接层,形状为 (1, 10 ), 到形状为 (1,5) 的输出层。

同样,很容易看出如何通过迭代和切片手动执行此操作。但是,这可能非常慢。分批执行此操作,其中张量 X、Y 现在具有形状 (n, 5, batch_size) 也是可取的,特别是对于小批量梯度下降。

这里很难说清楚为什么我想创建这个网络;我觉得它适合我的 'itemized tabular data' 领域,并且与完全连接的网络相比,每次操作的权重数量显着减少。

这可以使用 tensorflow 吗?当然不只是使用keras。 以下是根据 AloneTogether 的请求

在 numpy 中的示例
import numpy as np

features = 16
batch_size = 256

X_batch = np.random.random((features, 5, batch_size))
Y_batch = np.random.random((features, 5, batch_size))

# one tensor operation to reduce weights in this custom 'layer'
f = np.random.random((features, 2 * features))

for b in range(batch_size):
    X = X_batch[:, :, b]
    Y = Y_batch[:, :, b]
    for i in range(5):
        x_i = X[:, i:i+1]
        for j in range(5):
            y_j = Y[:, j:j+1]

            x_i_y_j = np.concatenate([x_i, y_j], axis=0)
            
            # f(x_i, y_j)
            # implemented by a fully-connected layer
            f_i_j = np.matmul(f, x_i_y_j)

您需要的所有操作(串联和矩阵乘法)都可以进行批处理。 这里的困难部分是,您想要将 X 中所有项目的特征与 Y 中所有项目的特征(所有组合)连接起来。 我推荐的解决方案是将 X 的维度扩展到 [batch, features, 5, 1],将 Y 的维度扩展到 [batch, features, 1, 5]tf.repeat() 两个张量所以它们的形状变成 [batch, features, 5, 5]。 现在您可以连接 X 和 Y。您将得到一个形状为 [batch, 2*features, 5, 5] 的张量。观察以这种方式构建所有组合。 下一步是矩阵乘法。 tf.matmul() 也可以做批量矩阵乘法,但我在这里使用 tf.einsum() 因为我想更多地控制哪些维度被视为批量。 完整代码:

import tensorflow as tf
import numpy as np

batch_size=3
features=6
items=5

x = np.random.uniform(size=[batch_size,features,items])
y = np.random.uniform(size=[batch_size,features,items])

f = np.random.uniform(size=[2*features,features])

x_reps= tf.repeat(x[:,:,:,tf.newaxis], items, axis=3)
y_reps= tf.repeat(y[:,:,tf.newaxis,:], items, axis=2)

xy_conc = tf.concat([x_reps,y_reps], axis=1)

f_i_j = tf.einsum("bfij, fg->bgij", xy_conc,f)

f_i_j = tf.reshape(f_i_j , [batch_size,features,items*items])