2016-08-01 24 views
0

Ich bin ein bisschen stecken, versucht, ein ziemlich Standard-MLP-Modell mit Theano zu trainieren. Mein Modell-Code sieht wie folgt ausTraining MLP in Theano

 
class Layer(object): 
    def __init__(self, inputs, n_in, n_out, activation=T.nnet.softmax): 
     def weights(shape): 
      return np.array(np.random.uniform(size=shape), dtype='float64') 
     def biases(size): 
      return np.zeros((size), dtype='float64') 

     self.W = theano.shared(value=weights((n_in, n_out)), name='weights', borrow=True) 
     self.b = theano.shared(value=biases(n_out), name='biases', borrow=True) 
     self.output = activation(T.dot(inputs, self.W) + self.b) 
     self.pred = T.argmax(self.output, axis=1) 
     self.params = [self.W, self.b] 

class MLP(object): 
    def __init__(self, inputs, n_in, n_hidden, n_out): 
     """ for now lets go with one hidden layer""" 
     self._hidden = Layer(inputs, n_in, n_hidden, activation=T.tanh) 
     self._output = Layer(self._hidden.output, n_hidden, n_out) # softmax by default   
    def loss(self, one_hot): 
     return T.mean(T.sqr(one_hot - self._output.output)  
    def accuracy(self, y): 
     return T.mean(T.eq(self._output.pred, y))  
    def updates(self, loss, rate=0.01): 
     updates = [] 
     updates.append((self._hidden.W, self._hidden.W - rate * T.grad(cost=loss, wrt=self._hidden.W))) 
     updates.append((self._hidden.b, self._hidden.b - rate * T.grad(cost=loss, wrt=self._hidden.b))) 
     updates.append((self._output.W, self._output.W - rate * T.grad(cost=loss, wrt=self._output.W))) 
     updates.append((self._output.b, self._output.b - rate * T.grad(cost=loss, wrt=self._output.b))) 
     return updates 

Dann versuche ich es wie diese

 
x = T.matrix('x', dtype='float64') 
y = T.vector('y', dtype='int32') 

# basic logistic model 
# model = Layer(x, 784, 10, activation=T.nnet.softmax) 
# basic multi-layer perceptron 
model = MLP(x, 784, 128, 10) 

labels = T.extra_ops.to_one_hot(y, 10) 
# loss function 
#loss = T.mean(T.sqr(labels - model.output)) 
loss = model.loss(labels) 
# average number of correct predictions over a batch 
#accuracy = T.mean(T.eq(model.pred, y)) 
accuracy = model.accuracy(y) 

# updates 
#rate = 0.05 
#g_W = T.grad(cost=loss, wrt=model.W) 
#g_b = T.grad(cost=loss, wrt=model.b) 
#updates = [(model.W, model.W - rate * g_W), 
#   (model.b, model.b - rate * g_b)] 
updates = model.updates(loss, rate=0.3) 

# batch index 
index = T.scalar('batch index', dtype='int32') 
size = T.scalar('batch size', dtype='int32') 

train = theano.function([index, size], 
         [loss, accuracy], 
         updates=updates, 
         givens={x: train_set[0][index * size: (index + 1) * size], 
           y: train_set[1][index * size: (index + 1) * size]}) 

valid = theano.function([index, size], 
         [loss, accuracy], 
         givens={x: valid_set[0][index * size: (index + 1) * size], 
           y: valid_set[1][index * size: (index + 1) * size]}) 

test = theano.function([index, size], 
         [accuracy], 
         givens={x: test_set[0][index * size: (index + 1) * size], 
           y: test_set[1][index * size: (index + 1) * size]}) 

n_epochs = 10 
batch_size = 500 
# number of items in training dataset/batch size 
batches_in_epoch = datasets[0][0].shape[0] // batch_size 

losses = np.empty(0) 
errors = np.empty(0) 

for epoch in range(1, n_epochs + 1): 
    epoch_losses = np.empty(0) 
    epoch_errors = np.empty(0) 
    for batch_n in range(batches_in_epoch): 
     l, e = train(batch_n, batch_size) 
     epoch_losses = np.append(epoch_losses, l) 
     epoch_errors = np.append(epoch_errors, e) 
     print('[%s]' % time.ctime(), 
       'epoch: ', epoch, 
       'batch: ', batch_n, 
       'loss: ', np.round(l, 4), 
       'accuracy: ', np.round(e, 4)) 
    # shuffle train set every epoch 
    shuffle = np.arange(datasets[0][1].shape[0]) 
    np.random.shuffle(shuffle) 
    train_set[0] = train_set[0][shuffle] 
    train_set[1] = train_set[1][shuffle] 

    losses = np.concatenate([losses, epoch_losses]) 
    errors = np.concatenate([errors, epoch_errors]) 
    valid_l, valid_e = valid(0, datasets[1][0].shape[0]) 
    print('[%s]' % time.ctime(), 'epoch: ', epoch, 'validation loss: ', valid_l, 'validation accuracy: ', valid_e) 

acc = test(0, datasets[2][0].shape[0]) 
print() 
print('Final accuracy: ', np.round(acc, 4)[0]) 

Nun zu trainieren, wenn man sich die Kommentare sieht, versuchte ich es mit einem grundlegenden logistischen Regressionsmodell und es funktionierte, Ich habe eine Genauigkeit von 80%. Aber es funktioniert nicht, wenn ich es durch mein MLP-Modell ersetze. Es konvergiert zu nichts und ich bekomme zufällige Vermutungen mit 10% Genauigkeit. Was mache ich falsch? Die Daten, die ich benutze, sind das MNIST-Dataset, das wie bei Theano-Tutorials in Shared-Variablen geladen wird.

+0

Der Aufbau des Netzwerks hängt von den Daten ab, aber die Verwendung von 128 Einheiten in der versteckten Ebene für einen Datensatz mit der Eingabegröße 784 ist möglicherweise etwas niedrig (das ist eine große Dimensionsreduktion und kann zu Informationsverlust führen) Konvergenz. Vielleicht möchten Sie [hier] (http://stackoverflow.com/questions/10565868/multi-layer-perceptron-mlp-architecture-criteria-for-choosing-number-of-hidde) und [hier] (ftp : //ftp.sas.com/pub/neural/FAQ3.html#A_hu). Ich würde vorschlagen, dass Sie mit einer hohen Dimension von versteckten Einheiten beginnen, sagen wir, 1024 oder 512, dann tunen Sie es später, indem Sie kleine Werte ausprobieren – MGoksu

+0

I habe viele verschiedene Konfigurationen ausprobiert und ich bekomme das gleiche Ergebnis mit 128, 256, 512, 1024 und 2048. Und all diese konvergieren gut für mich, wenn ich es mit Tensorflow mache. Ich erhalte unterschiedliche Genauigkeiten, aber selbst mit 128 Einheiten versteckter Ebene erreiche ich eine Genauigkeit von 97%. MNIST ist kein schwieriger zu klassifizierender Datensatz. Ich vermute also, dass dies ein Fehler in meinem Theano-Code ist und kein Problem mit dem Modell. –

Antwort

0

Das Problem scheint innerhalb der Gewichtsinitialisierung zu liegen. Wie haben Sie das in Ihrer Tensorflow-Implementierung gemacht?

Ich bin mir nicht sicher über die zugrunde liegende Mathe jetzt so korrigieren Sie mich, wenn ich falsch liege, aber ich mag es zu interpretieren, wenn alle Gewichte positiv sind, das Modell negative Eigenschaften zu lernen.

Sie können versuchen, low=-1, high=1 zur Initialisierung hinzuzufügen (der Standardwert np.random.uniform liegt zwischen 0 und 1). In meinen Tests dauerte es ziemlich lange, um zu konvergieren (~ 100 Epochen), aber zumindest tat es.

die etwas schlauer glorot initialization wie folgt aus:

def weights(shape): 
    return np.random.uniform(low=-np.sqrt(6./sum(shape)), 
          high=np.sqrt(6./sum(shape)), 
          size=shape) 

macht das Training viel schneller. Ich habe ungefähr 90% Validierungsgenauigkeit nach 5 Epochen, die das zu Ihrem Code hinzufügen.

Dies ist auch die Art, wie Gewichte in der theano MLP example initialisiert werden.