You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中实现SGD时多关联向量的随机采样问题

解决SGD中保持x、y对应关系的随机采样问题

我明白你现在的困扰——要在SGD里随机采样x和y的对应数据点,又怕打乱它们的一一对应关系对吧?其实核心思路很简单:先随机选数据点的索引,再根据索引提取对应的x和y值,这样就能完美保留每组数据的配对关系。

下面给你两种可行的实现方案,分别对应单样本SGD和小批量(mini-batch)SGD:

方案1:标准SGD(每次随机选1个样本)

如果是标准的随机梯度下降,每次迭代只需要随机选一组(x_i, y_i)。你可以这样修改SGD函数:

import numpy as np
import matplotlib.pyplot as plt
import random

# 你的原始数据和函数保持不变
x = np.array([0.,0.,0.,100.,100.,300.,300.,900.,900.,900.])
y = np.array([0.,0.,1.,0.,1.,1.,1.,0.,1.,1.])

def f(b0,b1,x,y):
    vec = [y[i]*np.log(1/(1+np.exp(-b0-b1*x[i]))) + (1-y[i])*np.log(1 - (1/(1+np.exp(-b0-b1*x[i])))) for i in range(len(y))]
    return sum(vec)

def dervf0(b0,b1,x,y):
    vec = [-y[i] + (1/(1+np.exp(-b0-b1*x[i]))) for i in range(len(y))]
    return sum(vec)

def dervf1(b0,b1,x,y):
    vec = [-x[i]*(y[i]-(1/(1+np.exp(-b0-b1*x[i])))) for i in range(len(y))]
    return sum(vec)

def SGD(v, x, y, tol, maxiter):
    data_size = len(x)
    for i in range(maxiter):
        # 随机选一个索引
        rand_idx = random.randint(0, data_size - 1)
        # 根据索引提取对应的x和y样本
        x_sample = np.array([x[rand_idx]])
        y_sample = np.array([y[rand_idx]])
        
        # 计算当前样本的梯度并更新参数
        theta_new = v - 0.001 * np.array([dervf0(v[0], v[1], x_sample, y_sample), 
                                         dervf1(v[0], v[1], x_sample, y_sample)])
        if np.linalg.norm(theta_new - v) < tol:
            break
        else:
            v = theta_new
        # print('i	{}	v	{}	theta_new	{}'.format(i, v, theta_new))
    return theta_new, i

方案2:小批量SGD(每次随机选n组样本)

如果需要每次选n组数据(也就是mini-batch),可以修改函数,把批量大小batch_size作为参数传入,然后随机选择多个不重复的索引(或者允许重复,取决于你的需求):

def SGD_mini_batch(v, x, y, tol, maxiter, batch_size=3):
    data_size = len(x)
    for i in range(maxiter):
        # 随机选择batch_size个不重复的索引(不放回采样)
        rand_indices = random.sample(range(data_size), batch_size)
        # 提取对应的x和y子集
        x_batch = x[rand_indices]
        y_batch = y[rand_indices]
        
        # 计算小批量的梯度并更新参数
        theta_new = v - 0.001 * np.array([dervf0(v[0], v[1], x_batch, y_batch), 
                                         dervf1(v[0], v[1], x_batch, y_batch)])
        if np.linalg.norm(theta_new - v) < tol:
            break
        else:
            v = theta_new
        # print('i	{}	v	{}	theta_new	{}'.format(i, v, theta_new))
    return theta_new, i

关键细节说明

  • 不管是单样本还是小批量,核心都是先选索引,再按索引取数据,这样绝对不会打乱x和y的对应关系。
  • 如果需要允许重复采样(比如有些SGD实现会用放回采样),可以把random.sample换成[random.randint(0, data_size-1) for _ in range(batch_size)]。
  • 你的dervf0和dervf1函数已经是对传入的x、y求和,所以直接传入采样后的子集就可以正确计算小批量梯度,不需要修改这两个函数。

内容的提问来源于stack exchange,提问作者Yousef Kaddoura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:22:36