通过 feature_columns 使用数据集 API 将自由文本功能引入 Tensorflow Canned Estimators

Getting free text features into Tensorflow Canned Estimators with Dataset API via feature_columns

我正在尝试构建一个模型,它给出 reddit_score = f('subreddit','comment')

这主要是作为一个例子,我可以以此为基础构建一个工作项目。

我的密码是here.

我的问题是我看到罐头估算器,例如DNNLinearCombinedRegressor 必须有 feature_columns 是 FeatureColumn class 的一部分。

我有我的词汇文件,并且知道如果我只限制评论的第一个词,我可以做类似

的事情
tf.feature_column.categorical_column_with_vocabulary_file(
        key='comment',
        vocabulary_file='{}/vocab.csv'.format(INPUT_DIR)
        )

但是如果我传递的是评论中的前 10 个词,那么我不确定如何从 "this is a pre padded 10 word comment xyzpadxyz xyzpadxyz" 之类的字符串转换为 feature_column 这样我就可以构建传递给广度和深度模型中的 deep 特征的嵌入。

看起来它一定是非常明显或简单的东西,但我终其一生都找不到任何具有此特定设置的现有示例(广度和深度罐装,数据集 api,以及功能,例如 subreddit 和评论等原始文本功能)。

我什至在考虑自己进行词汇整数查找,这样我传入的 comment 功能将类似于 [23,45,67,12,1,345,7,99,999,999] 然后也许我可以通过 numeric_feature 获得它的形状,然后从那里做一些事情。但这感觉有点奇怪。

您可以使用 tf.string_split(),然后执行 tf.slice() 对其进行切片,注意首先 tf.pad() 带有零的字符串。看标题中的预处理操作: https://towardsdatascience.com/how-to-do-text-classification-using-tensorflow-word-embeddings-and-cnn-edae13b3e575

有了词,就可以创建十个特征栏

按照 post @Lak 的方法添加答案,但对数据集 api 做了一些调整。

# Create an input function reading a file using the Dataset API
# Then provide the results to the Estimator API
def read_dataset(prefix, mode, batch_size):

    def _input_fn():

        def decode_csv(value_column):

            columns = tf.decode_csv(value_column, field_delim='|', record_defaults=DEFAULTS)
            features = dict(zip(CSV_COLUMNS, columns))

            features['comment_words'] = tf.string_split([features['comment']])
            features['comment_words'] = tf.sparse_tensor_to_dense(features['comment_words'], default_value=PADWORD)
            features['comment_padding'] = tf.constant([[0,0],[0,MAX_DOCUMENT_LENGTH]])
            features['comment_padded'] = tf.pad(features['comment_words'], features['comment_padding'])
            features['comment_sliced'] = tf.slice(features['comment_padded'], [0,0], [-1, MAX_DOCUMENT_LENGTH])
            features['comment_words'] = tf.pad(features['comment_sliced'], features['comment_padding'])
            features['comment_words'] = tf.slice(features['comment_words'],[0,0],[-1,MAX_DOCUMENT_LENGTH])

            features.pop('comment_padding')
            features.pop('comment_padded')
            features.pop('comment_sliced')

            label = features.pop(LABEL_COLUMN)

            return features, label

        # Use prefix to create file path
        file_path = '{}/{}*{}*'.format(INPUT_DIR, prefix, PATTERN)

        # Create list of files that match pattern
        file_list = tf.gfile.Glob(file_path)

        # Create dataset from file list
        dataset = (tf.data.TextLineDataset(file_list)  # Read text file
                    .map(decode_csv))  # Transform each elem by applying decode_csv fn

        tf.logging.info("...dataset.output_types={}".format(dataset.output_types))
        tf.logging.info("...dataset.output_shapes={}".format(dataset.output_shapes))

        if mode == tf.estimator.ModeKeys.TRAIN:

            num_epochs = None # indefinitely
            dataset = dataset.shuffle(buffer_size = 10 * batch_size)

        else:

            num_epochs = 1 # end-of-input after this

        dataset = dataset.repeat(num_epochs).batch(batch_size)

        return dataset.make_one_shot_iterator().get_next()

    return _input_fn

然后在下面的函数中,我们可以引用我们在 decode_csv() 中创建的字段:

# Define feature columns
def get_wide_deep():

    EMBEDDING_SIZE = 10

    # Define column types
    subreddit = tf.feature_column.categorical_column_with_vocabulary_list('subreddit', ['news', 'ireland', 'pics'])

    comment_embeds = tf.feature_column.embedding_column(
        categorical_column = tf.feature_column.categorical_column_with_vocabulary_file(
            key='comment_words',
            vocabulary_file='{}/vocab.csv-00000-of-00001'.format(INPUT_DIR),
            vocabulary_size=100
            ),
        dimension = EMBEDDING_SIZE
        )

    # Sparse columns are wide, have a linear relationship with the output
    wide = [ subreddit ]

    # Continuous columns are deep, have a complex relationship with the output
    deep = [ comment_embeds ]

    return wide, deep