diff baseline_algorithms/mlp/mlp_nist.py @ 143:f341a4efb44a

added adaptive lr, weight file save, traine error and error curves
author XavierMuller
date Tue, 23 Feb 2010 18:08:11 -0500
parents 93b4b84d86cf
children 8ceaaf812891
line wrap: on
line diff
--- a/baseline_algorithms/mlp/mlp_nist.py	Tue Feb 16 17:12:35 2010 -0500
+++ b/baseline_algorithms/mlp/mlp_nist.py	Tue Feb 23 18:08:11 2010 -0500
@@ -30,6 +30,7 @@
 import theano.tensor as T
 import time 
 import theano.tensor.nnet
+import pylearn
 from pylearn.io import filetensor as ft
 
 data_path = '/data/lisa/data/nist/by_class/'
@@ -45,7 +46,7 @@
 
 
 
-    def __init__(self, input, n_in, n_hidden, n_out):
+    def __init__(self, input, n_in, n_hidden, n_out,learning_rate):
         """Initialize the parameters for the multilayer perceptron
 
         :param input: symbolic variable that describes the input of the 
@@ -94,8 +95,14 @@
         self.b2 = theano.shared( value = numpy.zeros((n_out,), 
                                                 dtype= theano.config.floatX))
 
+        #include the learning rate in the classifer so
+        #we can modify it on the fly when we want
+        lr_value=learning_rate
+        self.lr=theano.shared(value=lr_value)
         # symbolic expression computing the values of the hidden layer
         self.hidden = T.tanh(T.dot(input, self.W1)+ self.b1)
+        
+        
 
         # symbolic expression computing the values of the top layer 
         self.p_y_given_x= T.nnet.softmax(T.dot(self.hidden, self.W2)+self.b2)
@@ -103,6 +110,10 @@
         # compute prediction as class whose probability is maximal in 
         # symbolic form
         self.y_pred = T.argmax( self.p_y_given_x, axis =1)
+        self.y_pred_num = T.argmax( self.p_y_given_x[0:9], axis =1)
+        
+        
+        
         
         # L1 norm ; one regularization option is to enforce L1 norm to 
         # be small 
@@ -150,21 +161,9 @@
         else:
             raise NotImplementedError()
 
-#def jobman_mlp(state,channel):
-#    (validation_error,test_error,nb_exemples,time)=mlp_full_nist(state.learning_rate,\
- #                                                                state.n_iter,\
- #                                                                state.batch_size,\
- #                                                                state.nb_hidden_units)
- #   state.validation_error = validation_error
- #   state.test_error = test_error
- #   state.nb_exemples = nb_exemples
-  #  state.time=time
-   # return channel.COMPLETE
-
-
-                                                                 
 
 def mlp_full_nist(      verbose = False,\
+                        adaptive_lr = False,\
                         train_data = 'all/all_train_data.ft',\
                         train_labels = 'all/all_train_labels.ft',\
                         test_data = 'all/all_test_data.ft',\
@@ -178,6 +177,14 @@
                         nb_targets = 62):
    
     
+    configuration = [learning_rate,nb_max_exemples,nb_hidden,adaptive_lr]
+    
+    total_validation_error_list = []
+    total_train_error_list = []
+    learning_rate_list=[]
+    best_training_error=float('inf');
+    
+    
    
     f = open(data_path+train_data)
     g= open(data_path+train_labels)
@@ -235,11 +242,17 @@
     y = T.lvector()  # the labels are presented as 1D vector of 
                           # [long int] labels
 
+    if verbose==True:
+        print 'finished parsing the data'
     # construct the logistic regression class
     classifier = MLP( input=x.reshape((batch_size,32*32)),\
                         n_in=32*32,\
                         n_hidden=nb_hidden,\
-                        n_out=nb_targets)
+                        n_out=nb_targets,
+                        learning_rate=learning_rate)
+                        
+                        
+   
 
     # the cost we minimize during training is the negative log likelihood of 
     # the model plus the regularization terms (L1 and L2); cost is expressed
@@ -260,10 +273,10 @@
 
     # specify how to update the parameters of the model as a dictionary
     updates = \
-        { classifier.W1: classifier.W1 - learning_rate*g_W1 \
-        , classifier.b1: classifier.b1 - learning_rate*g_b1 \
-        , classifier.W2: classifier.W2 - learning_rate*g_W2 \
-        , classifier.b2: classifier.b2 - learning_rate*g_b2 }
+        { classifier.W1: classifier.W1 - classifier.lr*g_W1 \
+        , classifier.b1: classifier.b1 - classifier.lr*g_b1 \
+        , classifier.W2: classifier.W2 - classifier.lr*g_W2 \
+        , classifier.b2: classifier.b2 - classifier.lr*g_b2 }
 
     # compiling a theano function `train_model` that returns the cost, but in 
     # the same time updates the parameter of the model based on the rules 
@@ -273,13 +286,17 @@
 
    
    
+    
+   
    
    #conditions for stopping the adaptation:
    #1) we have reached  nb_max_exemples (this is rounded up to be a multiple of the train size)
-   #2) validation error is going up (probable overfitting)
+   #2) validation error is going up twice in a row(probable overfitting)
    
    # This means we no longer stop on slow convergence as low learning rates stopped
    # too fast. 
+   
+   # no longer relevant
     patience              =nb_max_exemples/batch_size
     patience_increase     = 2     # wait this much longer when a new best is 
                                   # found
@@ -296,9 +313,9 @@
     test_score           = 0.
     start_time = time.clock()
     n_iter = nb_max_exemples/batch_size  # nb of max times we are allowed to run through all exemples
-    n_iter = n_iter/n_minibatches + 1
+    n_iter = n_iter/n_minibatches + 1 #round up
     n_iter=max(1,n_iter) # run at least once on short debug call
-    # have a maximum of `n_iter` iterations through the entire dataset
+    
    
     if verbose == True:
         print 'looping at most %d times through the data set' %n_iter
@@ -307,7 +324,9 @@
         # get epoch and minibatch index
         epoch           = iter / n_minibatches
         minibatch_index =  iter % n_minibatches
-
+        
+      
+        
         # get the minibatches corresponding to `iter` modulo
         # `len(train_batches)`
         x,y = train_batches[ minibatch_index ]
@@ -317,7 +336,7 @@
 
         if (iter+1) % validation_frequency == 0: 
             # compute zero-one loss on validation set 
-           
+            
             this_validation_loss = 0.
             for x,y in validation_batches:
                 # sum up the errors for each minibatch
@@ -325,26 +344,40 @@
                 this_validation_loss += test_model(x_float,y)
             # get the average by dividing with the number of minibatches
             this_validation_loss /= len(validation_batches)
+            #save the validation loss
+            total_validation_error_list.append(this_validation_loss)
+            
+            #get the training error rate
+            this_train_loss=0
+            for x,y in train_batches:
+                # sum up the errors for each minibatch
+                x_float = x/255.0
+                this_train_loss += test_model(x_float,y)
+            # get the average by dividing with the number of minibatches
+            this_train_loss /= len(train_batches)
+            #save the validation loss
+            total_train_error_list.append(this_train_loss)
+            if(this_train_loss<best_training_error):
+                best_training_error=this_train_loss
+                
             if verbose == True:
-                print('epoch %i, minibatch %i/%i, validation error %f %%' % \
+                print('epoch %i, minibatch %i/%i, validation error %f, training error %f %%' % \
                     (epoch, minibatch_index+1, n_minibatches, \
-                        this_validation_loss*100.))
+                        this_validation_loss*100.,this_train_loss*100))
+                        
+                        
+            #save the learning rate
+            learning_rate_list.append(classifier.lr.value)
 
 
             # if we got the best validation score until now
             if this_validation_loss < best_validation_loss:
-
-                #improve patience if loss improvement is good enough
-                if this_validation_loss < best_validation_loss *  \
-                       improvement_threshold :
-                    patience = max(patience, iter * patience_increase)
-                elif verbose == True:
-                    print 'slow convergence stop'
-
                 # save best validation score and iteration number
                 best_validation_loss = this_validation_loss
                 best_iter = iter
-
+                # reset patience if we are going down again
+                # so we continue exploring
+                patience=nb_max_exemples/batch_size
                 # test it on the test set
                 test_score = 0.
                 for x,y in test_batches:
@@ -357,33 +390,40 @@
                                 (epoch, minibatch_index+1, n_minibatches,
                                 test_score*100.))
                                 
-            #if the validation error is going up, we are overfitting
-            #stop converging
-            elif this_validation_loss > best_validation_loss:
+            # if the validation error is going up, we are overfitting (or oscillating)
+            # stop converging but run at least to next validation
+            # to check overfitting or ocsillation
+            # the saved weights of the model will be a bit off in that case
+            elif this_validation_loss >= best_validation_loss:
                 #calculate the test error at this point and exit
                 # test it on the test set
-                if verbose==True:
-                    print ' We are diverging'
-                best_iter = iter
+                # however, if adaptive_lr is true, try reducing the lr to
+                # get us out of an oscilliation
+                if adaptive_lr==True:
+                    classifier.lr.value=classifier.lr.value/2.0
+
                 test_score = 0.
+                #cap the patience so we are allowed one more validation error
+                #calculation before aborting
+                patience = iter+validation_frequency+1
                 for x,y in test_batches:
                     x_float=x/255.0
                     test_score += test_model(x_float,y)
                 test_score /= len(test_batches)
                 if verbose == True:
-                    print ' validation error is going up, stopping now'
+                    print ' validation error is going up, possibly stopping soon'
                     print(('     epoch %i, minibatch %i/%i, test error of best '
                         'model %f %%') % 
                                 (epoch, minibatch_index+1, n_minibatches,
                                 test_score*100.))
                                 
-                break
+                
 
 
-            
-            if patience <= iter :
-               break 
-        
+        if iter>patience:
+            print 'we have diverged'
+            break
+
 
     end_time = time.clock()
     if verbose == True:
@@ -391,17 +431,25 @@
             'obtained at iteration %i, with test performance %f %%') %  
                     (best_validation_loss * 100., best_iter, test_score*100.))
         print ('The code ran for %f minutes' % ((end_time-start_time)/60.))
-    print iter
-    return (best_validation_loss * 100.,test_score*100.,best_iter*batch_size,(end_time-start_time)/60)
+        print iter
+        
+    #save the model and the weights
+    numpy.savez('model.npy', config=configuration, W1=classifier.W1.value,W2=classifier.W2.value, b1=classifier.b1.value,b2=classifier.b2.value)
+    numpy.savez('results.npy',config=configuration,total_train_error_list=total_train_error_list,total_validation_error_list=total_validation_error_list,\
+    learning_rate_list=learning_rate_list)
+    
+    return (best_training_error*100.0,best_validation_loss * 100.,test_score*100.,best_iter*batch_size,(end_time-start_time)/60)
 
 
 if __name__ == '__main__':
     mlp_full_mnist()
 
 def jobman_mlp_full_nist(state,channel):
-    (validation_error,test_error,nb_exemples,time)=mlp_full_nist(learning_rate=state.learning_rate,\
+    (train_error,validation_error,test_error,nb_exemples,time)=mlp_full_nist(learning_rate=state.learning_rate,\
                                                                 nb_max_exemples=state.nb_max_exemples,\
-                                                                nb_hidden=state.nb_hidden)
+                                                                nb_hidden=state.nb_hidden,\
+                                                                adaptive_lr=state.adaptive_lr)
+    state.train_error=train_error
     state.validation_error=validation_error
     state.test_error=test_error
     state.nb_exemples=nb_exemples