2014-02-08 3 views
4

파이썬에서 그래디언트 디센트로 선형 회귀를 구현했습니다. 그것이 얼마나 잘하고 있는지보기 위해서 나는 scikit-learn의 LinearRegression() 클래스와 비교했다. 어떤 이유로 Sklearn은 평균 3의 MSE (항상 테스트를 위해 Boston Housing 데이터 세트를 사용하고 있습니다)로 내 프로그램을 능가합니다. 나는 현재 컨버전스를 확인하기 위해 그라디언트 검사를하고 있지 않다는 것을 이해하지만 많은 반복을 허용하고 학습 속도를 충분히 낮추어 수렴해야합니다. 학습 알고리즘 구현에 명확한 버그가 있습니까? 여기 내 코드는 다음과 같습니다.선형 회귀 구현은 항상 sklearn보다 성능이 우수합니다.

import numpy as np 
from sklearn.linear_model import LinearRegression 

def getWeights(x): 
    lenWeights = len(x[1,:]); 
    weights = np.random.rand(lenWeights) 
    bias = np.random.random(); 
    return weights,bias 

def train(x,y,weights,bias,maxIter): 
    converged = False; 
    iterations = 1; 
    m = len(x); 
    alpha = 0.001; 
    while not converged: 
      for i in range(len(x)): 
       # Dot product of weights and training sample 
       hypothesis = np.dot(x[i,:], weights) + bias; 
       # Calculate gradient 
       error = hypothesis - y[i]; 
       grad = (alpha * 1/m) * (error * x[i,:]); 
       # Update weights and bias 
       weights = weights - grad; 
       bias = bias - alpha * error; 
       iterations = iterations + 1; 

       if iterations > maxIter: 
        converged = True; 
        break 

    return weights, bias 

def predict(x, weights, bias): 
    return np.dot(x,weights) + bias 

if __name__ == '__main__': 

    data = np.loadtxt('housing.txt'); 
    x = data[:,:-1]; 
    y = data[:,-1]; 
    for i in range(len(x[1,:])): 
     x[:,i] = ((x[:,i] - np.min(x[:,i]))/(np.max(x[:,i]) - np.min(x[:,i]))); 

    initialWeights,initialBias = getWeights(x); 
    weights,bias = train(x,y,initialWeights,initialBias,55000); 
    pred = predict(x, weights,bias); 
    MSE = np.mean(abs(pred - y)); 

    print "This Program MSE: " + str(MSE) 

    sklearnModel = LinearRegression(); 
    sklearnModel = sklearnModel.fit(x,y); 
    sklearnModel = sklearnModel.predict(x); 

    skMSE = np.mean(abs(sklearnModel - y)); 

    print "Sklearn MSE: " + str(skMSE) 

답변

7

먼저 올바른 목적 함수 값을 계산하고 있는지 확인하십시오. 선형 회귀 대수는 np.mean(abs(pred - y))이 아닌 .5*np.mean((pred-y)**2)이어야합니다.

실제로는 확률 적 그래디언트 디센트 (SGD) 알고리즘 (개별 예제에서 그래디언트 반복 실행)을 실행하고 있는데, 이는 "그래디언트 디센트"와 구별해야합니다.

SGD는 좋은 학습 방법이지만 잘못된 최적화 방법입니다. 경험적 오류 (http://leon.bottou.org/publications/pdf/nips-2007.pdf)로 수렴하기 위해 많은 반복이 필요할 수 있습니다.

SGD를 수렴하려면 학습 속도를 제한해야합니다. 일반적으로 학습 속도는 기본 학습 속도를 코드의 변수를 사용하여 alpha/(iterations+1)과 같은 반복 횟수로 나눈 값으로 설정됩니다.

그라디언트에는 일반적으로 SGD 업데이트에 사용되지 않는 1/m의 배수가 포함됩니다.

훈련 된 데이터 세트의 오류를 평가하는 대신 SGD 구현을 테스트하려면 데이터 세트를 교육 세트와 테스트 세트로 분리하고 두 가지 방법으로 학습 한 후에이 테스트 세트의 오류를 평가하십시오. 교육/테스트 세트 분할을 사용하면 최적화 알고리즘 (경험적 오류 최소화)보다는 학습 알고리즘 (예상 오류 추정)으로 알고리즘의 성능을 예측할 수 있습니다.

+0

대단한 답변을 보내 주셔서 감사합니다. 실제로 SGD를하고 있다는 것을 깨닫지 못했습니다. 당신이 말했듯이, 1/m의 배수를 더하는 것은 그것을 버리고있었습니다; 알고리즘은 이제 scikit-learn만큼 좋은 성능을 보입니다. – rahulm

+0

@rahulm 업데이트 된 코드는 어떻게 생겼습니까? github link? –

0

반복 값을 늘려보십시오. 이렇게하면 알고리즘이 전체 최소값에 더 가까운 값으로 수렴 할 수 있습니다. 평범한 그래디언트 디센트 또는 심지어 SGD보다 훨씬 빠르게 수렴에 가까워 질 수있는 l-bfg를 사용하지 않는다는 것을 명심하십시오.

선형 회귀를 수행하는 또 다른 방법으로 일반 방정식을 사용해보십시오.

http://eli.thegreenplace.net/2014/derivation-of-the-normal-equation-for-linear-regression/.