기계학습 특강 (4주차) 9월28일
딥러닝의 기초 - 회귀분석(2)--step1~4, step1의 다른표현, step4의 다른표현, 로지스틱 intro
- imports
- numpy, torch (선택학습)
- Review: step1~4
- step1의 다른버전 -- net 설계만
- step1의 다른버전 -- 끝까지
- step4의 다른버전: 옵티마이저!
- Appendix: net.parameters()의 의미? (선택학습)
- Logistic regression
- 숙제
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import torch
-
torch.tensor() = np.array() 처럼 생각해도 무방
np.array([1,2,3]), torch.tensor([1,2,3])
-
소수점의 정밀도에서 차이가 있음 (torch가 좀 더 쪼잔함)
np.array([3.123456789])
torch.tensor([3.123456789])
(서연필기)tensor는 gpu에 저장하기 때문에 메모리 아끼기 위해 정밀도가 낮은 경향이 있다.
-
기본적인 numpy 문법은 np 대신에 torch를 써도 무방 // 완전 같지는 않음
np.arange(10), torch.arange(10)
np.linspace(0,1,10), torch.linspace(0,1,10)
np.random.randn(10)
torch.randn(10)
브로드캐스팅 길이가 3인 벡터와 1인벡터를 더하면 오류 뜨지 않고 더해줌
-
길이가 3인 벡터 선언방법
a = torch.tensor([1,2,3])
a.shape
-
3x1 col-vec 선언방법
(방법1)
a = torch.tensor([[1],[2],[3]])
a.shape
(방법2)
a = torch.tensor([1,2,3]).reshape(3,1)
a.shape
-
1x3 row-vec 선언방법
(방법1)
a = torch.tensor([[1,2,3]])
a.shape
(방법2)
a = torch.tensor([1,2,3]).reshape(1,3)
a.shape
-
3x1 col-vec 선언방법, 1x3 row-vec 선언방법에서 [[1],[2],[3]]
혹은 [[1,2,3]]
와 같은 표현이 이해안되면 아래링크로 가셔서
https://guebin.github.io/STBDA2022/2022/03/14/(2주차)-3월14일.html
첫번째 동영상 12:15 - 22:45 에 해당하는 분량을 학습하시길 바랍니다.
-
기본적으로 torch는 소수점으로 저장되면 dtype=torch.float32 가 된다. (이걸로 맞추는게 편리함)
tsr = torch.tensor([1.23,2.34])
tsr
tsr.dtype
-
정수로 선언하더라도 dtype를 torch.float32로 바꾸는게 유리함
(안 좋은 선언예시)
tsr = torch.tensor([1,2])
tsr
tsr.dtype
(좋은 선언예시1)
tsr = torch.tensor([1,2],dtype=torch.float32)
tsr
tsr.dtype
(좋은 선언예시2)
tsr = torch.tensor([1,2.0])
tsr
tsr.dtype
(사실 int로 선언해도 나중에 float으로 바꾸면 큰 문제없음)
tsr = torch.tensor([1,2]).float()
tsr
tsr.dtype
-
왜 정수만으로 torch.tensor를 만들때에도 torch.float32로 바꾸는게 유리할까? $\to$ torch.tensor끼리의 연산에서 문제가 될 수 있음
별 문제 없을수도 있지만
torch.tensor([1,2])-torch.tensor([1.0,2.0])
아래와 같이 에러가 날수도 있다
(에러1)
torch.tensor([[1.0,0.0],[0.0,1.0]]) @ torch.tensor([[1],[2]])
(에러2)
torch.tensor([[1,0],[0,1]]) @ torch.tensor([[1.0],[2.0]])
(해결1) 둘다 정수로 통일
torch.tensor([[1,0],[0,1]]) @ torch.tensor([[1],[2]])
(해결2) 둘다 소수로 통일 <-- 더 좋은 방법임
torch.tensor([[1.0,0.0],[0.0,1.0]]) @ torch.tensor([[1.0],[2.0]])
-
행렬곱셈에 대한 shape 조심
A = torch.tensor([[2.00,0.00],[0.00,3.00]])
b1 = torch.tensor([[-1.0,-5.0]])
b2 = torch.tensor([[-1.0],[-5.0]])
b3 = torch.tensor([-1.0,-5.0])
A.shape,b1.shape,b2.shape,b3.shape
-
A@b1: 계산불가, b1@A: 계산가능
A@b1
b1@A
-
A@b2: 계산가능, b2@A: 계산불가
A@b2
b2@A
-
A@b3: 계산가능, b3@A: 계산가능
(A@b3).shape ## b3를 마치 col-vec 처럼 해석
(b3@A).shape ## b3를 마지 row-vec 처럼 해석
- 뒤에 놓으면 b3를 컬럼벡터로 인식
- 앞에 놓으면 b3를 로우벡터로 인식
-
브로드캐스팅
a = torch.tensor([1,2,3])
a - 1
b = torch.tensor([[1],[2],[3]])
b - 1
계산이 되지 않아야 맞지 않나
a - b # a를 row-vec 로 해석
잘못 계싼할 수 있으니 dimension 명시해주자
df = pd.read_csv("https://raw.githubusercontent.com/guebin/DL2022/master/_notebooks/2022-09-22-regression.csv")
df
plt.plot(df.x, df.y,'o')
torch.tensor(df.x)
(서연필기)
float64 숫자 정밀 저장
float32이면 dtype=torch.float64)
꼬리표가 붙지 않음
_trt = torch.tensor(df.x).float()
_trt = torch.tensor(df.x,dtype=float30)
같은 역할, 메모리 적게 쓰기 위해 타입 바꿔주자
x= torch.tensor(df.x,dtype=torch.float32).reshape(100,1)
컬럼형식으로 받아주기 위해 변경
x= torch.tensor(df.x,dtype=torch.float32).reshape(100,1)
y= torch.tensor(df.y,dtype=torch.float32).reshape(100,1)
_1= torch.ones([100,1])
X = torch.concat([_1,x],axis=1)
pyhon
torch.ones([100,1])
torch.tensor([[1]*100,x]).T
같은 셋
What = torch.tensor([[-5.0],[10.0]],requires_grad=True)
What
requires_grad=True
reshape 미분 가능 옵션 주기 전에 shape 정해주자
plt.plot(x,y,'o')
#plt.plot(x,-5+10*x,'--')
plt.plot(x,X@What.data,'--')
alpha = 1/1000
What = torch.tensor([[-5.0],[10.0]],requires_grad=True)
for epoc in range(30):
# step1: yhat
yhat = X@What
# step2: loss
loss = torch.sum((y-yhat)**2)
# step3: 미분
loss.backward()
# step4: update
What.data = What.data - alpha * What.grad
What.grad = None #
What
plt.plot(x,y,'o')
plt.plot(x,X@What.data,'--')
- note: 왜 What = What - alpha*What.grad 는 안되는지?
What
What.data
What과 What.data는 달라요, requires_grad=True 미분 가능 꼬리표가 붙지 않기 때문!
alpha = 1/10
What = torch.tensor([[-5.0],[10.0]],requires_grad=True)
for epoc in range(30):
# step1: yhat
yhat = X@What
# step2: loss
loss = torch.mean((y-yhat)**2)
# step3: 미분
loss.backward()
# step4: update
What.data = What.data - alpha * What.grad
What.grad = None #
What
(서연필기)mean 정의
- 데이터를 더 효율적으로 학습 가능, 데이터 수만큼 안 해도 돼, 계산 덜 해도 돼
torch.nn.Linear?
input 잡는 법
- x의 컬럼 부분을 input이라고 생각하자
x.shape
output 잡는 법
- y의 컬럼 부분을 output이라고 생각하자
y.shape
_net = torch.nn.Linear(in_features=1, out_features=1, bias=True)
_net(x).shape
_net.bias # w0
_net.weight # w1
torch.manual_seed(43052)
net = torch.nn.Linear(in_features=1, out_features=1, bias=True)
net.bias, net.weight
plt.plot(x,y,'o')
plt.plot(x,net(x).data,'--')
w0hat = -0.847
w1hat = -0.3467
plt.plot(x,w0hat+w1hat*x,'--')
출력결과 같음을 확인
-
net에서 $\hat{w}_0, \hat{w}_1$ 의 값은?
net.weight # w1
net.bias # w0
_yhat = -0.8470 + -0.3467*x
plt.plot(x,y,'o')
plt.plot(x, _yhat,'--')
plt.plot(x,net(x).data,'-.')
-
수식표현: $\hat{y}_i = \hat{w}_0 + \hat{w}_1 x_i = \hat{b} + \hat{w}x_i = -0.8470 + -0.3467 x_i$ for all $i=1,2,\dots,100$.
-
입력이 x가 아닌 X를 넣고 싶다면? (보통 잘 안하긴 해요, 왜? bias=False로 주는게 귀찮거든요)
- X는 바이어스가 고려된 상황
net(X) ## 그대로 쓰면 당연히 에러
torch.manual_seed(43052)
net = torch.nn.Linear(in_features=2, out_features=1, bias=False)
net(X).shape
net.weight
위에 $w_0,w_1$ 순
net.bias
bias 없음을 확인
plt.plot(x,y,'o')
plt.plot(x,net(X).data, '--')
plt.plot(x,X@torch.tensor([[-0.2451],[-0.5989]]), '-.')
-
수식표현: $\hat{\bf y} = {\bf X} {\bf \hat W} = \begin{bmatrix} 1 & x_1 \\ 1 & x_2 \\ \dots & \dots \\ 1 & x_{100} \end{bmatrix} \begin{bmatrix} -0.2451 \\ -0.5989 \end{bmatrix}$
_x = x.reshape(-1)
_x
torch.manual_seed(43052)
net = torch.nn.Linear(in_features=1,out_features=1)
net(_x)
net(_x.reshape(100,1))
과 같이 정의
torch.manual_seed(43052)
net = torch.nn.Linear(in_features=2,out_features=1) # bias=False를 깜빡..
net.weight
net.bias
plt.plot(x,y,'o')
plt.plot(x,net(X).data,'--')
plt.plot(x,X@torch.tensor([[-0.2451],[-0.5989]])+0.2549,'-.')
- 수식표현: $\hat{\bf y} = {\bf X} {\bf \hat W} + \hat{b}= \begin{bmatrix} 1 & x_1 \\ 1 & x_2 \\ \dots & \dots \\ 1 & x_{100} \end{bmatrix} \begin{bmatrix} -0.2451 \\ -0.5989 \end{bmatrix} + 0.2549$
-
준비
net = torch.nn.Linear(1,1,bias=True)
net.weight.data = torch.tensor([[10.0]])
net.bias.data = torch.tensor([-5.0])
net.weight,net.bias
-
step1
yhat = net(x)
plt.plot(x,y,'o')
plt.plot(x,net(x).data,'--')
plt.plot(x,-5+10*x,'--')
-
step2
loss = torch.mean((y-yhat)**2)
-
step3
(미분전)
net.bias,net.weight
net.bias.grad, net.weight.grad
(미분)
loss.backward()
(미분후)
net.bias,net.weight
net.bias.grad,net.weight.grad
-
step4
(업데이트전)
net.bias,net.weight
net.bias.grad, net.weight.grad
(업데이트)
net.bias.data = net.bias.data - 0.1*net.bias.grad
net.weight.data = net.weight.data - 0.1*net.weight.grad
net.bias.grad = None
net.weight.grad = None
(업데이트후)
net.bias,net.weight
net.bias.grad, net.weight.grad
-
반복
net = torch.nn.Linear(1,1)
net.weight.data = torch.tensor([[10.0]])
net.bias.data = torch.tensor([-5.0])
for epoc in range(30):
yhat = net(x)
loss = torch.mean((y-yhat)**2)
loss.backward()
net.weight.data = net.weight.data - 0.1*net.weight.grad
net.bias.data = net.bias.data - 0.1*net.bias.grad
net.weight.grad = None
net.bias.grad = None
plt.plot(x,y,'o')
plt.plot(x,net(x).data,'--')
-
준비
net = torch.nn.Linear(2,1,bias=False)
net.weight.data = torch.tensor([[-5.0, 10.0]])
-
step1
yhat = net(X)
-
step2
loss = torch.mean((y-yhat)**2)
-
step3
(미분전)
net.weight
net.weight.grad
(미분)
loss.backward()
(미분후)
net.weight
net.weight.grad
-
step4
(업데이트전)
net.weight
net.weight.grad
(업데이트)
net.weight.data = net.weight.data - 0.1*net.weight.grad
net.weight.grad = None
(업데이트후)
net.weight
net.weight.grad
-
반복
net = torch.nn.Linear(2,1,bias=False)
net.weight.data = torch.tensor([[-5.0, 10.0]])
plt.plot(x,y,'o')
plt.plot(x,net(X).data,'--')
for epoc in range(30):
yhat = net(X)
loss = torch.mean((y-yhat)**2)
loss.backward()
net.weight.data = net.weight.data - 0.1*net.weight.grad
net.weight.grad = None
plt.plot(x,y,'o')
plt.plot(x,net(X).data,'--')
-
준비
net = torch.nn.Linear(1,1)
net.weight.data = torch.tensor([[10.0]])
net.bias.data = torch.tensor([[-5.0]])
torch.optim.SGD?
Stocastic Gradiant Decscent
net.parameters()
optimizr = torch.optim.SGD(net.parameters(),lr=1/10)
-
step1~3
yhat = net(x)
loss = torch.mean((y-yhat)**2)
loss.backward()
-
step4
(update 전)
net.weight.data, net.bias.data ## 값은 업데이트 전
net.weight.grad, net.bias.grad ## 미분값은 청소전
(update)
optimizr.step()
optimizr.zero_grad()
(update 후)
net.weight.data, net.bias.data ## 값은 업데이트 되었음
net.weight.grad, net.bias.grad ## 미분값은 0으로 초기화하였음
-
반복
net = torch.nn.Linear(1,1)
net.weight.data = torch.tensor([[10.0]])
net.bias.data = torch.tensor([-5.0])
optimizr = torch.optim.SGD(net.parameters(),lr=1/10)
plt.plot(x,y,'o')
plt.plot(x,net(x).data,'--')
for epoc in range(30):
yhat = net(x)
loss = torch.mean((y-yhat)**2)
loss.backward()
optimizr.step(); optimizr.zero_grad()
plt.plot(x,y,'o')
plt.plot(x,net(x).data,'--')
-
바로 반복하겠습니다..
net = torch.nn.Linear(2,1,bias=False)
net.weight.data = torch.tensor([[-5.0, 10.0]])
optimizr = torch.optim.SGD(net.parameters(),lr=1/10)
plt.plot(x,y,'o')
plt.plot(x,net(X).data,'--')
for epoc in range(30):
yhat = net(X)
loss = torch.mean((y-yhat)**2)
loss.backward()
optimizr.step(); optimizr.zero_grad()
plt.plot(x,y,'o')
plt.plot(x,net(X).data,'--')
-
iterator, generator의 개념필요
-
탐구시작: 네트워크 생성
net = torch.nn.Linear(in_features=1,out_features=1)
net.weight
net.bias
-
torch.optim.SGD? 를 확인하면 params에 대한설명에 아래와 같이 되어있음
params (iterable): iterable of parameters to optimize or dicts defining
parameter groups
-
설명을 읽어보면 params에 iterable object를 넣으라고 되어있음 (iterable object는 숨겨진 명령어로 __iter__
를 가지고 있는 오브젝트를 의미)
set(dir(net.parameters)) & {'__iter__'}
set(dir(net.parameters())) & {'__iter__'}
-
무슨의미?
_generator = net.parameters()
_generator.__next__()
_generator.__next__()
_generator.__next__()
-
이건 이런느낌인데?
_generator2 = iter([net.weight,net.bias])
_generator2
_generator2.__next__()
_generator2.__next__()
_generator2.__next__()
-
즉 아래는 같은코드이다.
### 코드1
_generator = net.parameters()
torch.optim.SGD(_generator,lr=1/10)
### 코드2
_generator = iter([net.weight,net.bias])
torch.optim.SGD(_generator,lr=1/10)
### 코드3 (이렇게 써도 코드2가 실행된다고 이해할 수 있음)
_iterator = [net.weight,net.bias]
torch.optim.SGD(_iterator,lr=1/10)
결론: net.parameters()
는 net오브젝트에서 학습할 파라메터를 모두 모아 리스트(iterable object)로 만드는 함수라 이해할 수 있다.
-
응용예제1
What = torch.tensor([[-5.0],[10.0]],requires_grad=True)
optimizr = torch.optim.SGD([What],lr=1/10)
plt.plot(x,y,'o')
plt.plot(x,(X@What).data,'--')
for epoc in range(30):
yhat = X@What
loss = torch.mean((y-yhat)**2)
loss.backward()
optimizr.step();optimizr.zero_grad()
plt.plot(x,y,'o')
plt.plot(x,(X@What).data,'--')
-
응용예제2
b = torch.tensor(-5.0,requires_grad=True)
w = torch.tensor(10.0,requires_grad=True)
optimizr = torch.optim.SGD([b,w],lr=1/10)
plt.plot(x,y,'o')
plt.plot(x,(w*x+b).data,'--')
for epoc in range(30):
yhat = b+ w*x
loss = torch.mean((y-yhat)**2)
loss.backward()
optimizr.step(); optimizr.zero_grad()
plt.plot(x,y,'o')
plt.plot(x,(w*x+b).data,'--')
-
현실에서 이런 경우가 많음
- $x$가 커질수록 (혹은 작아질수록) 성공확률이 증가함.
-
(X,y)는 어떤모양?
_df = pd.DataFrame({'x':range(-6,7),'y':[0,0,0,0,0,0,1,0,1,1,1,1,1]})
_df
plt.plot(_df.x,_df.y,'o')
-
(예비학습) 시그모이드라는 함수가 있음
xx = torch.linspace(-6,6,100)
def f(x):
return torch.exp(x)/(1+torch.exp(x))
plt.plot(_df.x,_df.y,'o')
plt.plot(xx,f(xx))
plt.plot(xx,f(2.5*xx-1.2)) # 영향을 크게 받을 때 + 운적인 요소 영향 받을 때(절편) -> 모델링하는 과정
베르누이 특정 확률로 0 또는 1 뽑기
-
$x$가 커질수록 $y=1$이 잘나오는 모형은 아래와 같이 설계할 수 있음 <--- 외우세요!!!
-
$y_i \sim Ber(\pi_i),\quad $ where $\pi_i = \frac{\exp(w_0+w_1x_i)}{1+\exp(w_0+w_1x_i)}$
-
$\hat{y}_i= \hat{pi}_\frac{\exp(\hat{w}_0+\hat{w}_1x_i)}{1+\exp(\hat{w}_0+\hat{w}_1x_i)}=\frac{1}{1+\exp(-\hat{w}_0-\hat{w}_1x_i)}$
-
$loss= - \sum_{i=1}^{n} \big(y_i\log(\hat{y}_i)+(1-y_i)\log(1-\hat{y}_i)\big)$ <--- 외우세요!!
$y_i=1$ $\hat{y_i} = 1$loss가 0 근처 $\hat{y_i} = 0$ loss가- 무한대
$y_i = 0$ $\hat{y_i} = 0 $loss가 0근처 $\hat{y_i} = 1$ loss가 1
-
예제시작
torch.bernoulli?
torch.bernoulli(torch.tensor([0.5]*100)) # 0.5의 확률ㄹ 0 또는 1 뽑아
x=torch.linspace(-1,1,2000).reshape(2000,1)
w0= -1
w1= 5
u = w0+x*w1
v = torch.exp(u)/(1+torch.exp(u)) # v=πi, 즉 확률을 의미함
y = torch.bernoulli(v)
v
u
plt.plot(x,y,'o',alpha=0.05,ms=4)
plt.plot(x,v,'--r')
- 우리의 목적: $x$가 들어가면 빨간선 $\hat{y}$의 값을 만들어주는 mapping을 학습해보자.
w0hat = 10
w1hat = 3
yhat = f(w0hat + w1hat*x)
plt.plot(x,y,'o',alpha=0.05,ms=4)
plt.plot(x,v,'--r')
plt.plot(x,yhat,'--r')
l1 = torch.nn.Linear(1,1)
l1.bias.data = torch.tensor([-1.0])
l1.weight.data = torch.tensor([[1.0]])
a1 = torch.nn.Sigmoid()
w0hat = -1
w1hat = 3
yhat = a1(w0hat + w1hat*x)
plt.plot(x,y,'o',alpha=0.05,ms=4)
plt.plot(x,v,'--r')
plt.plot(x,yhat,'--r')
for epoc in range(6000):
## step1
yhat = a1(l1(x))
## step2
loss = torch.mean((y-yhat)**2) ## loss 를 원래 이렇게 하는건 아니에요..
## step3
loss.backward()
## step4
l1.bias.data = l1.bias.data - 0.1 * l1.bias.grad
l1.weight.data = l1.weight.data - 0.1 * l1.weight.grad
l1.bias.grad = None
l1.weight.grad = None
plt.plot(x,y,'o',alpha=0.05,ms=4)
plt.plot(x,v,'--r')
plt.plot(x,a1(l1(x)).data,'--r')