在 Theano 中训练 MLP

Posted

技术标签:

【中文标题】在 Theano 中训练 MLP【英文标题】:Training MLP in Theano 【发布时间】:2016-12-07 03:08:03 【问题描述】:

我在尝试使用 Theano 训练一个非常标准的 MLP 模型时有点卡住了。我的模型代码是这样的

类层(对象): def __init__(自我,输入,n_in,n_out,激活=T.nnet.softmax): def 权重(形状): 返回 np.array(np.random.uniform(size=shape), dtype='float64') 定义偏差(大小): 返回 np.zeros((大小), 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 = 激活(T.dot(inputs, self.W) + self.b) self.pred = T.argmax(self.output, axis=1) self.params = [self.W, self.b] MLP 类(对象): def __init__(自我,输入,n_in,n_hidden,n_out): """ 现在让我们使用一个隐藏层""" self._hidden = 层(输入,n_in,n_hidden,激活=T.tanh) self._output = Layer(self._hidden.output, n_hidden, n_out) # 默认为softmax def loss(self, one_hot): 返回 T.mean(T.sqr(one_hot - self._output.output) def 精度(自我,y): 返回 T.mean(T.eq(self._output.pred, y)) def 更新(自我,损失,率=0.01): 更新 = [] 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))) 返回更新

然后我尝试像这样训练它

x = T.matrix('x', dtype='float64') y = T.vector('y', dtype='int32') # 基本逻辑模型 # model = Layer(x, 784, 10, activation=T.nnet.softmax) # 基本的多层感知器 模型 = MLP(x, 784, 128, 10) 标签 = T.extra_ops.to_one_hot(y, 10) # 损失函数 #loss = T.mean(T.sqr(labels - model.output)) 损失 = 模型损失(标签) # 一个批次的平均正确预测数 #accuracy = T.mean(T.eq(model.pred, y)) 准确度 = 模型.准确度(y) # 更新 #率 = 0.05 #g_W = T.grad(成本=损失,wrt=model.W) #g_b = T.grad(成本=损失,wrt=model.b) #updates = [(model.W, model.W - rate * g_W), # (model.b, model.b - rate * g_b)] 更新 = model.updates(损失,率 = 0.3) # 批次索引 index = T.scalar('批量索引', dtype='int32') size = T.scalar('批量大小', dtype='int32') train = theano.function([index, size], [损失,准确性], 更新=更新, givens=x: train_set[0][index * size: (index + 1) * size], y: train_set[1][index * size: (index + 1) * size]) 有效 = theano.function([索引, 大小], [损失,准确性], givens=x: valid_set[0][index * size: (index + 1) * size], y: valid_set[1][index * size: (index + 1) * size]) test = theano.function([index, size], [准确性], givens=x: test_set[0][index * size: (index + 1) * size], y: test_set[1][index * size: (index + 1) * size]) n_epochs = 10 批量大小 = 500 # 训练数据集中的项目数/批量大小 batches_in_epoch = datasets[0][0].shape[0] // batch_size 损失 = np.empty(0) 错误 = np.empty(0) 对于范围内的纪元(1,n_epochs + 1): epoch_losses = np.empty(0) epoch_errors = np.empty(0) 对于范围内的 batch_n(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(), '时代:',时代, '批次:',batch_n, '损失:', np.round(l, 4), '准确度:',np.round(e, 4)) # 在每个 epoch 洗牌训练集 shuffle = np.arange(数据集[0][1].shape[0]) np.random.shuffle(随机播放) train_set[0] = train_set[0][随机播放] train_set[1] = train_set[1][随机播放] loss = np.concatenate([losses, epoch_losses]) 错误= np.concatenate([错误,epoch_errors]) 有效_l,有效_e =有效(0,数据集[1][0].shape[0]) print('[%s]' % time.ctime(), 'epoch: ', epoch, '验证损失: ', valid_l, '验证准确度: ', valid_e) acc = test(0, datasets[2][0].shape[0]) 打印() print('最终精度:', np.round(acc, 4)[0])

现在,如果您查看 cmets,我使用基本的逻辑回归模型进行了尝试,并且成功了,我得到了大约 80% 的准确率。但是当我用我的 MLP 模型替换它时它不起作用。它不会收敛到任何东西,我得到 10% 准确率的随机猜测。我究竟做错了什么?我使用的数据是按照 Theano 教程的方式加载到共享变量中的 MNIST 数据集。

【问题讨论】:

网络的构建依赖于数据,但是对于输入维度为 784 的数据集,在隐藏层使用 128 个单元可能会有点低(这是一个很大的降维,可能会导致信息丢失)。也是很少有隐藏单元可能会阻止收敛。你可能想看看here 和here。我建议你从隐藏单元的高维开始,比如 1024 或 512,然后通过尝试小的值来调整它 我尝试了许多不同的配置,并且使用 128、256、512、1024 和 2048 得到了相同的结果。当我使用 Tensorflow 时,所有这些都收敛得很好。我得到不同的准确度,但即使有 128 个单位的隐藏层,我也能得到大约 97% 的准确度。 MNIST 不是一个难以分类的数据集。所以我怀疑这是我的 Theano 代码中的错误,而不是模型的问题。 【参考方案1】:

问题似乎在于权重初始化。您是如何在 tensorflow 实现中做到这一点的?

我现在不太确定基础数学,所以如果我错了请纠正我,但我喜欢将其解释为如果所有权重都是正的,则模型无法学习负特征。

您可以尝试将low=-1, high=1 添加到初始化中(np.random.uniform 的默认值介于 0 和 1 之间)。 在我的测试中,这需要很长时间才能收敛(约 100 个 epoch),但至少确实如此。

像这样使用更聪明的glorot initialization:

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

使训练更快。将其添加到您的代码中 5 个 epoch 后,我得到了大约 90% 的验证准确率。

这也是在theano MLP example 中初始化权重的方式。

【讨论】:

以上是关于在 Theano 中训练 MLP的主要内容,如果未能解决你的问题,请参考以下文章

在 Theano 中使用屏幕会话 - 竞争条件

tensorflow 在 GPU 内存上存储训练数据

GPU 在执行 Tensorflow 或 Theano 代码期间丢失

使用 theano 后端加载 keras 模型时出现断言错误

Theano学习笔记——逻辑回归函数解析

如何获取变量的当前值?