从Tensorflow中的``嵌入列''获取嵌入向量

时间:2019-12-04 02:06:02

标签: numpy tensorflow deep-learning

我想获取使用Tensorflow中的“嵌入列”创建的numpy向量。

例如,创建样本DF:

sample_column1 = ["Apple","Apple","Mango","Apple","Banana","Mango","Mango","Banana","Banana"]
sample_column2 = [1,2,1,3,4,6,2,1,3]
ds = pd.DataFrame(sample_column1,columns=["A"])
ds["B"] = sample_column2
ds

将熊猫DF转换为Tensorflow对象

# A utility method to create a tf.data dataset from a Pandas Dataframe
def df_to_dataset(dataframe, shuffle=True, batch_size=32):

    dataframe = dataframe.copy()
    labels = dataframe.pop('B')
    ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
    #print (ds)
    if shuffle:
       ds = ds.shuffle(buffer_size=len(dataframe))
    #print (ds)
    ds = ds.batch(batch_size)
    return ds

创建嵌入列:

tf_ds = df_to_dataset(ds)
# embedding cols
col_a = feature_column.categorical_column_with_vocabulary_list(
  'A', ['Apple', 'Mango', 'Banana'])
col_a_embedding = feature_column.embedding_column(col_a, dimension=8)

反正是从“ col_a_embedding”对象中获取嵌入作为numpy向量吗?

示例

“ Apple”类别将被嵌入8号矢量中:

[a1 a2 a3 a4 a5 a6 a7 a8]

我们可以获取该向量吗?

2 个答案:

答案 0 :(得分:1)

我看不到使用功能列来获得想要的方法的方法(在sequence_embedding_column的{​​{3}}中看不到名为tf.feature_column或类似功能的函数)。因为要素列的结果似乎是固定长度的张量。他们通过使用组合器聚合各个嵌入向量(总和,均值,sqrtn等)来实现这一点。因此,类别序列的维实际上丢失了。

但是,如果您使用较低级别的API,则完全可行。 首先,您可以构造一个查找表,以将分类字符串转换为ID。

features = tf.constant(["apple", "banana", "apple", "mango"])
table = tf.lookup.index_table_from_file(
    vocabulary_file="fruit.txt", num_oov_buckets=1)
ids = table.lookup(features)

#Content of "fruit.txt"
apple
mango
banana
unknown

现在,您可以将嵌入初始化为2d变量。其形状为[number of categories, embedding dimension]

num_categories = 3
embedding_dim = 64
category_emb = tf.get_variable(
                "embedding_table", [num_categories, embedding_dim],
                initializer=tf.truncated_normal_initializer(stddev=0.02))

然后您可以按以下方式查找嵌入的类别:

ids_embeddings = tf.nn.embedding_lookup(category_emb, ids)

请注意,ids_embeddings中的available functions是一个串联的长张量。随时reshape使其变形为您想要的形状。

答案 1 :(得分:1)

我建议最简单的最快方法就是这样做,这就是我在自己的应用程序中所做的事情:

  1. 使用熊猫将文件read_csv转换为类型为string的列 使用dtype参数的熊猫中的“类别”。我们称之为领域 “F”。这是原始的字符串列,而不是数字列。

    仍在熊猫中,创建一个新列并复制原始列的 熊猫cat.codes进入新列。我们将其称为“ f_code”字段。熊猫自动将其编码为紧凑表示的数字列。它将具有传递给神经网络所需的数字。

    现在在keras功能性API神经中的嵌入层中 网络模型,将f_code传递到模型的输入层。的 f_code中的value现在将是一个数字,例如int8。嵌入 层现在将正确处理它。不要将原始列传递给模型。

下面是从我的项目中复制的一些示例代码行,它们完全按照上面的步骤操作。

createApolloClient

您可以看到为您制作的数字熊猫:

all_col_types_readcsv = {'userid':'int32','itemid':'int32','rating':'float32','user_age':'int32','gender':'category','job':'category','zipcode':'category'}

<some code omitted>

d = pd.read_csv(fn, sep='|', header=0, dtype=all_col_types_readcsv, encoding='utf-8', usecols=usecols_readcsv)

<some code omitted>

from pandas.api.types import is_string_dtype
# Select the columns to add code columns to. Numeric cols work fine with Embedding layer so ignore them.

cat_cols = [cn for cn in d.select_dtypes('category')]
print(cat_cols)
str_cols = [cn for cn in d.columns if is_string_dtype(d[cn])]
print(str_cols)
add_code_columns = [cn for cn in d.columns if (cn in cat_cols) and (cn in str_cols)]
print(add_code_columns)

<some code omitted>

# Actually add _code column for the selected columns
for cn in add_code_columns:
  codecolname = cn + "_code"
  if not codecolname in d.columns:
    d[codecolname] = d[cn].cat.codes

最后,在此示例中,您可以省略job列并保留job_code列,以传递到keras神经网络模型中。这是我的一些模型代码:

d.info()
d.head()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 99991 entries, 0 to 99990
Data columns (total 5 columns):
userid      99991 non-null int32
itemid      99991 non-null int32
rating      99991 non-null float32
job         99991 non-null category
job_code    99991 non-null int8
dtypes: category(1), float32(1), int32(2), int8(1)
memory usage: 1.3 MB

顺便说一句,在将np.array()传递到model.fit()时,也请将其包装在所有熊猫数据框中。没有足够的文档记录,并且在运行时也没有检查过熊猫数据帧无法安全传递。您将获得大量的内存分配,否则将导致主机崩溃。