TensorFlow input function for reading sparse data (in libsvm format)

Viewed 1141

I'm new to TensorFlow and trying to use the Estimator API for some simple classification experiments. I have a sparse dataset in libsvm format. The following input function works for small datasets:

def libsvm_input_function(file):

    def input_function():

        indexes_raw = []
        indicators_raw = []
        values_raw = []
        labels_raw = []
        i=0

        for line in open(file, "r"):
            data = line.split(" ")
            label = int(data[0])
            for fea in data[1:]:
                id, value = fea.split(":")
                indexes_raw.append([i,int(id)])
                indicators_raw.append(int(1))
                values_raw.append(float(value))
            labels_raw.append(label)
            i=i+1

        indexes = tf.SparseTensor(indices=indexes_raw,
                              values=indicators_raw,
                              dense_shape=[i, num_features])

        values = tf.SparseTensor(indices=indexes_raw,
                             values=values_raw,
                             dense_shape=[i, num_features])

        labels = tf.constant(labels_raw, dtype=tf.int32)

        return {"indexes": indexes, "values": values}, labels

    return input_function

However, for a dataset of a few GB size I get the following error:

ValueError: Cannot create a tensor proto whose content is larger than 2GB.

How can I avoid this error? How should I write an input function to read medium-sized sparse datasets (in libsvm format)?

2 Answers

When use estimator, for libsvm data input, you can create dense index list, dense value list, then use feature_column.categorical_column_with_identity and feature_column.weighted_categorical_column to create feature column, finally, put feature columns to estimator. Maybe your input features length is variable, you can use padded_batch to handle it. here some codes:

## here is input_fn
def input_fn(data_dir, is_training, batch_size):
    def parse_csv(value):
        ## here some process to create feature_indices list, feature_values list and labels
        return {"index": feature_indices, "value": feature_values}, labels

dataset = tf.data.Dataset.from_tensor_slices(your_filenames)

ds = dataset.flat_map(
    lambda f: tf.data.TextLineDataset(f).map(parse_csv)
)
ds = ds.padded_batch(batch_size, ds.output_shapes, padding_values=(
    {
        "index": tf.constant(-1, dtype=tf.int32),
        "value": tf.constant(0, dtype=tf.float32),
    },
    tf.constant(False, dtype=tf.bool)
))
return ds.repeat().prefetch(batch_size) 

## create feature column
def build_model_columns():
categorical_column = tf.feature_column.categorical_column_with_identity(
    key='index', num_buckets=your_feature_dim)
sparse_columns = tf.feature_column.weighted_categorical_column(
    categorical_column=categorical_column, weight_feature_key='value')
dense_columns = tf.feature_column.embedding_column(sparse_columns, your_embedding_dim)
return [sparse_columns], [dense_columns] 

## when created feature column, you can put them into estimator, eg. put dense_columns into DNN, and sparse_columns into linear model.

## for export savedmodel
def raw_serving_input_fn():
    feature_spec = {"index": tf.placeholder(shape=[None, None], dtype=tf.int32),
                    "value": tf.placeholder(shape=[None, None], dtype=tf.float32)}
    return tf.estimator.export.build_raw_serving_input_receiver_fn(feature_spec)

Another way, you can create your custom feature column, like this: _SparseArrayCategoricalColumn

I have been using tensorflow.contrib.libsvm. Here's an example (i am using eager execution with generators)

import os
import tensorflow as tf
import tensorflow.contrib.libsvm as libsvm


def all_libsvm_files(folder_path):
    for file in os.listdir(folder_path):
        if file.endswith(".libsvm"):
            yield os.path.join(folder_path, file)

def load_libsvm_dataset(path_to_folder):
    return tf.data.TextLineDataset(list(all_libsvm_files(path_to_folder)))


def libsvm_iterator(path_to_folder):
    dataset = load_libsvm_dataset(path_to_folder)
    iterator = dataset.make_one_shot_iterator()
    next_element = iterator.get_next()
    yield libsvm.decode_libsvm(tf.reshape(next_element, (1,)),
                               num_features=666,
                               dtype=tf.float32,
                               label_dtype=tf.float32)

libsvm_iterator gives you a feature-label pair back on each iteration, from multiple files inside a folder that you specify.

Related