딥러닝 이론:1. 선형회귀

milkbuttercheese·2023년 2월 1일
0

Dive_into_Deeplearning

목록 보기
1/7
post-custom-banner

선형회귀

  • 선형회귀 의 정의
  • 회귀계수의 이론적 추정
  • 선형회귀식의 변형

1. Linear Regression은 무엇인가?

  • 특징
    • 정량적인 종속변수를 예측하는데 쓰이는 도구이다.
    • 현대 통계학습중 일반화된 선형회귀법이 많은 부분을 차지한다
    • 선형회귀는 회귀문제를 다루는데 있어 가장 유명하고 간단한 형태의 툴이다.
  • 정의
    • 독립변수 x1,x2,...,xnx_1,x_2,...,x_n과 종속변수 yy, 계수 β0,β1,...,βn\beta_0,\beta_1,...,\beta_n 오차항 ϵ1,ϵ2,...,ϵn\epsilon_1,\epsilon_2,...,\epsilon_n이 있다하자
    • 다음과 같은 가정이 성립한다 한다.
      • 비확률변수nonstochastic :독립변수 x1,x2,...,xnx_1,x_2,...,x_n는 비확률변수이다(상수취급한다)
      • 선형성linearity: 계수와 종속변수 사이 선형성을 갖는다
      • 독립성:independence 독립변수가 다른 독립변수에 영향을 주지 않는다
      • 등분산성homoskedasticity: Var(ϵi)=σ2Var(\epsilon_i)=\sigma^2fori=1,2,...\,\,for\,\,i=1,2,...
      • 정규성normality: ϵN(0,σ2)\epsilon\sim \mathcal{N}(0,\sigma^2)
      • iji\ne j일때 Cov(ϵi,ϵj)=0Cov(\epsilon_i,\epsilon_j)=0 이다
  • 정의
    • 모델형태가 y^=i=1nβixi+β0+ϵ\hat{y}=\sum_{i=1}^{n}\beta_{i}x_i+\beta_0+\epsilon 이라고 가정하자. 그 계수값 β0,β1,β2,...,βn\beta_0,\beta_1,\beta_2,...,\beta_n 을 구한뒤, 해당 모델로 종속변수를 예측하는 일련의 방법론을 선형회귀라고 부른다
    • 모델형태를 벡터폼으로 정의할 수도 있다. y^=Xβ+b+ϵ\hat{y}=\boldsymbol{X}\boldsymbol{\beta}+b+\epsilon 이때
      - β=[β1,β2,,βn]\boldsymbol{\beta}=[\beta _{1},\beta _{2},\cdots,\beta _{n}] and b=β0{b}=\beta _{0}
      - XRm×n\boldsymbol{X} \in \mathbb{R} ^{m \times n} 는 design matrix라 불린다. 이 행렬은 jthj ^{th} 의 행이 jthj ^{th} 의 데이터포인트이다.
      - 이때 β=[β0,β1,,βn]\boldsymbol{\beta}=[\beta _{0},\beta _{1},\cdots,\beta _{n}] 으로 표현할수도 있으며 이런 경우 상수항 정보를 β\boldsymbol{\beta} 에 넣음으로써 항이 하나 줄어들게 작성할 수 있다. 이경우 X(i)=[1xi1xi2xin]\boldsymbol{X}^{(i)}=\begin{bmatrix} 1 & x _{i1} & x _{i2} & \cdots x _{in} \end{bmatrix} 이 된다. 아래서부턴 이 표현식을 활용한다

2. Loss-Function

  • L(β)=12i=1ny(i)y^(i)2L(\boldsymbol{\beta})=\displaystyle\frac{1}{2}\displaystyle\sum_{i=1}^{n}{|\boldsymbol{y}^{(i)}-\hat{\boldsymbol{y}}^{(i)}| ^{2}}
    - =12yy^2=\displaystyle\frac{1}{2}|\boldsymbol{y}-\hat{\boldsymbol{y}}| ^{2}
    - =12yXβ2=\displaystyle\frac{1}{2} \| \boldsymbol{y}-\boldsymbol{X}\boldsymbol{\beta} \| ^{2}
    - where X=[1x11x12x1n1x21x22x2n1xm1xm2xmn]\boldsymbol{X}=\begin{bmatrix} 1 & x_{11} & x _{12} & \cdots & x _{1n} \\ 1 & x _{21} & x _{22} & \cdots & x _{2n} \\ \cdots & \cdots & & \cdots & \\ 1 & x _{m1} & x _{m2} & \cdots & x _{mn} \end{bmatrix}
    - \boldsymbol{w}=\begin{bmatrix} 1 \\ \beta _{1} \\ \beta_{2 \\ } \\ \cdots \\ \beta _{n} \end{bmatrix}

  • 최적화된 회귀계수 찾기
    - 논리
    - L(β)L(\boldsymbol{\beta}) 를 최소화하는 β^\hat{\boldsymbol{\beta}} 가 최적화된 β\boldsymbol{\beta} 값이다
    - 순서
    - L(β)=YXβ2=YXβ,YXβ=L(\boldsymbol{\beta})=|\boldsymbol{Y}-\boldsymbol{X}\beta|^2=\langle \boldsymbol{Y}-\boldsymbol{X}\beta,\boldsymbol{Y}-\boldsymbol{X}\beta\rangle=(YXβ)T(YXβ)=(YTβTXT)(YXβ)=YTYYTXββTXTY+βTXTXβ(\boldsymbol{Y}-\boldsymbol{X}\beta)^T(\boldsymbol{Y}-\boldsymbol{X}\beta)=(\boldsymbol{Y}^T-\beta^T\boldsymbol{X}^T)(\boldsymbol{Y}-\boldsymbol{X}\beta)=\boldsymbol{Y}^T\boldsymbol{Y}-\boldsymbol{Y}^T\boldsymbol{X}\beta-\beta^T\boldsymbol{X}^T\boldsymbol{Y}+\beta^T\boldsymbol{X}^T\boldsymbol{X}\beta
    - =YTY2βTXTY+βTXTXβ=\boldsymbol{Y}^T\boldsymbol{Y}-2\beta^T\boldsymbol{X}^T\boldsymbol{Y}+\beta^T\boldsymbol{X}^T\boldsymbol{X}\beta
    - (Axx=A\displaystyle\frac{\partial {\boldsymbol{A}\boldsymbol{x}}}{\partial {\boldsymbol{x}}}=\boldsymbol{A}, xAxx=2Ax\displaystyle\frac{\partial {\boldsymbol{x}\boldsymbol{A}\boldsymbol{x}}}{\partial {\boldsymbol{x}}}=2\boldsymbol{A}\boldsymbol{x} (A\boldsymbol{A}가 대칭행렬일 경우)을 활용함)
    - 미분을 이용하여 RSSRSS를 최소화하는 계수값을 찾자
    - (L(β))β=2(XTY)T+2βT(XTX)=2YTX+2XTXβ=0\displaystyle\frac{\partial{(L(\boldsymbol{\beta}))}}{\partial\beta}=-2(\boldsymbol{X}^T\boldsymbol{Y})^T+2\beta^T(\boldsymbol{X}^T\boldsymbol{X})=-2\boldsymbol{Y}^T\boldsymbol{X}+2\boldsymbol{X}^T\boldsymbol{X}\beta=0
    - XTXβ=YTX\boldsymbol{X}^T\boldsymbol{X}\beta=\boldsymbol{Y}^T\boldsymbol{X}
    - β=(XTX)1(YTX)\beta=(\boldsymbol{X}^T\boldsymbol{X})^{-1}(\boldsymbol{Y}^T\boldsymbol{X}) : 추정된 β\beta

3. Minibatch Stochastic Gradient

  • 위와 같이 β=(XtX)1(YTX)\boldsymbol{\beta}=(\boldsymbol{X} ^{t}\boldsymbol{X}) ^{-1}(\boldsymbol{Y}^{T}\boldsymbol{X}) 가 계산이 되는, 즉 (XTX\boldsymbol{X}^{T}\boldsymbol{X}) 의 역행렬이 존재하는 상태라면 해석적으로 해를 구할수 있다
    - 이는 rank(TT))=rank(T))rank(T ^{*}T))=rank(T)) 로, 즉 각 데이터포인터의 집합이 모두 선형독립인 정보일때 이렇게 해석적으로 계산가능한 것이다
  • 반대로, 해석적으로 최적화된 β\boldsymbol{\beta} 값을 구할수 없더라도, 반복 계산을 통하여 근사하는 값을 찾을 수 있다. 이 방법이 gradent descent이다

Gradient descent

  • 반복적인 계산으로 Loss function L(β)L(\boldsymbol{\beta}) 값을 줄이는 파라미터 β\boldsymbol{\beta} 를 찾아가는 방법이다.
  • 종류
    - Batch gradient descent
    - loss function을 계산할 때 전체 훈련데이터셋을 활용하는 방법이다
    - stochastic gradient descent
    - loss function을 계산할 때 무작위로 선택된 하나의 데이터포인트만 활용하는 방법이다
    - 계산에 참가하는 데이터포인트가 적기 때문에 계산이 빠르지만 어떤 데이터포인트가 뽑힐지 모른다는 점에서 불안정성이 올라간다
    - minibatch gradient descent
    - loss function을 계산할 때 (주로 2의 n승) 특정 갯수의 데이터포인트를 뽑아 활용하는 방법이다
    - 계산
    - ββηBL(β)β\boldsymbol{\beta} \leftarrow \boldsymbol{\beta}-\displaystyle\frac{\eta}{|\mathcal{B}|}\displaystyle \cfrac{\partial {L(\boldsymbol{\beta})}}{\partial {\boldsymbol{\beta}}}
    - ββηBβiBt12(βTx(i)y(i))2\boldsymbol{\beta} \leftarrow\boldsymbol{\beta}-\displaystyle\frac{\eta}{|\mathcal{B}|}\cfrac{\partial {}}{\partial {\boldsymbol{\beta}}}\displaystyle\sum_{i \in \mathcal{B}_{t}}^{}{\displaystyle\frac{1}{2}(\boldsymbol{\beta}^{T}\boldsymbol{x}^{(i)}-\boldsymbol{y}^{(i)}) ^{2}}
    - ββηBβ(12XβY2)\boldsymbol{\beta} \leftarrow\boldsymbol{\beta}-\displaystyle\frac{\eta}{|\mathcal{B}|}\cfrac{\partial {}}{\partial {\boldsymbol{\beta}}}(\displaystyle\frac{1}{2}|\boldsymbol{\boldsymbol{X}\beta}-\boldsymbol{Y}| ^{2})
    - ββηB(2YTX+2XTXβ)\boldsymbol{\beta} \leftarrow \boldsymbol{\beta}-\displaystyle\frac{\eta}{|\mathcal{B}|}(-2\boldsymbol{Y}^T\boldsymbol{X}+2\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{\beta})
    - ββ2ηB(XTXβYTX)\boldsymbol{\beta} \leftarrow \boldsymbol{\beta}-\displaystyle\frac{2\eta}{|\mathcal{B}|}(\boldsymbol{X}^{T}\boldsymbol{X}\boldsymbol{\beta}-\boldsymbol{Y}^{T}\boldsymbol{X})

4. 노이즈 계산

  • 가정
    - ϵN(0,σ2)\epsilon \sim \mathcal{N}(0,\sigma ^{2})로 가정하자
    - y=βTx+ϵy=\boldsymbol{\beta}^{T}\boldsymbol{x}+\epsilon
  • 그렇다면 독립변수값이 x\boldsymbol{x} f로 주어져있을때 관측값이 yy 이라면
    - P(yx)=12πσ2exp[12σ2(yβTx)2]P(y|\boldsymbol{x})=\displaystyle\frac{1}{\sqrt{2 \pi \sigma ^{2}}}\cdot exp[-\displaystyle\frac{1}{2 \sigma ^{2}}(y-\boldsymbol{\beta}^{T}\boldsymbol{x}) ^{2}]
  • 최대우도추정의 원칙에 따라 P(yX)=i=1nP(y(i)x(i))P(y|\boldsymbol{X})=\prod_{i=1}^{n}{P(y ^{(i)}|x ^{(i)})}

5.모델 설계

Utilities

  • 우리가 만들고자 하는 수학적 모델들을 pythonclass 형태로 정의하자
  • 이때 필요한 함수를 미리 정의하여 둔다
"""
어떤 함수의 정의식 위에 @add_to_class(클래스)를 적는다면
해당 클래스의 메소드로 해당 함수가 추가되게 된다
"""
def add_to_class(Class):  #@save
    def wrapper(obj):
        setattr(Class, obj.__name__, obj)
    return wrapper

""" 
__init__함수: 특정 클래스가 클래스 내부에서 활용될 값을 
미리 저장해놓을 수 있게 해주는 함수. 이 값을 attribute라고 부른다
"""

Model 구조

  • 모듈
    - 현재 클래스를 파이토치의 neural network의 기본 클래스가 되는 nn.Module의 서브클래스로 정할 수 있다. 이를 활용하면 neural network를 활용하는 유용한 feature를 제공한다
  • 함수
    - __init__
    - 학습될 파라미터를 저장한다
    - training_step
    - 손실함수 계산에 활용될 training 데이터 배치 크기를 정한다
    - configure_optimizers
    - 손실함수 계산에 활용된 옵티마이저 종류를 반환한다
    - validation_step
    - 손실함수 계산에 활용될 validation 데이터 배치 크기를 정한다
    - loss
    - 손실함수 식을 정의하는 공간.
"""
Module 클래스에 속성을 nn.Module과 dl2.HyperParameters의 속성을
상속시킨다
super().__init__(): 부모 클래스인 nn.Module과 
dl2.Hyperparameters를 호출한다
"""
class Module(nn.Module, d2l.HyperParameters):
    def __init__(self,plot_train_per_epoch=2,
                    plot_valid_per_epoch=1) -> None:
        super().__init__()
        self.save_hyperparameters()
        self.board= ProgressBoard()

    #NotImplementedError:실행 시나리오중 구현되지 않음을 나타내는 것
    def loss(self,y_hat,y):
        raise NotImplementedError 
    
    """
    hasattr:argument로 넘겨준 object에 name의 속성이 존재하면 
    True 아니면 False를 반환한다

    assert: 이 조건이 참일때 코드를 보장한다. 이 조건이 거짓일때 
    보장하지 않은 동작이기에 AssertionError를 발생시켜라
    assert[조건][오류메시지] 순으로 작성됨
    """
    def foward(self,X):
        assert hasattr(self,'net'), 'Neural network is defined'
        return self.net(X)  # self.net속성이 없을시에 대해 오류를 제시하는 모습: 컴퓨터가 잘못 이해(self.net이 없다면 먼저 앞에서 종료되니까)
 
    def plot(self,key,value,train):
        """ plot a point in animation"""
        assert hasattr(self,'trainer') , 'Trainer is not inited'
        self.board.xlabel= 'epoch'
        if train:
            x = self.trainer.train_batch_idx / \
                self.trainer.num_train_batches
            n = self.trainer.num_train_batches / \
                self.plot_train_per_epoch
        else:
            x=self.trainer.epoch + 1
            n=self.trainer.num_val_batches /\
                self.plot_valid_per_epoch
        self.board.draw(x,value.to(d2l.cpu()).detach().numpy(),
            'train_' if train else 'val_' +key , every_n=int(n))
    
    """
    *batch[:-1]는 왼쪽 끝부터 오른쪽 끝 하나전까지의 부분배열을, 
    batch[-1]는 오른쪽 원소값을 지정한다
    """
    def training_step(self,batch):
        # *arg는 가변인자임을 의미한다
        l=self.loss(self(*batch[:-1]),batch[-1])
        self.plot('loss',l,train=True)
        return l
    
    def validation_step(self,batch):
        #
        l= self.loss(self(*batch[:-1]),batch[-1])
        self.plot('loss',l,train=False)

    def configure_optimizers(self):
        raise NotImplementedError
        

데이터

  • 함수
    - train_dataloader
    - 저장된 training 데이터를 반환한다
    - val_dataloader
    - 저장된 validation 데이터를 반환한다
    - get_dataloader
class DataModule(d2l.HyperParameters):
    def __init__(self,root='../data',num_workers=4) -> None:
        self.save_hyperparameters()

    def get_dataloader(self,train):
        raise NotImplementedError

    def train_dataloader(self):
        return self.get_dataloader(train=True)

    def val_dataloader(self):
        return self.get_dataloader(train=False)
   

훈련

  • Module 클래스의 학습가능한 파라미터를 DataModule 클래스를 활용하여 학습시킨다
  • 함수
    - __init
    - max_epoches : 에포크(총 데이터셋을 한번 학습하는 행위)의 수를 정할 수 있다
    - prepare_data
    - DataModule에서 training,validation 데이터셋과 training,validation 배치수를 받는다
class Trainer(d2l.HyperParameters):
    def __init__(self,max_epochs,num_gpus=0,
                gradient_clip_val=0) -> None:
        self.save_hyperparameters()
        assert num_gpus == 0, 'No GPU support yet'
    
    def prepare_data(self,data):
        self.train_dataloader = data.train_datalodaer()
        self.val_dataloader= data.val_datalodaer()
        self.num_train_batches = len(self.train_dataloader)
        self.num_val_batches = (len(self.val_dataloader) 
                if self.val_dataloader is not None else 0 )
    
    def prepare_model(self,model):
        model.trainer= self 
        model.board.xlim=[0,self.max_epochs]
        self.model= model

    def fit(self,model,data):
        self.prepare_data(data)
        self.prepare_model(model)
        self.optim= model.configure_optimzers()
        self.epoch=0
        self.train_batch_idx= 0
        self.val_batch_idx= 0
        for self.epoch in range(self.max_epochs):
            self.fit_epoch()

    
    def fit_epoch(self):
        raise NotImplementedError

Ref: Automatic Differentiation in Pytorch

  • 변수에 대한 도함수값 저장
    - x= torch.tensor(value,requires_grad=True)
    - requires_grad=True 조건 설정을 통하여 해당 변수의 도함수값을 저장한다
  • 수식 정의
    - y=f(x)
    - y.backward()
  • 수식의 도함수값 호출
    - x.grad : y 에 대한 x 의 편미분값임

선형회귀 모델 Scratch

  • 함수
    - __init__
    - 파라미터 β\boldsymbol{\beta} 의 가중치를 평균0, 표준편차 0.01의 가우시안 분포 bias를 0으로 초기값을 정한다
    - forward
    - Xβ\boldsymbol{X}\boldsymbol{\beta} 행렬곱을 계산하여준다
    - loss
    - 손실함수를 정의한다
    - 클래스 SGD
    - step : param -= self.lr * param *grad 로 값을 계산해준다
    - fit_epoch
    1. loss 값을 계산한다
    2. 한번의 학습이 완료될 때마다 requires_grad=False로 텐서에 저장된 미분값을 0으로 초기화한다
profile
안녕하세요!
post-custom-banner

0개의 댓글