如何限制梯度下降算法迭代过程中生成的权重取值范围?
梯度下降权重范围限制实现方案
是否需要封装为类?
不需要强制封装为类,直接修改现有函数即可快速实现需求。封装为类的优势仅在于方便统一管理超参数、复用训练逻辑,你可以根据自己的使用场景选择实现方式。
方案1:直接修改现有函数(最简实现)
核心逻辑是每次完成权重更新后,添加截断操作,把超出指定范围的权重拉回到边界值。我们可以给原函数加一个可选的范围参数,默认关闭限制,需要时传入指定区间即可:
def predict(row, coef): # 原代码配套的预测逻辑,如果你已经实现可以删掉这段 yhat = coef[0] for i in range(len(row)-1): yhat += coef[i + 1] * row[i] return yhat def coefficients_sgd(train, l_rate, n_epoch, coef_range=None): coef = [0.0 for i in range(len(train[0]))] for epoch in range(n_epoch): sum_error = 0 for row in train: yhat = predict(row, coef) error = yhat - row[-1] sum_error += error**2 # 更新权重 coef[0] = coef[0] - l_rate * error for i in range(len(row)-1): coef[i + 1] = coef[i + 1] - l_rate * error * row[i] # 逐样本更新后做权重截断(也可以移到epoch结束后统一处理) if coef_range is not None: min_val, max_val = coef_range for j in range(len(coef)): coef[j] = max(min_val, min(coef[j], max_val)) print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error)) return coef
调用时如果要限制权重在(-1,1)区间,直接传参即可:
coef = coefficients_sgd(train_data, 0.01, 50, coef_range=(-1, 1))
方案2:封装为类(适合高频复用场景)
如果你需要频繁用不同超参数训练、或者要和其他机器学习组件统一调用格式,封装为类使用起来更方便:
class SGDLinearRegressor: def __init__(self, l_rate=0.01, n_epoch=50, coef_range=None): self.l_rate = l_rate self.n_epoch = n_epoch self.coef_range = coef_range self.coef = None def predict(self, row): yhat = self.coef[0] for i in range(len(row)-1): yhat += self.coef[i + 1] * row[i] return yhat def fit(self, train): self.coef = [0.0 for i in range(len(train[0]))] for epoch in range(self.n_epoch): sum_error = 0 for row in train: yhat = self.predict(row) error = yhat - row[-1] sum_error += error**2 # 更新权重 self.coef[0] = self.coef[0] - self.l_rate * error for i in range(len(row)-1): self.coef[i + 1] = self.coef[i + 1] - self.l_rate * error * row[i] # 权重截断 if self.coef_range is not None: min_val, max_val = self.coef_range for j in range(len(self.coef)): self.coef[j] = max(min_val, min(self.coef[j], max_val)) print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, self.l_rate, sum_error)) # 调用示例 model = SGDLinearRegressor(l_rate=0.01, n_epoch=50, coef_range=(-1,1)) model.fit(train_data) print(model.coef)
注意事项
- 截断时机可以根据需求调整:逐样本更新后截断精度更高,每个epoch结束后统一截断速度更快,小数据集下二者差异很小
- 如果发现添加限制后模型收敛速度变慢,可以适当调小学习率,避免每次更新都触碰到权重边界导致更新不充分
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

