최적화 문제 - 경사도 하강 (Gradient Descent) 알고리즘 & 샘플 코드 및 관련 확장
17749 단어 최적화 문제
β
X
Y≈f(X,β)
구체 적 인 응용 장면, 예 를 들 어 광고 시스템 의 온라인 트 래 픽 예측 (온라인 트 래 픽 분 배 를 통 해 계약 식 보 유량 표현 확보) 은 트 래 픽 예측 을 통 해 광고 시스템 수익 을 최적화 시 킬 수 있다. 대부분의 회귀 분석 에서 알 수 없 는 변수의 구 해 는 대부분 목표 함수 최적화 로 이 루어 졌 다.
min∑i=0n(yi−f(xi,β))
상기 수학 표현 식 에서 x i 는 제 i 개 견본 의 특징 값 (벡터) 을 나타 내 고 y i 는 대응 하 는 목표 값 을 나타 내 며 f 는 함수 (이 부분 은 일반적으로 선험 지식 에서 얻 을 수 있 으 며, 예 를 들 어 다항식) 를 나타 낸다. 만약 견본 공간 에서 모든 점 이 상기 수학 등식 을 최소 화 할 수 있다 면 (어떻게 정의 하여 최소 화 합 니까? 일반적으로 엔지니어 가 밸브 값 을 설정 합 니 다)공정 상 우 리 는 함수 f 와 \ beta 가 견본 공간 과 목표치 의 관 계 를 잘 묘사 했다 고 생각 합 니 다. 구 해 된 목표 함수 가 미 지 의 견본 을 잘 묘사 할 수 있 는 지 에 대해 본 고의 토론 범위 에 있 지 않 습 니 다. 관심 이 있 는 독 자 는 회귀 분석 에서 의 과 의합 문제 (overfitting) 를 검색 할 수 있 습 니 다. 본 블 로 그 는 경사 하강 (gradient descent) 을 통 해 어떻게 하 는 지 에 중심 을 두 고 토론 할 것 입 니 다.알고리즘 은 회귀 분석의 최적화 문제 와 관련 확장 알고리즘 을 해결 합 니 다. 회귀 분석 에 관 한 토론 은 본 편의 토론 을 넘 어 섰 습 니 다. 여기 서 간단하게 건 너 뛰 고 관심 이 있 는 독자 들 은 볼 수 있 습 니 다 [2].
이론 부분
우선 경사도 가 떨 어 지 는 기본 사상 을 살 펴 보 자. 여기 서 우 리 는 목표 함 수 를 다시 인용 하 자.
F(β)=min(∑i=0n(yi−f(xi,β)))
그 중에서 \ beta 는 알 수 없 는 변수 입 니 다. 우 리 는 F (돌출 함수 - convex function) 가 지정 한 도 메 인 에서 유도 할 수 있다 고 가정 합 니 다. 유도 할 수 없 는 함수 에 대한 최적화 해법 은 (차 계단 subgradient method) 을 볼 수 있 습 니 다. 만약 에 우리 가 \ beta 를 F (x) 1 단계 도체 의 방향 으로 변화 시 키 면 우 리 는 확보 할 수 있 습 니 다.
F(β(k))≤F(β(k−1))
이 를 위해 알 수 없 는 변 수 를 초기 화 할 수 있 습 니 다. \ beta 0. 알 수 없 는 변 수 를 업데이트 / 탐색 할 때마다 \ beta 를 따라 갑 니 다.
∂F∂β
1 단계 도체 의 마이너스 방향 이 일정한 걸음 길 이 를 바 꿉 니 다. (여기 서 우 리 는 r 를 상수 로 하 는 상황 을 먼저 토론 합 니 다. 만약 r 가 충분 하 다 면) 코드 실현 에서 우 리 는 목표 함수 의 1 단계 도 수 를 미리 계산 해 야 합 니 다.
β(k)=β(k−1)−r∗∂F∂βk−1
샘플 코드 부분
# -*- encoding: utf-8 -*-
import re
import sys
import numpy as np
import copy
import time
def timeConsumption(func):
def func_wrapper(x):
start_time = time.time()
func(x)
end_time = time.time()
print "[Function-Time-Consumption] ", end_time - start_time
return func_wrapper
def initialize(length=300):
"""
"""
X = []
Y = []
mu, sigma = 0, 0.1
V = 100
# here we assume x is two-dimesion matrix
for i in np.random.random(length):
a = i * V
for j in np.random.random(length):
b = j * V
X.append([a**2, b**2, a, b, 1, 1])
# white noise
noise = np.random.normal(mu, sigma, size=length * length)
# a * x**2 + b * x + c
function = lambda x: np.dot([3.0, -1.5, 3.5, -2, 4, 1.0], x)
Y = [function(X[i]) + noise[i] for i in range(length * length)]
return X, Y
class GradientDescent(object):
"""
"""
def __init__(self, X, Y, eplison=0.000001, gama=0.01, iter_num=10000):
"""
"""
_d = X.shape[-1]
# parameter initailization
self.a = np.random.normal(0, 1, size=_d)
self.X = X
self.Y = Y
self.eplison = eplison
self.gama = (1.0 / max(Y)) * 1.0 / len(X)
self.iter_num = iter_num
def function(self, a, x):
"""
Do we have prior knowledge about the function?
- quadratic ?
- exponential ?
- linear ?
"""
return np.dot(a, x)
@timeConsumption
def run(self):
"""
"""
derative = []
for i in range(len(self.a)):
derative.append(np.mean([x[i] for x in self.X]))
local_y = [self.function(self.a, x) for x in self.X]
diff = np.mean(np.subtract(local_y, self.Y))
while self.iter_num > 0:
local_a = copy.copy(self.a)
for i in range(len(local_a)):
local_a[i] -= self.gama * derative[i] * diff
local_y = [self.function(local_a, x) for x in self.X]
diff = np.mean(np.subtract(local_y, self.Y))
print diff
self.a = local_a
self.iter_num -= 1
if abs(diff) < self.eplison: break
print self.a
def main():
"""
"""
X, Y = initialize()
# time-consumption for length of 300 is 298.651947021, dependent on initialize value
# instance = GradientDescent(np.array(X), np.array(Y))
# instance.run()
# time-consumption for length of 300 is 290.654798031
instance = StochasticGradientDescent(np.array(X), np.array(Y))
instance.run()
# time-consumption for length of 300 is 287.527049065, dependent on initialize value
# instance = MiniBatchGradientDescent(np.array(X), np.array(Y))
# instance.run()
if __name__ == "__main__":
reload(sys)
sys.setdefaultencoding("utf-8")
main()
경사도 하강 확장 부분
구체 적 인 프로젝트 가 실 현 될 때 훈련 데이터 가 너무 커서 메모리 에 전부 불 러 올 수 없 거나 훈련 량 이 많아 훈련 이 느 릴 수 있 습 니 다 (변수 업데이트 때마다 전체 데 이 터 를 한 번 씩 필요 로 합 니 다). 이때 우 리 는 경사도 가 떨 어 지 는 집중 변형 을 사용 할 수 있 습 니 다 [2]: - 대량 경사도 하락 (Batch Gradient Descent) - 랜 덤 경사도 하락 (Stochastic Gradient Descent)- 소량 경사도 하강 (Mini - Patch Gradient Descent)
상기 알고리즘 의 기본 사상 은 사다리 가 떨 어 지 는 것 과 비슷 하 다. 변 수 를 업데이트 할 때 모든 훈련 데이터 의 양 이 다 르 고 대량의 사다리 가 떨 어 지면 매번 에 의존 하 는 훈련 집합의 양 을 미리 설정 하고 무 작위 사다리 가 떨 어 지면 모든 훈련 데이터 가 한 번 씩 변 수 를 업데이트 한다.
class StochasticGradientDescent(GradientDescent):
def __init__(self, X, Y, eplison=0.000001, gama=0.01, iter_num=300):
super(StochasticGradientDescent, self).__init__(X, Y, eplison, gama, iter_num)
@timeConsumption
def run(self):
derative = []
for i in range(len(self.a)):
derative.append(np.mean([x[i] for x in self.X]))
LENGTH = len(self.X)
i = np.random.randint(0, LENGTH, 1)
local_y = self.function(self.a, self.X[i].reshape(-1))
diff = local_y - self.Y[i]
# https://en.wikipedia.org/wiki/Stochastic_gradient_descent
learning_rate = self.gama
den = self.iter_num
while self.iter_num > 0:
local_a = copy.copy(self.a)
for i in range(len(local_a)):
local_a[i] -= learning_rate * derative[i] * diff
i = np.random.randint(0, LENGTH, 1)
local_y = self.function(local_a, self.X[i].reshape(-1))
diff = local_y - self.Y[i]
self.a = local_a
self.iter_num -= 1
learning_rate = self.gama * self.iter_num / den
_temp = [self.function(local_a, x) for x in self.X]
_diff = np.mean(np.subtract(_temp, self.Y))
print _diff
if abs(_diff) < self.eplison: break
# make sure result converge
while abs(_diff) > self.eplison:
local_a = copy.copy(self.a)
for i in range(len(local_a)):
local_a[i] -= self.gama * derative[i] * _diff
local_y = [self.function(local_a, x) for x in self.X]
_diff = np.mean(np.subtract(local_y, self.Y))
print _diff
self.a = local_a
print self.a
class MiniBatchGradientDescent(GradientDescent):
def __init__(self, X, Y, eplison=0.000001, gama=0.01, iter_num=300, batch=100):
super(MiniBatchGradientDescent, self).__init__(X, Y, eplison, gama, iter_num)
self.batch = int(0.1 * self.X.shape[0])
@timeConsumption
def run(self):
derative = []
for i in range(len(self.a)):
derative.append(np.mean([x[i] for x in self.X]))
LENGTH = len(self.X)
local_a = copy.copy(self.a)
learning_rate = self.gama
den = self.iter_num
_diff = 0
while self.iter_num > 0:
index = np.random.randint(0, LENGTH, self.batch)
data = self.X[index]
local_y = [self.function(local_a, x) for x in data]
diff = np.mean(np.subtract(local_y, self.Y[index]))
for i in range(len(local_a)):
local_a[i] -= learning_rate * derative[i] * diff
self.a = local_a
self.iter_num -= 1
learning_rate = self.gama * self.iter_num / den
_temp = [self.function(local_a, x) for x in self.X]
_diff = np.mean(np.subtract(_temp, self.Y))
print _diff
if abs(_diff) < self.eplison: break
# without follow code, diff do not converge to minimize
# make sure result converge
while abs(_diff) > self.eplison:
local_a = copy.copy(self.a)
for i in range(len(local_a)):
local_a[i] -= self.gama * derative[i] * _diff
local_y = [self.function(local_a, x) for x in self.X]
_diff = np.mean(np.subtract(local_y, self.Y))
print _diff
self.a = local_a
print self.a
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
최적화 문제 - 경사도 하강 (Gradient Descent) 알고리즘 & 샘플 코드 및 관련 확장대응 변수 y 와 알 수 없 는 변수 \ 베타 와 독립 변수 x 의 함수 관 계 를 찾 고 싶 습 니 다. 상기 수학 표현 식 에서 x i 는 제 i 개 견본 의 특징 값 (벡터) 을 나타 내 고 y i 는 대응 하...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.