我正在研究这本很棒的书,用PyTorch重写示例,以便更好地保留材料。对于大多数示例,我的结果与书中的Keras代码相当,但我在这个练习中遇到了一些麻烦。对于那些有书的人,这是在第106页。
书中用于对文本进行分类的网络如下:
图书代码(Keras)
keras_model = keras.Sequential([
layers.Dense(64,activation='relu'),
layers.Dense(64,activation='relu'),
layers.Dense(46,activation='softmax'),
])
keras_model.compile(
optimizer = 'rmsprop',
loss = 'sparse_categorical_crossentropy',
metrics = ['accuracy']
)
hist = keras_model.fit(
partial_train_xs,
partial_train_ys,
epochs=20,
batch_size=512,
validation_data=[val_xs,val_ys]
)
字符串
我尝试在PyTorch中重新创建相同的内容:
model = nn.Sequential(
nn.Linear(10_000,64),
nn.ReLU(),
nn.Linear(64,64),
nn.ReLU(),
nn.Linear(64,46),
nn.Softmax()
)
def compute_val_loss(model,xs,ys):
preds = model(xs)
return(F.cross_entropy(preds,ys)).item()
def compute_accuracy(model,xs,ys):
preds = model(xs)
acc = (preds.argmax(dim=1) == ys).sum() / len(preds)
return acc.item()
def train_loop(model,xs,ys,epochs=20,lr=1e-3,opt=torch.optim.RMSprop,
batch_size=512,loss_func=F.cross_entropy):
opt = opt(model.parameters(),lr=lr)
losses = []
for i in range(epochs):
epoch_loss = []
for b in range(0,len(xs),batch_size):
xbatch = xs[b:b+batch_size]
ybatch = ys[b:b+batch_size]
logits = model(xbatch)
loss = loss_func(logits,ybatch)
model.zero_grad()
loss.backward()
opt.step()
epoch_loss.append(loss.item())
losses.append([i,sum(epoch_loss)/len(epoch_loss)])
print(loss.item())
return losses
型
为了简洁,我已经排除了数据加载部分,但它只是对单词序列进行“多点”编码。例如,如果vocab是10 k单词,则每个输入都是一个10 k向量,其中向量中的每个索引都对应于vocab中的单词索引。
我的问题:
我在这里遇到的问题是,这本书的Keras版本之间的结果存在很大差异(其行为符合预期)和PyTorch版本。经过20个epoch,Keras版本的训练损失可以忽略不计,约为80%。在有效期上是准确的。然而,Torch版本几乎没有在训练损失上移动。对于上下文,它从大约3.4开始,在20个epoch后结束,3.1. Keras版本的火车损失比单个纪元后的火车损失更低(2.6)。
Torch 版本在准确性上确实取得了进步,尽管仍然落后于Keras版本。准确性也有一个奇怪的阶梯模式:
x1c 0d1x的数据
我在Torch版本中做错了什么?或者有一个合理的理由来解释预期的分歧?两个库的RMSProp args中有一些微小的超参数差异,但我摆弄了一下,并没有看到太大的差异。两者的学习率是相等的。即使我运行 Torch 版本150个epoch,训练/测试损失继续下降(非常缓慢),但验证准确度在75%左右达到峰值。
1条答案
按热度按时间63lcw9qa1#
经过更多的研究(和睡眠),我发现损失函数(交叉熵)在PyTorch中期望原始logits,而在Keras中它期望概率。您可以在Keras版本中设置
from_logits
= True以使它们等效。在PyTorch版本中删除Softmax层,我得到了大致相同的结果。