在神经网络中使用model.eval()导致每次对非常不同的输入产生相同输出

我有一个用pytorch实现的简单网络,比如,

class network:    def __init__(self):        self.device = device        #这些是3个卷积突触;相同的卷积;        self.layer     = sequential(                                conv2d(3, 3, (23), padding=11),                                batch_norm_2d(3),                                Swish(),                                        conv2d(3, 3, (11), padding=5),                                batch_norm_2d(3),                                Swish(),                                        conv2d(3, 3, (5), padding=2),                                batch_norm_2d(3),                                Swish(),                                conv2d(3, 4, (3), padding=15, stride=2),                                batch_norm_2d(4),                                Swish(),                                        conv2d(4, 8, (3), padding=15, stride=2),                                batch_norm_2d(8),                                Swish(),                                        conv2d(8, 4, (1)),                                batch_norm_2d(4),                                Swish(),                                        conv2d(4, 8, (3), padding=15, stride=2),                                batch_norm_2d(8),                                Swish(),                                                        conv2d(8, 16, (3), padding=15, stride=2),                                batch_norm_2d(16),                                Swish(),                                        conv2d(16, 8, (1)),                                batch_norm_2d(8),                                Swish(),                                        conv2d(8, 16, (3), padding=15, stride=2),                                batch_norm_2d(16),                                Swish(),                                                        conv2d(16, 32, (3), padding=15, stride=2),                                batch_norm_2d(32),                                Swish(),                                        conv2d(32, 16, (1)),                                batch_norm_2d(16),                                Swish(),                                        conv2d(16, 32, (3), padding=15, stride=2),                                batch_norm_2d(32),                                Swish(),                                                        conv2d(32, 64, (3), padding=15, stride=2),                                batch_norm_2d(64),                                Swish(),                                        conv2d(64, 32, (1)),                                batch_norm_2d(32),                                Swish(),                                        conv2d(32, 64, (3), padding=15, stride=2),                                batch_norm_2d(64),                                Swish(),                                                        conv2d(64, 128, (3), padding=15, stride=2),                                batch_norm_2d(128),                                Swish(),                                        conv2d(128, 64, (1)),                                batch_norm_2d(64),                                Swish(),                                        conv2d(64, 128, (3), padding=15, stride=2),                                batch_norm_2d(128),                                Swish(),                                                        conv2d(128, 256, (3), padding=15, stride=2),                                batch_norm_2d(256),                                Swish(),                                        conv2d(256, 128, (1)),                                batch_norm_2d(128),                                Swish(),                                                                flatten(1, -1),                                        linear(128*29*29, 8*8*2*5),                                batch_norm_1d(8*8*2*5),                                Swish()            )                #损失和优化器函数用于ethirun        self.Loss_1 = IoU_Loss() #用于边界框的损失函数        self.Loss_2 = tor.nn.SmoothL1Loss(reduction='mean')            #优化器        self.Optimizer =     tor.optim.AdamW(self.parameters())#tor.optim.SGD(self.parameters(), lr=1e-2, momentum=0.9, weight_decay=1e-5, nesterov=True)        self.Scheduler = tor.optim.lr_scheduler.StepLR(self.Optimizer, 288, gamma=0.5)        self.sizes = tor.tensor(range(0, 5), dtype=tor.int64, device=self.device)    def forward(self, input):         return self.layer(input)    def backprop(self, preds, lbls, val_or_trn):    #接受预测和标签并计算误差并反向传播                 mask = tor.index_select(lbls, -1, self.sizes[0])         preds.register_hook(lambda grad: grad * mask.float())         error = self.Loss_2(preds, lbls)                 if val_or_trn == 1:             #反向传播             error.backward()             self.Optimizer.step()             self.Scheduler.step()                     #将梯度归零             self.Optimizer.zero_grad()            return error.detach()model = network()

其中的输入、输出和通道都是任意的。假设我创建一个随机输入张量,如下所示,

input_data = torch.randn(1, 3, 256, 256)

然后我在这些数据中进行预测,如下所示,

model(input_data)

假设我还通过多次初始化torch.randn命令来改变input_data变量,同时保持模型不变。也就是说,不重新初始化model=network()命令。

我得到了这个错误,

训练时每个通道期望超过1个值,得到的输入大小为torch.Size([1, some_value])

因此,我尝试通过使用model.eval()函数以评估模式运行它,如下所示,

model.eval()with tor.no_grad()   pred = model(input_data)model.train()

这样做没有错误。然而,无论我如何改变input_data变量,我在pred中总是得到相同的值。但是,如果我重新初始化模型的参数,我会得到一个新的pred,它再次不会随着不同的输入而改变。除非我再次使用model=network()重新初始化模型。我做错了什么?

编辑:为了提供更多关于我的问题的信息,我正在尝试从头开始创建一个类似yolo的网络。这是我正在使用的数据集 https://www.kaggle.com/devdgohil/the-oxfordiiit-pet-dataset


回答:

基本上这就是Batchnorm在做的事情。你使用Batchnorm来使训练不太容易过拟合,但在评估中不要使用batchnorm,以便你能得到正确的结果。Dropout也是如此。

每个带有批量归一化和/或dropout的CNN模型都会这样做。在训练和评估期间,相同输入的输出会有所不同

这正是Pytorch具有model.eval()的原因。在推理期间关闭这些层以获得正确输出。

编辑

问题出在输出处的激活和批量归一化。

只使用那些能使结果与真实值相似的函数。比如,当你希望输出在0到1的范围内时使用sigmoid,当希望在-1到1范围内时使用tanh,当希望在轴上概率分布时使用softmax

想象一下relu函数(它基本上是swishsoftplus的简化版本)。它会将所有低于0的值变成0。而你可能需要一些输出低于0的值,所以你的模型根本不会收敛。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注