Keras、PyTorch和Numpy中的批量标准化是不同的

Keras、PyTorch和Numpy中的批量标准化是不同的,numpy,tensorflow,machine-learning,keras,pytorch,Numpy,Tensorflow,Machine Learning,Keras,Pytorch,我在Keras、PyTorch中创建了BatchNormalization层,并使用Numpy计算了相同的操作,但得到了三个不同的结果。我是不是犯了什么错误 我在下面假设:layer.get_weights()intf.kerasfor BN layer返回顺序为gamma、beta、running\u mean、running\u var。对于BN操作,我使用以下操作:gamma*(x-running\u mean)/sqrt(running\u var+epsilon)+beta 重现问题的

我在Keras、PyTorch中创建了BatchNormalization层,并使用Numpy计算了相同的操作,但得到了三个不同的结果。我是不是犯了什么错误

我在下面假设:
layer.get_weights()
in
tf.keras
for BN layer返回顺序为
gamma、beta、running\u mean、running\u var
。对于BN操作,我使用以下操作:
gamma*(x-running\u mean)/sqrt(running\u var+epsilon)+beta

重现问题的代码段:

导入火炬
输入张量流
来自torch.nn导入模块,BatchNorm1d,Conv1d
来自torch.nn.功能导入垫
将numpy作为np导入
从tensorflow.keras.layers导入Conv1D、BatchNormalization、Input
从tensorflow.keras.models导入模型
torch.backends.cudnn.deterministic=True
np.random.seed(12345)
z=输入((1024,8),dtype=np.float32)
inp=z
z=Conv1D(64,16,padding='same',使用_bias=False)(z)
z=批次标准化(ε=0.001)(z)
keras_模型=模型(inp,z)
#顺序:conv层重量、伽马、贝塔、运行平均值、运行变量
权重=[np.random.random((16,8,64)),np.random.random((64,),np.random.random((64,)),np.random.random((64,),
np.random.random((64,))]
权重=[np.array(x,dtype=np.float32)表示权重中的x]
keras_模型。层[1]。设置_权重([weights[0]])
keras_模型。层[2]。设置_权重(权重[1:])
keras_模型子部分=模型(keras_模型.输入,keras_模型.层[1].输出)
类TorchModel(模块):
定义初始化(自):
超级(TorchModel,self)。\uuuu init\uuuuu()
self.l1=Conv1d(8,64,16,偏差=False)
self.l2=BatchNorm1d(64,0.001)
def前进(自身,x):
x=焊盘(x,(7,8))
x=自我。l1(x)
y=x
x=self.l2(x)
返回y,x
torch_model=TorchModel().to(torch.device('cpu'))
torch_model.l1.weight.data=torch.from_numpy(权重[0].T).float()
torch_model.l2.weight.data=torch.from_numpy(weights[1].T).float()
torch_model.l2.bias.data=torch.from_numpy(权重[2]).float()
火炬_model.l2.running _mean=火炬_numpy(重量[3])。浮动()
火炬_model.l2.running _var=火炬_numpy(重量[4]).float()
torch_model.eval()
input_value=np.array(np.random.random((1024,8)),dtype=np.float32)
keras_结果=[np.数组(keras_模型_子部分.预测(输入_值[np.newaxis,:,:]),
数组(keras_模型.predict(输入_值[np.newaxis,:,:])]
使用手电筒。无梯度()
torch_results=[x.detach().numpy(),用于torch_模型中的x(torch.from_numpy(input_value.T[np.newaxis,:,:]).float())]
keras_结果=[keras_结果中x的np.挤压(x)]
torch_结果=[np.torch_结果中x的挤压(x)]
numpy_结果=权重[1]*(keras_结果[0]-权重[3])/np.sqrt(权重[4]+0.001)+权重[2]
打印(torch.\uuuuuuu版本,tensorflow.\uuuuu版本,np.\uuuuu版本,sep=“,”))
打印('\n结果:')
打印('\T第1层差异:',np.mean(np.abs(keras_结果[0]-torch_结果[0].T).flatten())
打印('\T第2层差异:',np.mean(np.abs(keras_结果[1]-torch_结果[1].T).flatten())
打印('\t第2层keras-numpy:',np.mean(np.abs(keras\u结果[1]-numpy\u结果).flatten())
打印('\T第2层torch-numpy:',np.mean(np.abs(torch\u results[1]-numpy\u results.T).flatten())
我得到的输出(在tensorflow的所有初始化打印之后)


差别很小,这种差别是可能发生的。请确保每次计算都使用相同的浮动大小。Numpy将使用64位,python float是64位,等等,但我看到一些地方使用dtype=np.float32,但它似乎不一致。我想你知道0.1实际上不是0.1等,例如print(“{.52f}”。format(0.1))将显示它实际上不是0.1。0.1*3==30/100为假。浮点数舍入错误可能发生在很多地方。@mon我保证这里所有的东西都使用32位浮点,对吗?另外,如果它是一个浮点截断错误,它是否也应该出现在卷积输出中?类似精度浮点的类似计算应产生相同的舍入afaik。误差的大小可能很小,但在使用更深的网络时,这些误差累积成更大的差异,特别是当倒数第二层输出的值接近最终S形层的高斜率区域时。ε=0.001。0.001的类型是什么?此浮点的位大小是多少?@mon使用
np.array([0.001],dtype=np.float32)[0]
不会更改结果
1.7.1+cu110,2.4.1,1.19.5

RESULTS:
        Layer 1 difference: 0.0
        Layer 2 difference: 6.8671216e-07
        Layer 2 keras - numpy: 2.291581e-06
        Layer 2 torch - numpy: 1.8929532e-06