Я пытаюсь реализовать алгоритм RankNet (обучение рангу) в PyTorch из этой статьи: https://www.microsoft.com/en-us/research/publication/from-ranknet-to-lambdarank-to-lambdamart-an-overview/
Я реализовал двухслойную нейронную сеть (MLP) с активацией RELU.Я использую оптимизатор Адама, с уменьшением веса 0,01.Я написал пользовательскую функцию потерь, как упомянуто в статье.Подробности следующие:
Уравнение потерь / затрат: Loss_Image.png
где, для данного запроса S_ij ∈ {0, ±1} и S_ij = 1, если документ i помечен как более релевантный, чем документ j, -1, если документ i помечен как менее релевантный, чем документ j, и 0, если они имеют одинаковую метку.s_i и s_j - это прогнозируемые оценки по модели для URL-адресов URL_i и URL_j запроса.
Кроме того, я реализовал функцию NDCG в качестве метрики оценки алгоритма обучения рангу.Я использую набор данных LETOR MQ2008 с обучающими выборками 52 000.
Функция потерь
def custom_loss_func(x_tr, y_tr):
#x_tr = predicted score by the model
#y_tr = true score
loss_mean = torch.tensor(0.0)
x_tr = torch.squeeze(x_tr)
for i in range(len(x_tr))[::2]:
s_i = x_tr[i]
s_j = x_tr[i+1]
s_ij_diff = s_i - s_j
true_i = y_tr[i]
true_j = y_tr[i+1]
if true_i > true_j:
S_ij = 1
elif true_i < true_j:
S_ij = -1
else:
S_ij = 0
loss = (1 - S_ij) * s_ij_diff / 2. + torch.log(1 + torch.exp(-s_ij_diff))
loss_mean += loss
loss_mean /= (len(x_tr)/2)
return loss_mean
Метрика оценки: NDCG
def calc_ndcg(y_true, y_pred, k):
y_pred = torch.squeeze(y_pred, 1)
dcg = torch.tensor([0.])
ideal_dcg = torch.tensor([0.])
y_true_sorted, index_y_true = torch.sort(y_true, descending=True)
y_pred_sorted, index_y_pred = torch.sort(y_pred, descending=True)
for i in range(k):
ideal_dcg += (torch.tensor(2.) ** y_true_sorted[i] - torch.tensor(1.)) / torch.log2(torch.tensor(i) + torch.tensor(2.))
for i in range(k):
dcg += (torch.tensor(2.) ** y_true[index_y_pred[i]] - torch.tensor(1.)) / torch.log2(torch.tensor(i) + torch.tensor(2.))
ndcg = dcg / ideal_dcg
return ndcg
Main
for epoch in range(epochs):
#model.train()
running_loss = 0.0
for i, each_batch in enumerate(pairs_dl, start=0):
xb, yb = get_train_batch(each_batch)
pred = model(xb)
loss = custom_loss_func(pred, yb)
running_loss += loss
opt.zero_grad()
loss.backward()
opt.step()
avg_loss = running_loss / (i+1)
print('[%d, %5d] loss: %.10f' % (epoch + 1, i + 1, avg_loss))
running_loss = 0.0
#model.eval()
with torch.no_grad():
y_pred_t = model(X_train_t)
ndcg_epoch = calc_ndcg(y_train_t, y_pred_t, 10)
Вот мои результаты: Accuracy_Loss_image.png
- Количество скрытых 1 единиц = 64
- Количество скрытых 2 единиц слоя = 32
- Количество эпох = 100
- Размер партии = 32
- Скорость обучения = 1e-05
- NDCG k = 10
Как видно из рисунка, точность обучения (NDCG) сильно колеблется и кажется совершенно неверной.Я также попробовал это с различными настройками гиперпараметра, изменяя скорость обучения, размер пакета, количество слоев, количество нейронов.Также пробовал на проверочном наборе, и это дает ошибки как в потерях, так и в NDCG.Поэтому в настоящее время я сосредотачиваюсь на том, чтобы сначала получить правильную точность обучения.
Я предполагаю, что где-то в функции потерь или NDCG я делаю ошибку или в градиентах, но не в состоянии выяснить это.У меня вопрос, где я ошибаюсь, и какие изменения я должен внести, чтобы получить правильную точность?
Я новичок в PyTorch, и я был бы очень признателен за любую помощь в этом.Заранее спасибо.