多目标推荐排序模型优化
题意
在双目标推荐排序场景中,需要同时预测点击率(CTR)和转化率(CVR)。模型使用共享的线性权重向量 提取通用特征,同时为每个任务配置独立的偏置
和
。
给定特征矩阵 (
)、标签矩阵
(每行两列分别为 CTR 和 CVR 标签)、迭代次数
、学习率
和权重系数
,从全零参数出发进行
次批量梯度下降,然后用训练后的参数计算组合损失,输出
。
思路
这道题本质上是手写一个多任务线性回归的训练过程,核心在于正确推导共享参数的梯度。
前向传播:
$$
损失函数:
$$
其中 。
梯度推导:
由于 是共享参数,两个任务的梯度需要叠加:
$$
偏置的梯度各自独立:
$$
$$
注意 的梯度前面要乘
,因为 CVR 任务的损失本身带有
系数。
每次迭代按 更新所有参数。
最后用 Python 的 Decimal 进行四舍五入,避免浮点精度问题。
时间复杂度 ,空间复杂度
。
代码
import sys
from decimal import Decimal, ROUND_HALF_UP
def solve():
data = sys.stdin.read().split('\n')
idx = 0
# 解析特征矩阵 X
x_rows = data[idx].strip().split(';')
X = []
for row in x_rows:
X.append(list(map(float, row.split(','))))
idx += 1
# 解析标签矩阵 Y(ctr, cvr)
y_rows = data[idx].strip().split(';')
Y_ctr = []
Y_cvr = []
for row in y_rows:
vals = list(map(float, row.split(',')))
Y_ctr.append(vals[0])
Y_cvr.append(vals[1])
idx += 1
N = int(data[idx].strip()); idx += 1
lr = float(data[idx].strip()); idx += 1
alpha = float(data[idx].strip()); idx += 1
n_samples = len(X)
n_features = len(X[0])
# 初始化参数为零
w = [0.0] * n_features
b_ctr = 0.0
b_cvr = 0.0
# 批量梯度下降迭代 N 次
for _ in range(N):
# 计算预测值
pred_ctr = []
pred_cvr = []
for i in range(n_samples):
dot = sum(X[i][j] * w[j] for j in range(n_features))
pred_ctr.append(dot + b_ctr)
pred_cvr.append(dot + b_cvr)
# 计算误差
err_ctr = [pred_ctr[i] - Y_ctr[i] for i in range(n_samples)]
err_cvr = [pred_cvr[i] - Y_cvr[i] for i in range(n_samples)]
# 共享权重梯度:两个任务的梯度叠加
grad_w = [0.0] * n_features
for j in range(n_features):
g_ctr = sum(X[i][j] * err_ctr[i] for i in range(n_samples)) * 2.0 / n_samples
g_cvr = sum(X[i][j] * err_cvr[i] for i in range(n_samples)) * 2.0 / n_samples
grad_w[j] = g_ctr + alpha * g_cvr
# 偏置梯度
grad_b_ctr = 2.0 / n_samples * sum(err_ctr)
grad_b_cvr = alpha * 2.0 / n_samples * sum(err_cvr)
# 更新参数
for j in range(n_features):
w[j] -= lr * grad_w[j]
b_ctr -= lr * grad_b_ctr
b_cvr -= lr * grad_b_cvr
# 计算最终损失
mse_ctr = 0.0
mse_cvr = 0.0
for i in range(n_samples):
dot = sum(X[i][j] * w[j] for j in range(n_features))
pred_c = dot + b_ctr
pred_v = dot + b_cvr
mse_ctr += (pred_c - Y_ctr[i]) ** 2
mse_cvr += (pred_v - Y_cvr[i]) ** 2
mse_ctr /= n_samples
mse_cvr /= n_samples
loss = mse_ctr + alpha * mse_cvr
# 四舍五入输出
scaled = Decimal(str(loss)) * Decimal('10000000000')
result = scaled.quantize(Decimal('1'), rounding=ROUND_HALF_UP)
print(result)
solve()

京公网安备 11010502036488号