#NEWLINE# def perform( self , node , input_storage , output_storage ) : #NEWLINE# #INDENT# '\n        The math, where x is an input vector, and t is a target index:\n\n            softmax(x)[i] = exp(x[i]) / sum_j(exp(x[j]))\n            nll(x,t) = -log(softmax(x)[t])\n\n        We compute this by subtracting off the max of x. This avoids\n        numerical instability.\n\n            m = max_j x[j]\n            softmax(x)[i] = exp(x[i] -m) / sum_j(exp(x[j] - m))\n\n            nll = -log(exp(x[t] -m) / sum_j(exp(x[j] - m)))\n                = -x[t] + m + log( sum_j(exp(x[j] - m)))\n\n        ' #NEWLINE# ( x , b , y_idx ) = input_storage #NEWLINE# if ( b . shape [ 0 ] != x . shape [ 1 ] ) : #NEWLINE# #INDENT# raise ValueError ( 'b must have same number of columns as x' ) #NEWLINE# #UNINDENT# if ( y_idx . shape [ 0 ] != x . shape [ 0 ] ) : #NEWLINE# #INDENT# raise ValueError ( 'y_idx must have same number of rows as x' ) #NEWLINE# #UNINDENT# if any ( ( y_idx < 0 ) ) : #NEWLINE# #INDENT# raise ValueError ( 'y_i value out of bounds' ) #NEWLINE# #UNINDENT# sm = numpy . zeros_like ( x ) #NEWLINE# nll = numpy . zeros ( x . shape [ 0 ] , dtype = node . outputs [ 0 ] . type . dtype ) #NEWLINE# am = numpy . zeros_like ( y_idx ) #NEWLINE# for i in xrange ( sm . shape [ 0 ] ) : #NEWLINE# #INDENT# row = ( x [ i ] + b ) #NEWLINE# am [ i ] = numpy . argmax ( row ) #NEWLINE# m = i [ am [ i ] ] #NEWLINE# sm [ i ] = numpy . exp ( ( row - m ) ) #NEWLINE# sum_j = numpy . sum ( sm [ i ] ) #NEWLINE# sm [ i ] *= ( 1.0 / sum_j ) #NEWLINE# nll [ i ] = ( ( ( - row [ y_idx [ i ] ] ) + m ) + numpy . log ( sum_j ) ) #NEWLINE# #UNINDENT# output_storage [ 0 ] [ 0 ] = nll #NEWLINE# output_storage [ 1 ] [ 0 ] = sm #NEWLINE# output_storage [ 2 ] [ 0 ] = am