从数据中创建具有正确维度的输入张量

Creating input tensors with the right dimensions from data

我有 4 个特征,2 个连续的特征采用

的形式
[1,2,3,4,1,1,...]

和 2 个分类形式

[["A"],["A","B"],["A","B","C"], ["A", "C"]]

我的标签采用与连续特征相同的形式,从 0 到 8 用于多class化。我的目标是根据 4 个特征预测标签 class。

我将数据从 json 文件提取到 Pandas 数据帧中,如下所示:

         f1         f2   f3                f4         label
 0        1          3     [R]              [None]        1
 1        2          2     [U, W]           [Flying]      2
 2        1          4     [None]           [None]        2
 3        1          2     [B]              [Flying]      0
..     ...        ...     ...                 ...   ...

根据我对 ragged tensor 文档的理解,我可以像这样将所有这些特征直接输入到我的模型中:

import tensorflow as tf
f1 = tf.keras.Input(shape=(1,),dtype=tf.dtypes.int32)
f2 = tf.keras.Input(shape=(1,),dtype=tf.dtypes.int32)
f3 = tf.keras.Input(shape=(None,),dtype=tf.dtypes.string, ragged=True)
f4 = tf.keras.Input(shape=(None,),dtype=tf.dtypes.string, ragged=True)

之后,我对 f1 和 f2 进行了规范化,并对 f3 和 f4 使用了 StringLookup、Embedding 和 Flatten 层。然后我将它们连接起来并送入几个密集层,然后使用 softmax 将它们送入最终的密集层。

我的模型构建成功。

然而,当我像这样将我的数据框传递给我的训练函数时:

features = ["f1","f2","f3","f4"]
model.fit(x=[training_set[feature] for feature in features],
             y=training_set[label],
             validation_split=0.1)

我收到以下错误

ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type list).

接下来,我尝试手动将我的数据框转换为具有正确类型的 NumPy 数组:

import numpy as np
f1 = np.asarray(training_set["f1"]).astype(np.int32)
f2 = np.asarray(training_set["f2"]).astype(np.int32)
f3 = np.asarray(training_set["f3"]).astype(object)
f4 = np.asarray(training_set["f4"]).astype(object)
l = np.asarray(training_set["label"]).astype(np.int32)
model.fit(x=[f1,f2,f3,f4],
          y=l,
          validation_split=0.1)   

产生同样的错误:

ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type list).

在我看来,我应该将数据转换为张量并将其输入 fit 方法,而不是 Numpy 数组。如果我正确解释 tf.Data documentation 这应该是可能的?

在尝试这样做的过程中,我陷入了使尺寸正确的困境,例如:

f1 = tf.stack([tf.convert_to_tensor(i) for i in training_set["f1"].values],axis=0)
# Is shape (622,) afaik I need shape(1,)?
f3 = tf.ragged.stack(data["colors"])
# Is shape (622, None) afaik needs to be shape (None,)

我做错了什么?

Keras 模型将参差不齐的张量变平是相当复杂的,但你可以做的是使用 LSTM 层或 GlobalMaxPool1DGlobalAveragePooling1D 等。处理和展平张量。只要确保二维张量以某种方式转换为一维张量即可。这是一个有两个 GlobalMaxPool1D 层的工作示例:

资料准备:

import tensorflow as tf
import pandas as pd

d = {'f1': [1, 2, 1, 1], 
     'f2': [3, 2, 4, 2], 
     'f3':[['R'] , ['U', 'W'], [None], ['B']], 
     'f4':[[None] , ['Flying'], [None], ['Flying']],
     'label': [1, 2, 2, 0]}

df = pd.DataFrame(data=d)
df['f3'] =  df['f3'].apply(lambda x: ['[UNK]' if i == None else i for i in x ])
df['f4'] =  df['f4'].apply(lambda x: ['[UNK]' if i == None else i for i in x])

data_f1 = df[["f1"]].to_numpy()
data_f2 = df[["f2"]].to_numpy()
labels  = df[["label"]].to_numpy()

data_f3 = tf.ragged.constant([df['f3'].to_list()])
data_f4 = tf.ragged.constant([df['f4'].to_list()])

型号:

look_up_layer = tf.keras.layers.StringLookup()
look_up_layer.adapt(tf.ragged.stack([data_f3, data_f4]))
data_f3 = tf.squeeze(data_f3, axis=0)
data_f4 = tf.squeeze(data_f4, axis=0)

f1 = tf.keras.Input(shape=(1,),dtype=tf.dtypes.int32)
f2 = tf.keras.Input(shape=(1,),dtype=tf.dtypes.int32)
f3 = tf.keras.Input(shape=(None,),dtype=tf.dtypes.string, ragged=True)
f4 = tf.keras.Input(shape=(None,),dtype=tf.dtypes.string, ragged=True)
f1_dense = tf.keras.layers.Dense(5, activation='relu')(f1)
f2_dense = tf.keras.layers.Dense(5, activation='relu')(f2)
f3_lookup = look_up_layer(f3)
f4_lookup = look_up_layer(f4)
embedding_layer = tf.keras.layers.Embedding(len(look_up_layer.get_vocabulary()), 10, input_length=1)
embedd_f3 = embedding_layer(f3_lookup)
embedd_f4 = embedding_layer(f4_lookup)
embedd_f3 = tf.keras.layers.GlobalMaxPool1D()(embedd_f3)
embedd_f4 = tf.keras.layers.GlobalMaxPool1D()(embedd_f4)
output = tf.keras.layers.Concatenate(axis=-1)([f1_dense, f2_dense, embedd_f3, embedd_f4])
output = tf.keras.layers.Dense(3, 'softmax')(output)
model = tf.keras.Model([f1, f2, f3, f4], output)

model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy())
model.fit([data_f1, data_f2, data_f3, data_f4], labels, batch_size=1, epochs=2)