5

Tôi đã thực hiện một phép hồi quy tuyến tính đơn giản (đơn biến đổi cho bây giờ) trong C++ để giúp tôi có được đầu xung quanh các khái niệm. Tôi khá chắc chắn rằng thuật toán quan trọng là đúng nhưng hiệu suất của tôi là khủng khiếp.Hồi quy tuyến tính kém hiệu suất gốc dốc

Đây là phương pháp mà thực sự thực hiện các gradient descent:

void LinearRegression::BatchGradientDescent(std::vector<std::pair<int,int>> & data,float& theta1,float& theta2) 
{ 

    float weight = (1.0f/static_cast<float>(data.size())); 
    float theta1Res = 0.0f; 
    float theta2Res = 0.0f; 

    for(auto p: data) 
    { 

     float cost = Hypothesis(p.first,theta1,theta2) - p.second; 
     theta1Res += cost; 
     theta2Res += cost*p.first; 
    } 

    theta1 = theta1 - (m_LearningRate*weight* theta1Res); 
    theta2 = theta2 - (m_LearningRate*weight* theta2Res); 
} 

Với các chức năng quan trọng khác được đưa ra như:

float LinearRegression::Hypothesis(float x,float theta1,float theta2) const 
{ 
    return theta1 + x*theta2; 
} 


float LinearRegression::CostFunction(std::vector<std::pair<int,int>> & data, 
            float theta1, 
            float theta2) const 
{ 
    float error = 0.0f; 
    for(auto p: data) 
    { 

     float prediction = (Hypothesis(p.first,theta1,theta2) - p.second) ; 
     error += prediction*prediction; 
    } 

    error *= 1.0f/(data.size()*2.0f); 
    return error; 
} 

void LinearRegression::Regress(std::vector<std::pair<int,int>> & data) 
{ 
    for(unsigned int itr = 0; itr < MAX_ITERATIONS; ++itr) 
    { 
     BatchGradientDescent(data,m_Theta1,m_Theta2); 
     //Some visualisation code 
    } 
} 

Bây giờ vấn đề là nếu tỷ lệ học lớn hơn xung quanh 0,000101 giá trị của hàm chi phí sau độ dốc cao hơn là trước. Đó là để nói, thuật toán đang làm việc ngược lại. Đường thẳng tạo thành một đường thẳng qua nguồn gốc khá nhanh nhưng sau đó mất hàng triệu các lần lặp lại để thực sự đạt được một đường phù hợp hợp lý.

Với một tỷ lệ học 0,01, sau sáu lần lặp đầu ra là: (nơi khác biệt là costAfter-costBefore)

Cost before 102901.945312, cost after 517539430400.000000, difference 517539332096.000000 
Cost before 517539430400.000000, cost after 3131945127824588800.000000, difference 3131944578068774912.000000 
Cost before 3131945127824588800.000000, cost after 18953312418560698826620928.000000, difference 18953308959796185006080000.000000 
Cost before 18953312418560698826620928.000000, cost after 114697949347691988409089177681920.000000, difference 114697930004878874575022382383104.000000 
Cost before 114697949347691988409089177681920.000000, cost after inf, difference inf 
Cost before inf, cost after inf, difference nan 

Trong ví dụ này thetas được thiết lập để không, tỷ lệ học để 0.000001, và có 8.000.000 lần lặp! Mã hình ảnh chỉ cập nhật biểu đồ sau mỗi 100.000 lần lặp lại.

enter image description here

Chức năng mà tạo ra các điểm dữ liệu:

static void SetupRegressionData(std::vector<std::pair<int,int>> & data) 
{ 
    srand (time(NULL)); 

    for(int x = 50; x < 750; x += 3) 
    { 
     data.push_back(std::pair<int,int>(x+(rand() % 100), 400 + (rand() % 100))); 
    } 
} 

Nói tóm lại, nếu tỷ lệ học của tôi là quá cao các thuật toán gradient descent hiệu quả chạy ngược trở lại và có xu hướng đến vô cùng và nếu nó được hạ xuống để điểm mà nó thực sự hội tụ về phía một minima số lần lặp lại cần thiết để thực sự làm như vậy là không thể chấp nhận được.

Tôi đã bỏ lỡ bất kỳ điều gì/đã làm sai trong thuật toán chính?

+0

Bạn có tham chiếu nhanh về thuật toán của mình không? Điều đó có thể dễ dàng hơn để xác định vấn đề. Ngoài ra, dựa trên kết quả trung gian, chi phí thực sự phát triển sau mỗi lần lặp lại, tôi nghĩ rằng phải có điều gì đó sai trái. – TimeString

+0

Thuật toán được lấy từ bài giảng khóa học máy học Stanford [link] (https://youtu.be/5u4G23_OohI), cũng như một vài video khác, nghĩ rằng nó khá chuẩn. Chi phí phát triển sau mỗi lần lặp lại chỉ khi tỷ lệ học tập quá cao (mà tôi nghĩ là sai), nếu tỷ lệ học tập thấp hơn nó sẽ * từ từ * giảm. – Davors72

+0

Một điều nữa là tôi đoán trong CostFunction() bạn cần phải có giá trị tuyệt đối trước khi bạn quay trở lại. – TimeString

Trả lời

5

Có vẻ như mọi thứ đều hoạt động như mong đợi, nhưng bạn đang gặp sự cố khi chọn tỷ lệ học tập hợp lý. Đó không phải là một vấn đề hoàn toàn tầm thường và có nhiều cách tiếp cận khác nhau, từ các lịch biểu được xác định trước, giảm dần tốc độ học tập (xem ví dụ: this paper) theo các phương pháp thích ứng như AdaGrad hoặc AdaDelta.

Để thực hiện vani với tỷ lệ học cố định, bạn nên làm cho cuộc sống của mình dễ dàng hơn bằng cách chuẩn hóa dữ liệu về 0 và độ lệch chuẩn đơn vị trước khi bạn nạp nó vào thuật toán gốc. Bằng cách đó bạn sẽ có thể lý do về tỷ lệ học tập dễ dàng hơn. Sau đó, bạn chỉ có thể rescale dự đoán của bạn cho phù hợp.

+0

Cảm ơn! Bình thường hóa các biến làm việc thực sự tốt, tôi thử nghiệm xung quanh với tỷ lệ học tập khác nhau và lặp đi lặp lại và nó hoạt động chính xác tôi mong đợi. – Davors72

Các vấn đề liên quan