Pytorch:NN函数逼近器,2合1出

时间:2018-08-01 10:34:11

标签: neural-network pytorch

[由于主要问题陈述已更改,请注意下面的“编辑历史记录”。

我们正在尝试在pytorch中实现一个神经网络,该网络近似函数f(x,y)= z。因此,有两个实数作为输入,一个为输出,因此我们希望在输入层中有2个节点,在输出层中有一个节点。我们构建了一个包含5050个样本的测试集,并在具有Tensorflow后端的Keras中完成了该任务,效果很好,其中3个隐藏层的节点配置如下:2(in)-4-16-4-1(out);和ReLU激活功能在所有隐藏层上起作用,在输入和输出上呈线性。

现在在Pytorch中,我们尝试实现一个类似的网络,但是损失函数实际上仍在爆炸:它在前几个步骤中发生变化,然后收敛到大约10 ^ 7的某个值。在Keras,我们有大约10%的错误。我们已经尝试了不同的网络配置,而没有任何改进。也许有人可以看看我们的代码并提出任何建议?

要说明:tr_data是一个列表,包含5050个2 * 1 numpy数组,它们是网络的输入。 tr_labels是一个列表,包含5050个数字,这是我们要学习的输出。 loadData()仅加载这两个列表。

import torch.nn as nn
import torch.nn.functional as F

BATCH_SIZE     = 5050
DIM_IN         = 2
DIM_HIDDEN_1   = 4
DIM_HIDDEN_2   = 16
DIM_HIDDEN_3   = 4
DIM_OUT        = 1
LEARN_RATE     = 1e-4
EPOCH_NUM      = 500

class Net(nn.Module):
    def __init__(self):
        #super(Net, self).__init__()
        super().__init__()
        self.hidden1 = nn.Linear(DIM_IN, DIM_HIDDEN_1)
        self.hidden2 = nn.Linear(DIM_HIDDEN_1, DIM_HIDDEN_2)
        self.hidden3 = nn.Linear(DIM_HIDDEN_2, DIM_HIDDEN_3)
        self.out     = nn.Linear(DIM_HIDDEN_3, DIM_OUT)

    def forward(self, x):
        x = F.relu(self.hidden1(x))
        x = F.tanh(self.hidden2(x))
        x = F.tanh(self.hidden3(x))
        x = self.out(x)
        return x

model = Net()

loss_fn = nn.MSELoss(size_average=False)

optimizer = torch.optim.Adam(model.parameters(), lr=LEARN_RATE)

tr_data,tr_labels = loadData()

tr_data_torch    = torch.zeros(BATCH_SIZE, DIM_IN)
tr_labels_torch  = torch.zeros(BATCH_SIZE, DIM_OUT)

for i in range(BATCH_SIZE):
    tr_data_torch[i]   = torch.from_numpy(tr_data[i])
    tr_labels_torch[i] = tr_labels[i]

for t in range(EPOCH_NUM):

    labels_pred = model(tr_data_torch)
    loss = loss_fn(labels_pred, tr_labels_torch)
    #print(t, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

我不得不说,这些是我们在Pytorch迈出的第一步,所以如果有一些明显的愚蠢错误,请原谅我。感谢您的帮助或提示, 谢谢!

编辑1 --------------------------------------------- ---------------------

在评论和答案之后,我们改进了代码。现在,“损失”函数首次具有合理的值,约为250。我们的新类定义如下:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        #super().__init__()
        self.hidden1 = nn.Sequential(nn.Linear(DIM_IN, DIM_HIDDEN_1), nn.ReLU())
        self.hidden2 = nn.Sequential(nn.Linear(DIM_HIDDEN_1, DIM_HIDDEN_2), nn.ReLU())
        self.hidden3 = nn.Sequential(nn.Linear(DIM_HIDDEN_2, DIM_HIDDEN_3), nn.ReLU())
        self.out = nn.Linear(DIM_HIDDEN_3, DIM_OUT)

    def forward(self, x):
        x = self.hidden1(x)
        x = self.hidden2(x)
        x = self.hidden3(x)
        x = self.out(x)
        return x

和损失函数:

loss_fn = nn.MSELoss(size_average=True, reduce=True)

正如我们之前所说,在具有tensorflow后端的keras中,我们已经获得了令人满意的结果。丢失功能约为30,具有类似的网络配置。我在这里分享我们的keras代码的基本部分(!):

model = Sequential()
model.add(Dense(4, activation="linear", input_shape=(2,)))
model.add(Dense(16, activation="relu"))
model.add(Dense(4, activation="relu"))
model.add(Dense(1, activation="linear" ))
model.summary()

model.compile ( loss="mean_squared_error", optimizer="adam", metrics=["mse"] )

history=model.fit ( np.array(tr_data), np.array(tr_labels), \
                    validation_data = ( np.array(val_data), np.array(val_labels) ), 
                    batch_size=50, epochs=200, callbacks = [ cbk ] )

感谢您的所有帮助!如果还有人提出改善网络的建议,我们将为此感到高兴。正如有人已经要求数据一样,我们要在此处共享一个pickle文件:

https://mega.nz/#!RDYxSYLY!P4a9mEDtZ7A5Bl7ZRjRk8EzLXQt2gyURa3wN3NCWFPA

连同访问它的代码:

import pickle
f=open("data.pcl","rb")
tr_data=pickle.load ( f )
tr_labels=pickle.load ( f )
val_data=pickle.load ( f )
val_labels=pickle.load ( f )
f.close()

1 个答案:

答案 0 :(得分:0)

您应该指出torch.nntorch.nn.functional之间的区别(请参阅here)。从本质上讲,由于规格不同,反向传播图可能执行不正确100%。

正如以前的评论者所指出的,我建议定义包括激活的层。我个人最喜欢的方法是使用nn.Sequential(),它允许您指定链接在一起的多个操作,如下所示:

self.hidden1 = nn.Sequential(nn.Linear(DIM_IN, DIM_HIDDEN1), nn.ReLU())

,然后稍后简单地调用self.hidden1(而无需将其包装在F.relu()中)。

我也可以问一下为什么您不拨打带注释的super(Net, self).__init__()(这是通常推荐的方式)吗? 此外,如果那不能解决问题,您是否可以在比较中共享Keras的代码?