Tensorflow Sampled Softmax Loss Correct Usage
python, tensorflow
Solution
In your softmax layer you are multiplying your network predictions, which have dimension `(num_classes,)` by your `w` matrix which has dimension `(num_classes, num_hidden_1)`, so you end up trying to compare your target labels of size `(num_classes,)` to something that is now size `(num_hidden_1,)`. Change your tiny perceptron to output `layer_1` instead, then change the definition of your cost. The code below might do the trick.
def tiny_perceptron(x, weights, biases):
layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1'])
layer_1 = tf.nn.relu(layer_1)
return layer_1
layer_1 = tiny_perceptron(x, weights, biases)
loss_function = tf.reduce_mean(tf.nn.sampled_softmax_loss(
weights=weights['h1'],
biases=biases['b1'],
labels=labels,
inputs=layer_1,
num_sampled=num_sampled,
num_true=num_true,
num_classes=num_classes))
When you train your network with some optimizer, you will tell it to minimize `loss_function`, which should mean that it will adjust both sets of weights and biases.
Problem
In a classification problem with many classes, tensorflow docs suggests using sampled_softmax_loss over a simple softmax to reduce training runtime. According to the docs and source (line 1180), the call pattern for sampled_softmax_loss is: ``` tf.nn.sampled_softmax_loss(weights, # Shape (num_classes, dim) - floatXX biases, # Shape (num_classes) - floatXX labels, # Shape (batch_size, num_true) - int64 inputs, # Shape (batch_size, dim) - floatXX num_sampled, # - int num_classes, # - int num_true=1, sampled_values=None, remove_accidental_hits=True, partition_strategy="mod", name="sampled_softmax_loss") ``` It's unclear (at least to me) how to convert a real world problem into the shapes that this loss function requires. I think the 'inputs' field is the problem. Here is a copy-paste-ready minimum working example that throws a matrix multiplication shape error when calling the loss function. ``` import tensorflow as tf # Network Parameters n_hidden_1 = 256 # 1st layer number of features n_input = 784 # MNIST data input (img shape: 28*28) n_classes = 10 # MNIST total classes (0-9 digits) # Dependent & Independent Variable Placeholders x = tf.placeholder("float", [None, n_input]) y = tf.placeholder("float", [None, n_classes]) # # Weights and Biases weights = { 'h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])), 'out': tf.Variable(tf.random_normal([n_hidden_1, n_classes])) } biases = { 'b1': tf.Variable(tf.random_normal([n_hidden_1])), 'out': tf.Variable(tf.random_normal([n_classes])) } # Super simple model builder def tiny_perceptron(x, weights, biases): layer_1 = tf.add(tf.matmul(x, weights['h1']), biases['b1']) layer_1 = tf.nn.relu(layer_1) out_layer = tf.matmul(layer_1, weights['out']) + biases['out'] return out_layer # Create the model pred = tiny_perceptron(x, weights, biases) # Set up loss function inputs and inspect their shapes w = tf.transpose(weights['out']) b = biases['out'] labels = tf.reshape(tf.argmax(y, 1), [-1,1]) inputs = pred num_sampled = 3 num_true = 1 num_classes = n_classes print('Shapes\n------\nw:\t%s\nb:\t%s\nlabels:\t%s\ninputs:\t%s' % (w.shape, b.shape, labels.shape, inputs.shape)) # Shapes # ------ # w: (10, 256) # Requires (num_classes, dim) - CORRECT # b: (10,) # Requires (num_classes) - CORRECT # labels: (?, 1) # Requires (batch_size, num_true) - CORRECT # inputs: (?, 10) # Requires (batch_size, dim) - Not sure loss_function = tf.reduce_mean(tf.nn.sampled_softmax_loss( weights=w, biases=b, labels=labels, inputs=inputs, num_sampled=num_sampled, num_true=num_true, num_classes=num_classes)) ``` The final line triggers and ValueError, stating that you cant multiply tensors with shape (?,10) and (?,256). As a general rule, I'd agree with that statement. Full error shown below: ``` ValueError: Dimensions must be equal, but are 10 and 256 for 'sampled_softmax_loss_2/MatMul_1' (op: 'MatMul') with input shapes: [?,10], [?,256]. ``` If the 'dim' value from tensorflow docs is intended to be constant, either the 'weights' or 'inputs' variables going into the loss function are incorrect. Any thoughts would be awesome, I'm totally stumped on how to use this loss function correctly & it would have a huge impact on training time for the model we're using it for (500k classes). Thanks! ---EDIT--- It is possible to get the sample shown above to run without errors by playing with parameters and ignoring the `sampled_softmax_loss` call pattern's expected inputs. If you do that, it results in a trainable model that has 0 impact on prediction accuracy (as you would expect).