傾斜降下法(2)


  • 傾斜降下法、確率傾斜降下法
  • 資料出所:『Python機械学習完璧ガイド』
  • import numpy as np
    import pandas as pd
    
    import matplotlib.pyplot as plt
    %matplotlib inline
    np.random.seed(0)
    y = 4X + 6
    Y=4 X+6モデル上でシミュレーション実績値のデータ値を作成
    (w1=4, w0=6)
    np.random.seed(0) # 랜덤으로 형성된 값을 고정시켜줌
    np.random.rand(100,1)[0:10]
        # 0~1 표준정규분포를 가진 100행 1열 np array
    array([[0.5488135 ],
           [0.71518937],
           [0.60276338],
           [0.54488318],
           [0.4236548 ],
           [0.64589411],
           [0.43758721],
           [0.891773  ],
           [0.96366276],
           [0.38344152]])
    np.random.seed(0)
    X = 2*np.random.rand(100,1)
    X[0:10] # 0 ~ 2 값 표준정규분포
    array([[1.09762701],
           [1.43037873],
           [1.20552675],
           [1.08976637],
           [0.8473096 ],
           [1.29178823],
           [0.87517442],
           [1.783546  ],
           [1.92732552],
           [0.76688304]])
    # y는 랜덤으로 생성된 X값에 매칭되는 값
    y = 6 + 4*X + np.random.randn(100,1) # random 값은 Noise를 위해 만듦
    # x, y 데이터 셋 scatter plot으로 시각화
    plt.scatter(X,y);

    誤差関数を最小化するためにw 0、w 1値の更新を作成する
    y_pred = w1*x + w0

  • 予測配列y predはnpである.dot(x, w1.T) + w0
    データX(1,2,...,100)を入力します.
    予測値はw 0+X(1)w 1+X(2)w 1+.+X(100)*w 1は、入力アレイXおよびw 1アレイの内部である.

  • 新しいw 1とw 0を更新
  • # w1 과 w0 를 업데이트하는 함수
    def get_weight_updates(w1, w0, X, y, lr=0.01): # 편미분값을 조정하는 학습값
        N = len(y)
        # 먼저 w1_update, w0_update를 각각 w1, w0의 shape와 동일한 크기를 가진 0 값으로 초기화
        w1_update = np.zeros_like(w1)
        w0_update = np.zeros_like(w0)
    
        # 예측 배열 계산하고 예측과 실제 값의 차이 계산
        y_pred = np.dot(X, w1.T) + w0
        diff = y - y_pred
    
        # w0_update를 dot 행렬 연산으로 구하기 위해 모두 1값을 가진 행렬 생성
        w0_factors = np.ones((N, 1))
    
        # w1과 w0을 업데이트할 w1_update와 w0_update 계산
        w1_update = -(2/N)*lr*(np.dot(X.T, diff))
        w0_update = -(2/N)*lr*(np.dot(w0_factors.T, diff))
    
        return w1_update, w0_update
    w0 = np.zeros((1,1))
    w1 = np.zeros((1,1))
    
    w1, w0
    (array([[0.]]), array([[0.]]))
    y_pred = np.dot(X, w1.T) + w0
    diff = y - y_pred
    
    print(diff.shape, '\n')
    (100, 1)
    w0_factors = np.ones((100,1))
    
    w1_update = -(2/100)*0.01*(np.dot(X.T, diff))
    w0_update = -(2/100)*0.01*(np.dot(w0_factors.T,diff))
    print(w1_update.shape, w0_update.shape)
    (1, 1) (1, 1)
    # 반복적으로 w1과 w0를 업데이트 하는 함수
    def gradient_descent_steps(X, y, iters=10000):
        # w0와 w1을 모두 0으로 초기화
        w0 = np.zeros((1,1))
        w1 = np.zeros((1,1))
    
        # iters만큼 반복적으로 get_weight_updates() 호출
        for ind in range(iters):
            # w0, w1 업데이트
            w1_update, w0_update = get_weight_updates(w1, w0, X, y, lr=0.01)
            w1 = w1 - w1_update
            w0 = w0 - w0_update
    
        return w1, w0 # iter만큼 업데이트된 w1, w0 반환
    # 오차 함수 정의
    def get_cost(y, y_pred):
        N = len(y)
        cost = np.sum(np.square(y - y_pred))/N
        return cost
    傾斜降下更新w 1,w 0の実行
    w1, w0 = gradient_descent_steps(X, y, iters=70000)
    print("w1: {0:.3f} w0: {1:3f}".format(w1[0,0], w0[0,0]),'\n')
    
    y_pred = w1[0,0]*x+w0
    print('Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred)))
    w1: 3.968 w0: 6.222151
    
    Gradient Descent Total Cost:0.9924
    plt.scatter(x,y)
    plt.plot(x,y_pred);

    小規模(確率GD)を用いたコスト関数の最適化
    データ全体のチルトダウン操作には時間がかかります
    したがって、小型レイアウトでサンプリングを行うと、傾斜降下を迅速に実行できます.
    def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000):
        w0 = np.zeros((1,1))
        w1 = np.zeros((1,1))
        prev_cost = 100000
        iter_index = 0
    
        for i in range(iters):
            np.random.seed(i)
            # 전체 x,y 데이터를 batch_size로 랜덤추출하여 sample에 부여
            stochastic_random_index = np.random.permutation(X.shape[0])
            # 랜덤순열 만들기
            sample_X = X[stochastic_random_index[0:batch_size]]
            sample_y = y[stochastic_random_index[0:batch_size]]
    
            # 미니배치 임의 추출
            # batch_size만큼 추출된 랜덤데이터로 w1, w0 update
            w1_update, w0_update = get_weight_updates(w1, w0, sample_X, sample_y, lr=0.01)
            w1 = w1 - w1_update
            w0 = w0 - w0_update
    
        return w1, w0
    w1, w0 = stochastic_gradient_descent_steps(X, y, iters=50000)
    print("w1", round(w1[0,0],3), "w0",round(w0[0,0],3))
    y_pred = w1[0,0] * X + w0
    print(f"Stochastic Gradient Descent Total Cost: {get_cost(y,y_pred):.4f}")
    w1 3.991 w0 6.202
    Stochastic Gradient Descent Total Cost: 0.9926
    ->前とほぼ同様にw 1,w 0値をエクスポート