2016-08-01 5 views
0

Я немного застреваю, пытаясь обучить довольно стандартную модель MLP с помощью Theano. Мой код модели выглядит следующим образомТренировка MLP в 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 

Затем я пытаюсь обучить его, как этот

 
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]) 

Теперь, если вы посмотрите на комментарии, я попробовал его с базовой модели логистической регрессии, и она работала, Я получил около 80% точности. Но это не работает, когда я заменяю его своей моделью MLP. Это не сходится ни к чему, и я получаю 10% -ные случайные догадки. Что я делаю не так? Данные, которые я использую, представляют собой набор данных MNIST, загружаемый в общие переменные, как это делают учебные пособия по Anano.

+0

Строительство сети зависит от данных, но использование 128 единиц в скрытом слое для набора данных с входным размером 784 может быть немного низким (это большое уменьшение размерности и может привести к потере информации). Несколько скрытых блоков могут помешать конвергенция. Вы можете посмотреть [здесь] (http://stackoverflow.com/questions/10565868/multi-layer-perceptron-mlp-architecture-criteria-for-choosing-number-of-hidde) и [здесь] (ftp : //ftp.sas.com/pub/neural/FAQ3.html#A_hu). Я предлагаю вам начать с высокого размера скрытых единиц, скажем, 1024 или 512, а затем настроить его позже, попробовав небольшие значения – MGoksu

+0

I попробовали множество различных конфигураций, и я получаю тот же результат с 128, 256, 512, 1024 и 2048. И все это сходится для меня отлично, когда я делаю это с Tensorflow. Я получаю разную точность, но даже с 128 скрытым слоем я получаю около 97% точности. MNIST не является сложным набором данных для классификации. Поэтому я подозреваю, что это ошибка в коде Theano, а не проблема с моделью. –

ответ

0

Проблема, похоже, заключается в инициализации веса. Как вы это сделали в своей реализации tensorflow?

Я не слишком уверен в основополагающей математике прямо сейчас, так что поправьте меня, если я ошибаюсь, но мне нравится интерпретировать его так, как если бы все веса были положительными, модель не может узнать отрицательные черты.

Вы можете попробовать добавить low=-1, high=1 к инициализации (по умолчанию np.random.uniform находится между 0 и 1). В моих тестах это заняло довольно много времени, чтобы сходиться (~ 100 эпох), но, по крайней мере, это произошло.

Используя несколько умнее glorot initialization так:

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

делает обучение намного быстрее. Я получил около 90% точности проверки после 5 эпох, добавляя это к вашему коду.

Это также способ инициализации весов в theano MLP example.