搜广推校招面经一百零五
·
字节 广告算法
一、numpy 实现 mlp
import numpy as np
# 激活函数
def relu(x):
return np.maximum(0, x)
def relu_derivative(x):
return (x > 0).astype(float)
def softmax(x):
exp_x = np.exp(x - np.max(x, axis=1, keepdims=True)) # 防止溢出
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
def cross_entropy(y_true, y_pred):
m = y_true.shape[0]
return -np.sum(y_true * np.log(y_pred + 1e-9)) / m
def init_weights(shape, method="he"):
n_in, n_out = shape
if method == "zeros":
return np.zeros((n_in, n_out))
elif method == "random":
return np.random.randn(n_in, n_out) * 0.01
elif method == "xavier":
limit = np.sqrt(6 / (n_in + n_out))
return np.random.uniform(-limit, limit, (n_in, n_out))
elif method == "he":
return np.random.randn(n_in, n_out) * np.sqrt(2 / n_in)
else:
raise ValueError("Unknown init method")
class MLP:
def __init__(self, input_dim, hidden_dim, output_dim, init="he", lr=0.01):
# 初始化参数
self.W1 = init_weights((input_dim, hidden_dim), method=init)
self.b1 = np.zeros((1, hidden_dim))
self.W2 = init_weights((hidden_dim, output_dim), method=init)
self.b2 = np.zeros((1, output_dim))
self.lr = lr
def forward(self, X):
# 前向传播
self.Z1 = X.dot(self.W1) + self.b1
self.A1 = relu(self.Z1)
self.Z2 = self.A1.dot(self.W2) + self.b2
self.A2 = softmax(self.Z2)
return self.A2
def backward(self, X, y_true):
m = X.shape[0]
# 输出层梯度
dZ2 = self.A2 - y_true
dW2 = self.A1.T.dot(dZ2) / m
db2 = np.sum(dZ2, axis=0, keepdims=True) / m
# 隐藏层梯度
dA1 = dZ2.dot(self.W2.T)
dZ1 = dA1 * relu_derivative(self.Z1)
dW1 = X.T.dot(dZ1) / m
db1 = np.sum(dZ1, axis=0, keepdims=True) / m
# 参数更新
self.W1 -= self.lr * dW1
self.b1 -= self.lr * db1
self.W2 -= self.lr * dW2
self.b2 -= self.lr * db2
def train(self, X, y, epochs=1000):
for epoch in range(epochs):
y_pred = self.forward(X)
loss = cross_entropy(y, y_pred)
self.backward(X, y)
if epoch % 100 == 0:
acc = np.mean(np.argmax(y_pred, axis=1) == np.argmax(y, axis=1))
print(f"Epoch {epoch}, Loss: {loss:.4f}, Acc: {acc:.4f}")
# 生成 toy 数据集
from sklearn.datasets import make_moons
from sklearn.preprocessing import OneHotEncoder
X, y = make_moons(n_samples=500, noise=0.2, random_state=42)
y = y.reshape(-1, 1)
enc = OneHotEncoder(sparse=False)
y_onehot = enc.fit_transform(y)
# 建立模型
mlp = MLP(input_dim=2, hidden_dim=16, output_dim=2, init="he", lr=0.1)
mlp.train(X, y_onehot, epochs=1000)
二、神经网络的初始化方法有哪些
见【搜广推实习面经三】
三、数组里两数之和等于target的pair count
from collections import Counter
def two_sum_count(nums, target):
counter = Counter(nums)
count = 0
for num in list(counter.keys()):
complement = target - num
if complement not in counter:
continue
# 情况 1: num == complement
if num == complement:
count += counter[num] * (counter[num] - 1) // 2
# 情况 2: num < complement(避免重复计数)
elif num < complement:
count += counter[num] * counter[complement]
return count
四、知不知道meta learning做冷启动
4.1. 冷启问题是什么?
- 用户冷启:新用户注册,没有历史行为数据。
- 物品冷启:新商品上架,没有交互数据。
- 任务冷启:新场景/新领域,缺少标注样本。
传统模型往往需要大量历史数据才能学好,冷启时很难收敛。
4.2. Meta Learning 如何帮助冷启
Meta-learning 的核心思想是 学会学习 (learning to learn):
- 在大量历史任务(老用户/老商品/已知领域)上训练一个 元模型 (meta-model)。
- 学到一个好的 初始化参数 或者 学习策略。 遇到冷启任务(新用户/新商品/新任务)时,模型能 快速适应,只需要少量数据。
4.3. 常见方法
(1) Model-Agnostic Meta-Learning (MAML)
- 思路:学到一个“初始化参数”,使得在新任务上用 1-5 个样本微调几步就能收敛。
- 公式:
θ
∗
=
a
r
g
m
i
n
θ
Σ
T
i
p
(
T
)
L
T
i
(
U
(
θ
)
)
θ* = argmin_θ Σ_{T_i ~ p(T)} L_{T_i}(U(θ))
θ∗=argminθΣTi p(T)LTi(U(θ))
(其中 U(θ) 表示在任务 T i T_i Ti 上更新后的参数) - 应用到冷启:
- 在已有用户上 meta-train 得到 θ
- 新用户冷启时,只需少量交互数据就能 fine-tune
(2) Metric-based Methods(原型网络 / Matching Network)
- 思路:学到一个 embedding 空间,让相似用户/物品的距离更近。
- 冷启时:即使新用户/物品样本极少,也能通过 最近邻 / 度量学习 做推荐或分类。
- 应用:冷启推荐、新标签分类。
(3) Optimization-based Methods
- 思路:meta-learn 一个 学习率调度 或 更新规则,在冷启时比传统 SGD 更快适应。
- 例子:Meta-SGD, LEO。
4.4. 推荐系统中的应用示例
- 用户冷启:
- 用 meta-learning 在老用户数据上训练 embedding 初始化器
- 新用户注册 → 用少量行为数据更新 → 生成个性化 embedding
- 物品冷启:
- 利用物品内容(标题、图像) → meta-learn 一个 encoder
- 新商品出现 → encoder 直接生成 embedding,即使交互数据很少也能推荐
更多推荐
所有评论(0)