TLDR:
一个简单的(单隐藏层)前馈Pytorch模型被训练来预测函数y=sin(X1)sin(X2)... sin(X10)
的性能大大低于使用Keras构建/训练的相同模型。为什么会这样,可以做些什么来减轻性能差异?
在训练回归模型时,我注意到PyTorch的性能大大低于使用Keras构建的相同模型。
这种现象以前已经被观察和报道过:
>
相同的模型在pytorch上产生的结果比在张量流上更差
pytorch中的CNN模型比Tensoflowflow模型的精度低30%:
PyTorch Adam vs Tensorflow Adam
与TensorFlow模型相比的次优收敛性
RNN 和亚当:收敛速度比凯拉斯慢
PyTorch与keras相当,但在简单的前馈网络上比keras差
为什么PyTorch模型比Keras中的相同模型做得更差,即使在相同的权重初始化下?
为什么 Keras 在相同的网络配置下表现得比 Pytorch 更好?
之前也提出了以下解释和建议:
>
使用相同的十进制精度(32 vs 64):1,2,
使用CPU而不是GPU:1,2
在使用 autograd 计算
第二导数时,将 retain_graph=True
更改为 create_graph=True
。grad:1
检查keras是否以不同于pytorch的方式使用正则化、约束、偏差或损失函数:1,2
确保以相同的方式计算验证损失:1
使用相同的初始化程序:1,2
为更长的时代培训pytorch模型:1
尝试几个随机种子:1
确保<code>模型。在训练pytorch模型时,在验证步骤中调用eval():1
主要问题在于Adam优化器,而不是初始化:1
为了理解这个问题,我在Keras和PyTorch中训练了一个简单的两层神经网络(比我原来的模型简单得多),使用了相同的超参数和初始化例程,并遵循了上面列出的所有建议。然而,PyTorch模型导致的均方误差(MSE)比Keras模型的MSE高400%。
这是我的代码:
0. 进口
import numpy as np
from scipy.stats import pearsonr
from sklearn.preprocessing import MinMaxScaler
from sklearn import metrics
from torch.utils.data import Dataset, DataLoader
import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.regularizers import L2
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
1. 生成可重现的数据集
def get_data():
np.random.seed(0)
Xtrain = np.random.normal(0, 1, size=(7000,10))
Xval = np.random.normal(0, 1, size=(700,10))
ytrain = np.sum(np.sin(Xtrain), axis=-1)
yval = np.sum(np.sin(Xval), axis=-1)
scaler = MinMaxScaler()
ytrain = scaler.fit_transform(ytrain.reshape(-1,1)).reshape(-1)
yval = scaler.transform(yval.reshape(-1,1)).reshape(-1)
return Xtrain, Xval, ytrain, yval
class XYData(Dataset):
def __init__(self, X, y):
super(XYData, self).__init__()
self.X = torch.tensor(X, dtype=torch.float32)
self.y = torch.tensor(y, dtype=torch.float32)
self.len = len(y)
def __getitem__(self, index):
return (self.X[index], self.y[index])
def __len__(self):
return self.len
# Data, dataset, and dataloader
Xtrain, Xval, ytrain, yval = get_data()
traindata = XYData(Xtrain, ytrain)
valdata = XYData(Xval, yval)
trainloader = DataLoader(dataset=traindata, shuffle=True, batch_size=32, drop_last=False)
valloader = DataLoader(dataset=valdata, shuffle=True, batch_size=32, drop_last=False)
2.使用相同的超参数和初始化方法构建Keras和PyTorch模型
class TorchLinearModel(nn.Module):
def __init__(self, input_dim=10, random_seed=0):
super(TorchLinearModel, self).__init__()
_ = torch.manual_seed(random_seed)
self.hidden_layer = nn.Linear(input_dim,100)
self.initialize_layer(self.hidden_layer)
self.output_layer = nn.Linear(100, 1)
self.initialize_layer(self.output_layer)
def initialize_layer(self, layer):
_ = torch.nn.init.xavier_normal_(layer.weight)
#_ = torch.nn.init.xavier_uniform_(layer.weight)
_ = torch.nn.init.constant(layer.bias,0)
def forward(self, x):
x = self.hidden_layer(x)
x = self.output_layer(x)
return x
def mean_squared_error(ytrue, ypred):
return torch.mean(((ytrue - ypred) ** 2))
def build_torch_model():
torch_model = TorchLinearModel()
optimizer = optim.Adam(torch_model.parameters(),
betas=(0.9,0.9999),
eps=1e-7,
lr=1e-3,
weight_decay=0)
return torch_model, optimizer
def build_keras_model():
x = layers.Input(shape=10)
z = layers.Dense(units=100, activation=None, use_bias=True, kernel_regularizer=None,
bias_regularizer=None)(x)
y = layers.Dense(units=1, activation=None, use_bias=True, kernel_regularizer=None,
bias_regularizer=None)(z)
keras_model = Model(x, y, name='linear')
optimizer = Adam(learning_rate=1e-3, beta_1=0.9, beta_2=0.9999, epsilon=1e-7,
amsgrad=False)
keras_model.compile(optimizer=optimizer, loss='mean_squared_error')
return keras_model
# Instantiate models
torch_model, optimizer = build_torch_model()
keras_model = build_keras_model()
3.将PyTorch模型训练100个时期:
torch_trainlosses, torch_vallosses = [], []
for epoch in range(100):
# Training
losses = []
_ = torch_model.train()
for i, (x,y) in enumerate(trainloader):
optimizer.zero_grad()
ypred = torch_model(x)
loss = mean_squared_error(y, ypred)
_ = loss.backward()
_ = optimizer.step()
losses.append(loss.item())
torch_trainlosses.append(np.mean(losses))
# Validation
losses = []
_ = torch_model.eval()
with torch.no_grad():
for i, (x, y) in enumerate(valloader):
ypred = torch_model(x)
loss = mean_squared_error(y, ypred)
losses.append(loss.item())
torch_vallosses.append(np.mean(losses))
print(f"epoch={epoch+1}, train_loss={torch_trainlosses[-1]:.4f}, val_loss={torch_vallosses[-1]:.4f}")
4.训练100个时期的Keras模型:
history = keras_model.fit(Xtrain, ytrain, sample_weight=None, batch_size=32, epochs=100,
validation_data=(Xval, yval))
5.培训历史损失
plt.plot(torch_trainlosses, color='blue', label='PyTorch Train')
plt.plot(torch_vallosses, color='blue', linestyle='--', label='PyTorch Val')
plt.plot(history.history['loss'], color='brown', label='Keras Train')
plt.plot(history.history['val_loss'], color='brown', linestyle='--', label='Keras Val')
plt.legend()
Keras在训练中记录的错误要低得多。由于这可能是由于Keras计算损失的方式不同,我使用sklearn.metrics.mean_squared_error计算了验证集上的预测误差
6. 训练后的验证错误
ypred_keras = keras_model.predict(Xval).reshape(-1)
ypred_torch = torch_model(torch.tensor(Xval, dtype=torch.float32))
ypred_torch = ypred_torch.detach().numpy().reshape(-1)
mse_keras = metrics.mean_squared_error(yval, ypred_keras)
mse_torch = metrics.mean_squared_error(yval, ypred_torch)
print('Percent error difference:', (mse_torch / mse_keras - 1) * 100)
r_keras = pearsonr(yval, ypred_keras)[0]
r_pytorch = pearsonr(yval, ypred_torch)[0]
print("r_keras:", r_keras)
print("r_pytorch:", r_pytorch)
plt.scatter(ypred_keras, yval); plt.title('Keras'); plt.show(); plt.close()
plt.scatter(ypred_torch, yval); plt.title('Pytorch'); plt.show(); plt.close()
Percent error difference: 479.1312469426776
r_keras: 0.9115184443702814
r_pytorch: 0.21728812737220082
Keras的预测值与真实值的相关性为0.912,Pytorch的相关性为0.217,Pytorch的误差高出479%!
7. 我也尝试过的其他试验:
。权重初始化中的xavier_normal_
。R从0.217提高到0.639,但仍比Keras(0.912)差如何确保PyTorch模型收敛到与Keras模型相当的合理误差?
这里的问题是PyTorch训练回路中的无意广播。
nn.Linear
操作的结果总是具有形状[B, D]
,其中B
是批次大小,D
是输出维度。因此,在您的mean_squared_error
函数ypred
具有形状[32,1]
和ytrue
具有形状[32]
。根据NumPy和PyTorch使用的广播规则,这意味着ytrue-ypred
具有形状[32,32]
。您几乎可以肯定的意思是ypred
具有形状[32]
。这可以通过多种方式实现;可能最具可读性的是使用Tensor.flatten
class TorchLinearModel(nn.Module):
...
def forward(self, x):
x = self.hidden_layer(x)
x = self.output_layer(x)
return x.flatten()
产生以下列车/阀曲线
问题内容: 我正在尝试使用张量流中的一些简单模型,包括一个看起来与第一个MNIST for ML Beginners示例 非常相似的模型,但具有更大的维度。我能够毫无问题地使用梯度下降优化器,获得足够好的收敛性。当我尝试使用ADAM优化器时,出现如下错误: 抱怨未初始化的特定变量根据运行而变化。这个错误是什么意思?这表明错了吗?无论我使用什么学习率,它似乎都会发生。 问题答案: AdamOptim
问题内容: 与 不是由bean* 通过 applicationcontext.getbean 进行管理的bean 相比,使用 @configurable有 什么优势?任何人列出的利弊? *** 问题答案: 我要为此得到 -20 。即使是臭名昭著的马丁·福勒(Martin Fowler)发明了这个可怕的“依赖注入”名称,也认为它不适合测试: http://martinfowler.com/artic
我用python用800个样本训练了一个CNN神经网络,并用60个样本进行了测试。输出精度是50,现在每次我使用模型。预测它会给我同样的结果。 我用了keras和tensorflow。图像为224x224像素,每个像素分为两类。我对神经网络知之甚少,这是我第一次尝试把它做得这么大。我听说它可能太合适了,或者我需要一个更重要的图层,或者我的批量大小/年代/学习率是错误的。 编辑1:种子对网络培训有何
我使用的是tensorflow 1.10 Python 3.6 我的代码基于TensorFlow提供的预制虹膜分类模型。这意味着,我使用的是一个Tensorflow DNN预制的分类器,区别如下: 10个功能改为4个。 5个类改为3个。 我做了一个代码将这个分类器导出为tflite格式,但是python模型中的准确率高于75%,但是当导出时,准确率大约下降到45%,这意味着大约30%的准确率丢失了
最近,我比较了Keras版本和Pytorch版本在同一数据集上的unet实现。但是,使用Keras,10个纪元后损失持续下降,准确率更高,而使用Pytorch,10个纪元后损失下降不均匀,准确率更低。有人遇到过这样的问题并有任何答案吗? 最终的pytorch训练过程如下所示: 2019-12-15 18:14:20 纪元:9 迭代:1214/1219 损失:0.464673 acc:0.58171
我的模型JRip分类器有一个小问题 输出似乎足够好,但我担心相对绝对误差和相对平方根误差会很高。当我尝试J48和NaiveBayes时,它也高出了98%。这在分类中不是很重要吗?我可以就这样离开吗?否则,我如何改进它?成本矩阵为: 0 1 2 0 是什么改善了二等舱TP费率的结果。提前感谢您的帮助