(12주차) 11월30일
기울기소멸, 추천시스템
-
(1/3) 기울기소멸
-
(2/3) 추천시스템
-
(3/3) 숙제설명
-
중간에 한명이라도 잘못 말한다면..
-
In machine learning, the vanishing gradient problem is encountered when training artificial neural networks with gradient-based learning methods and backpropagation.
-
당연한것 아닌가?
- 그레디언트 기반의 학습 (그레디언트 기반의 옵티마이저): 손실함수의 기울기를 통하여 업데이트 하는 방식
- 역전파: 손실함수의 기울기를 구하는 테크닉 (체인룰 + $\alpha$). 구체적으로는 (1) 손실함수를 여러단계로 쪼개고 (2) 각 단계의 미분값을 각각 구하고 (3) 그것들을 모두 곱하여 기울기를 계산한다.
- 0 근처의 숫자를 계속 곱하면 터지거나 0으로 간다. (사실 안정적인 기울기가 나올 것이라고 생각하는것 자체가 사실 이상함)
import numpy as np
grads = np.random.uniform(low=-2,high=2,size=100)
grads
grads.prod()
- 기울기가 소멸함
grads = np.random.uniform(low=-5,high=5,size=100)
grads.prod()
- 기울기가 폭발함.
grads = np.random.uniform(low=-1,high=3.5,size=100)
grads.prod()
-
도깨비: 기울기가 소멸하기도 하고 터지기도 한다.
-
개념
- 데이터 $\to$ (아키텍처,손실함수,역전파,업데이트)
-
Multi-level hierarchy
- 여러층을 쪼개서 학습하자 $\to$ 어떻게? 사전학습, 층벼학습
- 기울기소실문제를 해결하여 딥러닝을 유행시킨 태초의(?) 방법임.
- 결국 입력자료를 바꾼뒤에 학습하는 형태
-
Faster hardware
- GPU를 중심으로 한 테크닉
- 근본적인 문제해결책은 아니라는 힌튼의 비판
- CPU를 쓸때보다 GPU를 쓰면 약간 더 깊은 모형을 학습할 수 있다 정도?
-
Residual networks
- 훌륭한 접근법중 하나임
- 아키텍처를 변경하는 방법이지만, 사실상 손실함수를 부드럽게 만드는 기법으로 이해해도 된다.
- 솟컷이라는 아키텍처를 추가하여 이리저리 실험해보니까 손실함수가 부드러워졌다. <--- 이런게 아니고
- 손실함수를 부드럽게 하기 위해서는 층별의차이(residual)를 학습하는게 유리할 것 같다. 그런데 이것을 위한 효과를 주기 위해서는 단지 아키텍처에 숏만만 추가하면 되겠다. <--- 이런 모티브였을 것이다.
-
Other activation functions
- 렐루의 개발
-
배치정규화
- 어쩌다보니 되는것.
- 배치정규화는 원래 공변량 쉬프트를 잡기 위한 방법임. 그런데 기울기 소멸에도 효과가 있음. 현재는 기울기소멸문제에 대한 해결책으로 빠짐없이 언급되고 있음. 2015년의 원래 논문에는 기울기소멸에 대한 언급은 없었음. (https://arxiv.org/pdf/1502.03167.pdf)
- 심지어 배치정규화는 오버피팅을 잡는효과도 있음 (이것은 논문에 언급했음)
-
기울기를 안구하면 안되나?`
- 베이지안 최적화기법: (https://arxiv.org/pdf/1807.02811.pdf) $\to$ GPU를 어떻게 쓰지? $\to$ 느리다
import pandas as pd
import torch
from fastai.collab import *
from fastai.tabular.all import *
df=pd.read_csv('https://raw.githubusercontent.com/guebin/2021BDA/master/_notebooks/2021-11-30-recommend.csv')
df
-
아래와 같은 매트릭스를 고려하자.
df2 = pd.DataFrame([[None]*20]*100,columns=['커피'+str(i) for i in range(1,11)]+['홍차'+str(i) for i in range(1,11)])
df2.index = pd.Index(['user'+str(i) for i in range(1,101)])
df2
for (i,j) in zip(df.user.to_list(), df.item.to_list()):
df2.iloc[i-1,j-1]=df.query('user == @i and item == @j')['rating'].to_list()[0]
df2.iloc[:5]
- user1~user5는 대체로 커피를 선호한다.
- user1은 커피 2,3,7,8,9,10을 먹지는 않았는데, 아마 먹었다면 높은 점수를 주었을 것임.
df2.iloc[47:53]
- user1 $\sim$ user50은 커피를 선호하고 user51 $\sim$ user100은 홍차를 선호함
df2.iloc[94:]
-
None의 값을 추론하는 방법? 머리속으로는 알고있음. 그런데 어떻게 수식화 할지?
df2.loc['user1']
-
유저의 취향은 예를들면 아래와 같이 표현할 수 있다.
- user1의 취향 = (커피좋아함, 홍차싫어함) = (0.8, 0.21)
-
코딩해보자.
user1_prprnc = (0.8,0.21)
user1_prprnc
-
여기에서 (0.8,0.21)은 각각 (커피음료,홍차음료)와 같은 음료의 특징으로 해석가능. 현재는 단순하게 원소가 2인 벡터이지만 다양한 feature도 가능하다.
- 음료의특징: (커피음료, 홍차음료, 우유포함, 설탕포함정도, 아이스여부, 행사여부)
-
아이템4와 아이템11의 특징은 예를들면 아래와 같이 표현할 수 있다.
item4_ftr = (0.71, 0.03) # 커피4
item11_ftr = (0.1, 0.88) # 홍차1
-
유저의 선호도와 아이템의 feature를 내적하여보자.
np.array(user1_prprnc) @ np.array(item4_ftr)
np.array(user1_prprnc) @ np.array(item11_ftr)
-
유저의 선호도와 item의 feature가 비슷할수록 값이 높게 나온다. 실제로 user1이 커피4와 홍차1에 매긴 평점은 (4.078139,1.142659) 인데 (0.5743, 0.2648) 가 실제평점과 비슷하게 나오도록 하면 좋겠다.
-
적당히 값을 조정하여 보자.
user1_prprnc = (0.8,0.21)
item4_ftr = (5, 0.03) # 커피4
item11_ftr = (0.1, 4.8) # 홍차1
np.array(user1_prprnc) @ np.array(item4_ftr)
np.array(user1_prprnc) @ np.array(item11_ftr)
-
신기한것은 이 파라메터들이 있다면 None에 대한 추론도 가능하다는 것이다. 예를들어서 user2는 홍차1을 먹지 않았지만 item11_ftr(홍차1)의 계수값
이 다른유저를 통해 학습되었다면 user2가 홍차1을 먹고 내릴 평점이 예측가능하다.
df2.loc['user2']
user2_prprnc = (0.77,0.18)
np.array(user2_prprnc) @ np.array(item11_ftr)
-
생각해보니까 user1_prprnc
, ... , user100_prprnc
, item1_ftr
, ... , item20_ftr
를 ${\bf W}$라고 해석하면 우리가 ${\bf W}$ 바꿈에 따라 예측값과 손실이 결정되므로 네트워크 구조가 만들어진다.
-
정리하면 적당한 아래와 같은 매트릭스를 정의하여
- ${\bf U} = \begin{bmatrix} \tt user1~ prprnc \\ \dots \\ \tt user100~prprnc \end{bmatrix}$ $\quad 100 \times 2$ mat
- ${\bf V} = \begin{bmatrix} \tt item1~ ftr \\ \dots \\ \tt item20~ftr \end{bmatrix}$ $\quad 20 \times 2$ mat
${\bf U}{\bf V}^\top \approx $ df2
가 만족하도록 하면 된다. (None은 무시)
dls=CollabDataLoaders.from_df(df,bs=100)
dls.items
lrnr = collab_learner(dls,n_factors=2,y_range=(0,5))
lrnr.fit(30,0.01)
lrnr.show_results()
-
학습이 잘 되었음.
X,y = dls.one_batch()
X[:5]
y[:5]
torch.tensor([[94,3]])
lrnr.model(torch.tensor([[94,3]]).to("cuda:0"))
x100 = torch.tensor([[100,j] for j in range(1,21) ])
lrnr.model(x100.to("cuda:0"))
-
예상대로 홍차를 매우 좋아함.
숙제는 유저2번에 대한 선호도 조사