ग्रेडिएंट वंश इस डेटासेट पर साधारण से कम वर्गों का समाधान नहीं खोजता है?


12

मैं रैखिक प्रतिगमन का अध्ययन कर रहा हूं और इसे नीचे दिए गए सेट {(x, y)} पर आजमाया, जहां x ने वर्ग-फुट में घर का क्षेत्र निर्दिष्ट किया, और y ने डॉलर में मूल्य निर्दिष्ट किया। एंड्रयू एनजी नोट्स में यह पहला उदाहरण है ।

2104.400
1600.330
2400.369
1416.232
3000.540

मैंने एक नमूना कोड विकसित किया है, लेकिन जब मैं इसे चलाता हूं, तो प्रत्येक चरण के साथ लागत बढ़ रही है, जबकि प्रत्येक चरण के साथ घटाना चाहिए। नीचे दिए गए कोड और आउटपुट। biasW 0 X 0 है , जहां X 0 = 1 है। featureWeights[X 1 , X 2 , ..., X N ] की एक सरणी है

मैंने यहाँ उपलब्ध एक ऑनलाइन अजगर समाधान की भी कोशिश की , और यहाँ समझाया । लेकिन यह उदाहरण भी वही आउटपुट दे रहा है।

अवधारणा को समझने में अंतर कहां है?

कोड:

package com.practice.cnn;

import java.util.Arrays;

public class LinearRegressionExample {

    private float ALPHA = 0.0001f;
    private int featureCount = 0;
    private int rowCount = 0;

    private float bias = 1.0f;
    private float[] featureWeights = null;

    private float optimumCost = Float.MAX_VALUE;

    private boolean status = true;

    private float trainingInput[][] = null;
    private float trainingOutput[] = null;

    public void train(float[][] input, float[] output) {
        if (input == null || output == null) {
            return;
        }

        if (input.length != output.length) {
            return;
        }

        if (input.length == 0) {
            return;
        }

        rowCount = input.length;
        featureCount = input[0].length;

        for (int i = 1; i < rowCount; i++) {
            if (input[i] == null) {
                return;
            }

            if (featureCount != input[i].length) {
                return;
            }
        }

        featureWeights = new float[featureCount];
        Arrays.fill(featureWeights, 1.0f);

        bias = 0;   //temp-update-1
        featureWeights[0] = 0;  //temp-update-1

        this.trainingInput = input;
        this.trainingOutput = output;

        int count = 0;
        while (true) {
            float cost = getCost();

            System.out.print("Iteration[" + (count++) + "] ==> ");
            System.out.print("bias -> " + bias);
            for (int i = 0; i < featureCount; i++) {
                System.out.print(", featureWeights[" + i + "] -> " + featureWeights[i]);
            }
            System.out.print(", cost -> " + cost);
            System.out.println();

//          if (cost > optimumCost) {
//              status = false;
//              break;
//          } else {
//              optimumCost = cost;
//          }

            optimumCost = cost;

            float newBias = bias + (ALPHA * getGradientDescent(-1));

            float[] newFeaturesWeights = new float[featureCount];
            for (int i = 0; i < featureCount; i++) {
                newFeaturesWeights[i] = featureWeights[i] + (ALPHA * getGradientDescent(i));
            }

            bias = newBias;

            for (int i = 0; i < featureCount; i++) {
                featureWeights[i] = newFeaturesWeights[i];
            }
        }
    }

    private float getCost() {
        float sum = 0;
        for (int i = 0; i < rowCount; i++) {
            float temp = bias;
            for (int j = 0; j < featureCount; j++) {
                temp += featureWeights[j] * trainingInput[i][j];
            }

            float x = (temp - trainingOutput[i]) * (temp - trainingOutput[i]);
            sum += x;
        }
        return (sum / rowCount);
    }

    private float getGradientDescent(final int index) {
        float sum = 0;
        for (int i = 0; i < rowCount; i++) {
            float temp = bias;
            for (int j = 0; j < featureCount; j++) {
                temp += featureWeights[j] * trainingInput[i][j];
            }

            float x = trainingOutput[i] - (temp);
            sum += (index == -1) ? x : (x * trainingInput[i][index]);
        }
        return ((sum * 2) / rowCount);
    }

    public static void main(String[] args) {
        float[][] input = new float[][] { { 2104 }, { 1600 }, { 2400 }, { 1416 }, { 3000 } };

        float[] output = new float[] { 400, 330, 369, 232, 540 };

        LinearRegressionExample example = new LinearRegressionExample();
        example.train(input, output);
    }
}

आउटपुट:

Iteration[0] ==> bias -> 0.0, featureWeights[0] -> 0.0, cost -> 150097.0
Iteration[1] ==> bias -> 0.07484, featureWeights[0] -> 168.14847, cost -> 1.34029099E11
Iteration[2] ==> bias -> -70.60721, featureWeights[0] -> -159417.34, cost -> 1.20725801E17
Iteration[3] ==> bias -> 67012.305, featureWeights[0] -> 1.51299168E8, cost -> 1.0874295E23
Iteration[4] ==> bias -> -6.3599688E7, featureWeights[0] -> -1.43594258E11, cost -> 9.794949E28
Iteration[5] ==> bias -> 6.036088E10, featureWeights[0] -> 1.36281745E14, cost -> 8.822738E34
Iteration[6] ==> bias -> -5.7287012E13, featureWeights[0] -> -1.29341617E17, cost -> Infinity
Iteration[7] ==> bias -> 5.4369677E16, featureWeights[0] -> 1.2275491E20, cost -> Infinity
Iteration[8] ==> bias -> -5.1600908E19, featureWeights[0] -> -1.1650362E23, cost -> Infinity
Iteration[9] ==> bias -> 4.897313E22, featureWeights[0] -> 1.1057068E26, cost -> Infinity
Iteration[10] ==> bias -> -4.6479177E25, featureWeights[0] -> -1.0493987E29, cost -> Infinity
Iteration[11] ==> bias -> 4.411223E28, featureWeights[0] -> 9.959581E31, cost -> Infinity
Iteration[12] ==> bias -> -4.186581E31, featureWeights[0] -> -Infinity, cost -> Infinity
Iteration[13] ==> bias -> Infinity, featureWeights[0] -> NaN, cost -> NaN
Iteration[14] ==> bias -> NaN, featureWeights[0] -> NaN, cost -> NaN

यह यहाँ विषय है।
माइकल आर। चेरिक

3
अगर चीजें अनंत तक उड़ती हैं जैसा कि वे यहां करते हैं, तो आप शायद वेक्टर के पैमाने से विभाजित करना भूल रहे हैं।
StasK

5
मैथ्यू द्वारा स्वीकृत उत्तर स्पष्ट रूप से सांख्यिकीय है। इसका मतलब यह है कि इस सवाल का जवाब देने के लिए सांख्यिकीय (और प्रोग्रामिंग नहीं) विशेषज्ञता की आवश्यकता है; यह परिभाषा के आधार पर इसे विषय बनाता है। मैं फिर से वोट देने के लिए।
अमीबा का कहना है कि मोनिका

जवाबों:


35

संक्षिप्त उत्तर यह है कि आपके कदम का आकार बहुत बड़ा है। इसके बजाय घाटी की दीवार उतरते की, अपने कदम इतना बड़ा होता है कि आप करने के लिए एक तरफ से भर में कूद उच्च अन्य पर!

नीचे लागत समारोह:

यहाँ छवि विवरण दर्ज करें

लंबा जवाब यह है कि इस समस्या को हल करने के लिए एक भोले-भाले वंश के लिए यह मुश्किल है क्योंकि आपके लागत फ़ंक्शन के स्तर सेट हलकों के बजाय अत्यधिक लम्बी दीर्घवृत्त हैं। इस समस्या को मजबूती से हल करने के लिए, ध्यान दें कि चुनने के लिए अधिक परिष्कृत तरीके हैं:

  • एक स्टेप साइज (हार्डकॉडिंग ए स्थिरांक)।
  • एक कदम दिशा (ढाल वंश की तुलना में)।

समस्या को रेखांकित करें

अंतर्निहित समस्या यह है कि आपके लागत फ़ंक्शन के स्तर सेट अत्यधिक दीर्घवृत्तीय हैं, और यह क्रमिक वंश के लिए समस्याएं पैदा करता है। नीचे का आंकड़ा लागत फ़ंक्शन के लिए स्तर सेट दिखाता है।

  • 026.789
  • यदि चरण का आकार बहुत बड़ा है, तो आप वस्तुतः निचले नीले क्षेत्र पर कूदेंगे और नीचे उतरने के बजाय चढ़ेंगे।
  • θ0

मेरा सुझाव है कि यह जवाब Quora पर पढ़ें ।

यहाँ छवि विवरण दर्ज करें

जल्दी ठीक 1:

अपना कोड बदलें private float ALPHA = 0.0000002f;और आप ओवरसोइंग को रोक देंगे।

जल्दी ठीक 2:

XX

अधिक उन्नत सुधार

यदि लक्ष्य कुशलता से साधारण वर्ग को हल करने के बजाय साधारण वर्ग को हल करने के लिए था, तो एक कक्षा के लिए ग्रेडिएंट वंश सीखें:

  • चरण आकार की गणना करने के लिए और अधिक परिष्कृत तरीके हैं, जैसे लाइन खोज और आर्मिजो नियम
  • एक उत्तर के पास जहां स्थानीय स्थितियां प्रबल होती हैं, न्यूटन की विधि द्विघात अभिसरण प्राप्त करती है और एक कदम दिशा और आकार चुनने का एक शानदार तरीका है।
  • कम से कम वर्गों को हल करना एक रैखिक प्रणाली को हल करने के बराबर है। आधुनिक एल्गोरिदम भोले ढाल वंश का उपयोग नहीं करते हैं। बजाय:
    • k
    • बड़ी प्रणालियों के लिए, वे इसे तैयार करते हैं यह एक अनुकूलन समस्या है और क्रायलोव उप- विधियों जैसे पुनरावृत्त तरीकों का उपयोग करें ।

(XX)b=Xyb

वास्तविक समाधान है

  26.789880528523071
   0.165118878075797

आप पाएंगे कि वे लागत समारोह के लिए न्यूनतम मूल्य प्राप्त करते हैं।


5
+1 कोड को डीबग करना अन्य लोगों को बताने के लिए लक्जरी है!
हायताओ डू

4
@ hxd1011 मुझे लगा कि यह पहली बार एक गूंगा कोडिंग त्रुटि थी, लेकिन इसके बजाय यह (imho) एक काफी शिक्षाप्रद उदाहरण है कि क्या एक भोले ढाल वंश के साथ गलत हो सकता है।
मैथ्यू गुन

@ मट्टूगुन I को समाधान b = 0.99970686, m = 0.17655967 (y = mx + b) मिला। और "एक स्थिर हार्डकोडिंग की तुलना में एक कदम आकार" से आपका क्या मतलब है? क्या इसका मतलब है कि हमें इसे हर पुनरावृत्ति के लिए बदलना चाहिए? या हमें इनपुट वैल्यू के आधार पर इसकी गणना करने की आवश्यकता है?
अंबर बेरीवाल

αiiααif

@AmberBeriwal आप पाएंगे कि (26.789, .1651) की लागत थोड़ी कम होगी। यह उस दिशा से थोड़ा नीचे की ओर है (.9997, .1766) जहां एक दिशा में लागत समारोह में एक छोटा ढलान है।
मैथ्यू गुन

2

जैसा कि मैथ्यू (गुन) ने पहले ही संकेत दिया है, इस मामले में 3-आयामी लागत या प्रदर्शन फ़ंक्शन के समरूप अत्यधिक अण्डाकार हैं। चूंकि आपका जावा कोड ढाल वंश गणना के लिए एक सिंगल स्टेप-साइज वैल्यू का उपयोग करता है, वेट (यानी y- अक्ष इंटरसेप्ट और लीनियर फंक्शन के ढलान) के अपडेट दोनों ही इस सिंगल-स्टेप-साइज द्वारा शासित होते हैं ।

नतीजतन, बहुत छोटे कदम-आकार जो बड़े ढाल के साथ जुड़े वजन के अद्यतन को नियंत्रित करने के लिए आवश्यक है (इस मामले में, रैखिक फ़ंक्शन का ढलान) काफी हद तक सीमित करता है कि छोटे ढाल के साथ दूसरा वजन कितनी तेजी से होता है ( y- अक्ष रैखिक समारोह के अवरोधन) को अद्यतन किया जाता है। वर्तमान परिस्थितियों में, बाद का वजन लगभग 26.7 के अपने वास्तविक मूल्य में परिवर्तित नहीं होता है।

आपके जावा कोड को लिखने में आपके द्वारा निवेश किए गए समय और प्रयास को देखते हुए, मैं इसे दो असतत चरण-आकार मानों का उपयोग करने के लिए संशोधित करने का सुझाव दूंगा, प्रत्येक वजन के लिए एक उपयुक्त चरण-आकार। एंड्रयू एनजी अपने नोट्स में सुझाव देते हैं कि यह सुनिश्चित करने के लिए फीचर स्केलिंग का उपयोग करना बेहतर है कि लागत फ़ंक्शन के स्वरूप अधिक नियमित (अर्थात परिपत्र) रूप में हैं। हालाँकि, फीचर स्केलिंग को देखने के अलावा प्रत्येक भार के लिए एक अलग चरण-आकार का उपयोग करने के लिए अपने जावा कोड को संशोधित करना एक अच्छा व्यायाम हो सकता है।

एक और विचार करने के लिए विचार करना है कि प्रारंभिक वजन मूल्यों को कैसे चुना जाता है। अपने जावा कोड में आपने दोनों मानों को शून्य से आरंभ किया। छोटे, भिन्नात्मक मूल्यों के लिए वज़न को शुरू करना भी काफी आम है। इस विशेष मामले में, हालांकि, ये दोनों दृष्टिकोण त्रि-आयामी लागत फ़ंक्शन के अत्यधिक अण्डाकार (अर्थात गैर-परिपत्र) आकृति के प्रकाश में काम नहीं करेंगे। इस समस्या के लिए वजन को देखते हुए अन्य तरीकों का उपयोग करके पाया जा सकता है, जैसे मैथ्यू द्वारा उनके पद के अंत में सुझाए गए रैखिक प्रणाली के समाधान के लिए, आप वजन को सही वजन के करीब मानने की कोशिश कर सकते हैं और देख सकते हैं कि आपका मूल कोड कैसे है एक एकल चरण-आकार का उपयोग करना अभिसरण करता है।

आपके द्वारा पाया गया पायथन कोड आपके जावा कोड की तरह ही समाधान को प्राप्त करता है - दोनों एक ही चरण-आकार के पैरामीटर का उपयोग करते हैं। मैंने प्रत्येक वजन के लिए एक अलग चरण-आकार का उपयोग करने के लिए इस पायथन कोड को संशोधित किया। मैंने इसे नीचे शामिल किया है।

from numpy import *

def compute_error_for_line_given_points(b, m, points):
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        totalError += (y - (m * x + b)) ** 2
    return totalError / float(len(points))

def step_gradient(b_current, m_current, points, learningRate_1, learningRate_2):
    b_gradient = 0
    m_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        b_gradient += -(2/N) * (y - ((m_current * x) + b_current))
        m_gradient += -(2/N) * x * (y - ((m_current * x) + b_current))
    new_b = b_current - (learningRate_1 * b_gradient)
    new_m = m_current - (learningRate_2 * m_gradient)
    return [new_b, new_m]

def gradient_descent_runner(points, starting_b, starting_m, learning_rate_1, learning_rate_2, num_iterations):
    b = starting_b
    m = starting_m
    for i in range(num_iterations):
        b, m = step_gradient(b, m, array(points), learning_rate_1, learning_rate_2)
    return [b, m]

def run():
    #points = genfromtxt("data.csv", delimiter=",")
    #learning_rate = 0.0001
    #num_iterations = 200

    points = genfromtxt("test_set.csv", delimiter=",")
    learning_rate_1 = 0.5
    learning_rate_2 = 0.0000001
    num_iterations = 1000

    initial_b = 0 # initial y-intercept guess
    initial_m = 0 # initial slope guess


    print("Starting gradient descent at b = {0}, m = {1}, error = {2}".format(initial_b, initial_m, compute_error_for_line_given_points(initial_b, initial_m, points)))
    print("Running...")

    [b, m] = gradient_descent_runner(points, initial_b, initial_m, learning_rate_1, learning_rate_2, num_iterations)

    print("After {0} iterations b = {1}, m = {2}, error = {3}".format(num_iterations, b, m, compute_error_for_line_given_points(b, m, points)))

if __name__ == '__main__':
    run()

यह पायथन 3 के तहत चलता है, जिसमें "प्रिंट" स्टेटमेंट के लिए तर्क के चारों ओर कोष्ठकों की आवश्यकता होती है। अन्यथा यह कोष्ठकों को हटाकर पायथन 2 के तहत चलेगा। आपको एंड्रयू एनजी के उदाहरण से डेटा के साथ एक सीएसवी-फ़ाइल बनाने की आवश्यकता होगी।

अपने जावा कोड की जाँच करने के लिए पायथन कोड को क्रॉस-रेफरेंस का उपयोग कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.