多目标推荐排序模型优化

题意

在双目标推荐排序场景中,需要同时预测点击率(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()