Map network symbol input names when using CSVIter


#1

Hi Guys,

X_train = mx.io.NDArrayIter({'var1': var1_vals_array, 
                             'var2': var2_vals_array},
...)

model = mx.module.Module(context=[mx.cpu()], 
                         data_names=('var1',  'var2'), 
                         symbol=get_symbol())

If I replace X_train with a CSVIter, how can I map say column 1 is var1 and column 2 is var2?

Thanks!


#2

Hi @robert,

CSVIter returns batches that have data and label properties, where the data will be an NDArray of the number of columns in your data CSV. So you can either slice each column as part of your symbol, using slice, or implement your own custom iterator that returns multiple data objects. Check out the tutorial here for an example of how this is done.


#3

Hi @thomelane,

Thanks for your help. When I use the slice_axis operator I got some errors:

test.csv
1,2,1
1,3,0
1,4,0
1,5,0
2,3,1
2,2,0
2,3,0

The first column is member id, the second column is movie id, the third column is class label

def simple_mf_net(n_users, n_items):

    data = mx.symbol.Variable("data")
    
    #  used to be mx.symbol.Variable("softmax_label")
    y_true = mx.symbol.slice_axis(data, axis=1, begin=2, end=3)

    # used to be mx.symbol.Variable("member")
    user = mx.symbol.slice_axis(data, axis=1, begin=0, end=1)
    
    user = mx.symbol.Embedding(name='member_embedding',
            data=user, input_dim=n_users, output_dim=64)

    # used to be mx.symbol.Variable("movie")
    movie = mx.symbol.slice_axis(data, axis=1, begin=1, end=2) 
    
    movie = mx.symbol.Embedding(name='movie_embedding',
            data=movie, input_dim=n_items, output_dim=64)

    dot = user * movie
    dot = mx.symbol.sum_axis(dot, axis=1)
    dot = mx.symbol.Flatten(dot)

    return mx.symbol.LinearRegressionOutput(data=dot, label=y_true)

n_users = 2
n_movies = 4
model = mx.module.Module(context=[mx.cpu()], 
                         symbol=simple_mf_net(n_users, n_movies))

csv_iter = mx.io.CSVIter(data_csv = 'test.csv', data_shape = (3,), batch_size = 7)

model.fit(csv_iter, 
          num_epoch=1, 
          eval_metric=['rmse'], 
          optimizer='adam') 

I got the following errors:

...
RuntimeError: simple_bind error. Arguments:
    data: (7, 3)
    softmax_label: (7,)
    Error in operator linearregressionoutput17: Shape inconsistent, Provided=[7,1], inferred shape=[7,64]

I’m not sure which operator I should be using here: slice_axis or slice? Basically I’d like
the ‘user’ variable uses the first column in the csv file
the ‘movie’ variable uses the second column
the ‘y_true’ variable uses the third column

Thanks!


#4

@robert Do you really need to use the module API? This would be 100 times easier, cleaner, and faster with Gluon and some CSV reader (like np.loadtxt or np.genfromtxt). CSVIter is really written for a classification case where your labels are stored in a separate file. If you really have to, here is a code that works:

def simple_mf_net(n_users, n_items):
    data = mx.symbol.Variable("data")
    label = mx.symbol.Variable("softmax_label")

    y_true = mx.symbol.slice_axis(label, axis=1, begin=2, end=3, name='y_true')

    # used to be mx.symbol.Variable("member")
    user = mx.symbol.slice_axis(data, axis=1, begin=0, end=1)

    user = mx.symbol.Embedding(name='member_embedding',
                               data=user, input_dim=n_users, output_dim=64)

    # used to be mx.symbol.Variable("movie")
    movie = mx.symbol.slice_axis(data, axis=1, begin=1, end=2)

    movie = mx.symbol.Embedding(name='movie_embedding',
                                data=movie, input_dim=n_items, output_dim=64)

    dot = user * movie
    dot = mx.sym.FullyConnected(dot, num_hidden=1)
    dot = mx.symbol.sum(dot, axis=1)
    dot = mx.symbol.Flatten(dot)

    return mx.symbol.LinearRegressionOutput(data=dot, label=y_true)


n_users = 2
n_movies = 4
model = mx.module.Module(context=[mx.cpu()],
                         symbol=simple_mf_net(n_users, n_movies))

csv_iter = mx.io.CSVIter(data_csv='test.csv', data_shape=(3,), label_csv='test.csv', label_shape=(3,), batch_size=7)

model.fit(csv_iter,
          num_epoch=1,
          eval_metric=['rmse'],
          optimizer='adam')

#5

@safrooze Thanks so much! I now understood how to use the CSVIter in my case.

It now returns the following error:

RuntimeError: simple_bind error. Arguments:
    data: (7, 3)
    softmax_label: (7, 3)
    Error in operator linearregressionoutput14: Shape inconsistent, Provided=[7,1], inferred shape=[7,64]

I don’t have to use the Module API, but I’m not very familiar with the Gluon interface. Can I reuse the same network symbol when using Gluon? Is there an example that I can study? Thanks!


#6

Yes you can move your network symbol to Gluon (using SymbolBlock), however I recommend to simply re-create your network in Gluon (it is soooo easy). Best place to start with Gluon is 60-minute Gluon Crash Course. The online book of Deep Learning - The straight dope is a great place to find a wide range of tutorials for different applications. Also the Apache MXNet Tutorials page is an incredible resource for introductory and advanced tutorials on many topics that Gluon users may have difficulty with.


#7

Thanks Sina, really appreciate your help.