首页 > 解决方案 > model.evaluate() 根据批量大小改变结果,当由生成器提供时

问题描述

在 colab 中工作,使用默认的 tensorflow 和 keras 版本(打印 tensorflow 2.2.0-rc2, keras 2.3.0-tf )

我有一个超级奇怪的错误。基本上,model.evaluate() 的结果取决于我使用的批量大小,并且在我对数据进行洗牌后它们会发生变化。这没有任何意义。我已经能够在一个最低限度的工作示例中重现这一点。在我的完整程序(使用更大的数据集在 3D 中工作)中,变化更加显着。我不知道这是否可能取决于批量标准化......但我希望它在我预测时得到修复!我的完整程序正在进行多类分割,我的最小示例采用随机位置带有白色方块的黑色图像,并带有一些小噪声,并尝试从中分割出相同的白色方块。我使用 keras 序列作为生成器向模型提供数据,我想这可能是相关的,因为我在直接评估数据时看不到行为。

#environment setup
%tensorflow_version 2.x
from tensorflow.keras import backend as K
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input,Conv2D, Activation, BatchNormalization 
from tensorflow.keras import metrics

#set up a toy model
K.set_image_data_format("channels_last")
inputL = Input([64,64,1])
l1 = Conv2D(4,[3,3],padding='same')(inputL)
l1N = BatchNormalization(axis=-1,momentum=0.9) (l1)
l2 = Activation('relu') (l1N)
l3 = Conv2D(32,[3,3],padding='same')(l2)
l3N = BatchNormalization(axis=-1,momentum=0.9) (l3)
l4 = Activation('relu') (l3N)
l5 = Conv2D(1,[1,1],padding='same',dtype='float32')(l4)
l6 = Activation('sigmoid') (l5)
model = Model(inputs=inputL,outputs=l6)
model.compile(optimizer='sgd',loss='mse',metrics='accuracy' )

#Create random images
import numpy as np
import random
X_train = np.zeros([96,64,64,1])
for imIdx in range(96):
  centPoin = random.randrange(7,50)
  X_train[imIdx,centPoin-5:centPoin+5,centPoin-5:centPoin+5,0]=1

X_val = X_train[:32,:,:,:]
X_train = X_train[32:,:,:,:]
Y_train = X_train.copy()
X_train = np.random.normal(0.,0.1,size=X_train.shape)+X_train
for imIdx in range(64):
  X_train[imIdx,:,:,:] = X_train[imIdx,:,:,:]+np.random.normal(0,0.2,size=1)

from tensorflow.keras.utils import Sequence
import random
import tensorflow as tf

#setup the data generator
class dataGen (Sequence):
  def __init__ (self,x_set,y_set,batch_size):
    self.x, self.y = x_set, y_set
    self.batch_size = batch_size
    nSamples = self.x.shape[0]
    patList = np.array(range(nSamples),dtype='int16')
    patList = patList.reshape(nSamples,1)
    np.random.shuffle(patList)
    self.patList = patList

  def __len__ (self):
    return round(self.patList.shape[0] / self.batch_size)

  def __getitem__ (self, idx):
    patStart = idx
    batchS = self.batch_size
    listLen = self.patList.shape[0]
    Xout = np.zeros((batchS,64,64,1))
    Yout = np.zeros((batchS,64,64,1))    
    for patIdx in range(batchS):
       curPat = (patStart+patIdx) % listLen
       patInd = self.patList[curPat]
       Xout[patIdx,:,:] = self.x[patInd,:,:,:]
       Yout[patIdx,:,:] = self.y[patInd,:,:,:]
    return Xout, Yout

  def on_epoch_end(self):
    np.random.shuffle(self.patList)

  def setBatchSize(self,batchS):
    self.batch_size = batchS

#load the data in the generator
trainGen = dataGen(X_train,Y_train,16)
valGen = dataGen(X_val,X_val,16)

# train the model for two epochs, so that the loss is bad 
trainSteps = len(trainGen)
model.fit(trainGen,steps_per_epoch=trainSteps,epochs=32,validation_data=valGen,validation_steps=len(valGen))

trainGen.setBatchSize(4)
model.evaluate(trainGen)
[0.16259156167507172, 0.9870567321777344]

trainGen.setBatchSize(16)
model.evaluate(trainGen)
[0.17035068571567535, 0.9617958068847656]

trainGen.on_epoch_end()
trainGen.setBatchSize(16)
model.evaluate(trainGen)
[0.16663715243339539, 0.9710426330566406]

如果我这样做model.evaluate(Xtrain,Ytrain,batch_size=16),结果不依赖于批量大小。如果我训练模型直到收敛,损失达到 0.05,同样的事情仍然会发生。准确度从一种评估到另一种评估从 0.95 波动到 0.99。为什么会发生这种情况?我希望预测非常容易,我错了吗?

标签: pythontensorflowkerasdeep-learning

解决方案


__getitem__你在函数内部犯了一个小错误。

curPat = (patStart+patIdx)

应该改为

curPat = (patStart*batchS+patIdx)

patStart等于idx,当前批号。如果您的数据集包含 64 个样本并且批量大小设置为 16,则可能的值为idx0、1、2 和 3。

curPat另一方面是指当前样本编号在样本编号打乱列表中的索引。curPat因此应该能够采用从 0 到 63 的所有值。在您的代码中,情况并非如此。通过进行上述更改,此问题已得到解决。


推荐阅读