import torch
import numpy as np
import matplotlib.pyplot as plt
10wk-1: 순환신경망 (2)
순환신경망
순환신경망 intro (2)– abc예제, abdc예제, AbAcAd예제(1)
강의영상
https://youtube.com/playlist?list=PLQqh36zP38-wXdABtimM1pYK5TjPTBA6X
import
Define some funtions
def f(txt,mapping):
return [mapping[key] for key in txt]
= torch.nn.Softmax(dim=1) soft
Exam2: abc
data
= list('abc')*100
txt 10] txt[:
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a']
= txt[:-1]
txt_x = txt[1:] txt_y
5],txt_y[:5] txt_x[:
(['a', 'b', 'c', 'a', 'b'], ['b', 'c', 'a', 'b', 'c'])
하나의 은닉노드를 이용한 풀이 – 억지로 성공
-
데이터정리
= {'a':0,'b':1,'c':2}
mapping = torch.tensor(f(txt_x,mapping))
x = torch.tensor(f(txt_y,mapping))
y 5],y[:5] x[:
(tensor([0, 1, 2, 0, 1]), tensor([1, 2, 0, 1, 2]))
-
학습
43052)
torch.manual_seed(= torch.nn.Sequential(
net =3,embedding_dim=1),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),#===#
=1,out_features=3)
torch.nn.Linear(in_features
)= torch.nn.CrossEntropyLoss()
loss_fn = torch.optim.Adam(net.parameters()) optimizr
for epoc in range(5000):
## 1
## 2
= loss_fn(net(x),y)
loss ## 3
loss.backward()## 4
optimizr.step() optimizr.zero_grad()
-
결과해석
= net[:-1](x).data
hidden = soft(net(x)).data yhat
9],'--o') plt.plot(hidden[:
9],'--o') plt.plot(net(x).data[:
9],'--o') plt.plot(yhat[:
- 억지로 맞추고있긴한데 파라메터가 부족해보인다.
-
결과시각화1
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
9], (net[-1].weight.data).T, net[-1].bias.data hidden[:
(tensor([[-0.0147],
[ 0.9653],
[-0.9896],
[-0.0147],
[ 0.9653],
[-0.9896],
[-0.0147],
[ 0.9653],
[-0.9896]]),
tensor([[-4.6804, 0.3071, 5.2894]]),
tensor([-1.5440, 0.9143, -1.3970]))
9]@(net[-1].weight.data).T + net[-1].bias.data hidden[:
tensor([[-1.4755, 0.9098, -1.4745],
[-6.0618, 1.2108, 3.7086],
[ 3.0875, 0.6104, -6.6312],
[-1.4755, 0.9098, -1.4745],
[-6.0618, 1.2108, 3.7086],
[ 3.0875, 0.6104, -6.6312],
[-1.4755, 0.9098, -1.4745],
[-6.0618, 1.2108, 3.7086],
[ 3.0875, 0.6104, -6.6312]])
- (파랑,주황,초록) 순서로 그려짐
- 파랑 = hidden * (-4.6804) + (-1.5440)
- 주황 = hidden * (0.3071) + (0.9143)
- 초록 = hidden * (5.2894) + (-1.3970)
-
내부동작을 잘 뜯어보니까 사실 엉성해. 엄청 위태위태하게 맞추고 있었음.
- weight: 파랑과 초록을 구분하는 역할을 함
- weight + bias: 뭔가 교모하게 애매한 주황값을 만들어서 애매하게 ’b’라고 나올 확률을 학습시킨다. \(\to\) 사실 학습하는 것 같지 않고 때려 맞추는 느낌, 쓸수있는 weight가 한정적이라서 생기는 현상 (양수,음수,0)
참고: torch.nn.Linear()의 비밀?
- 사실 \({\boldsymbol y}={\boldsymbol x}{\bf W} + {\boldsymbol b}\) 꼴에서의 \({\bf W}\)와 \({\boldsymbol b}\)가 저장되는게 아니다.
- \({\boldsymbol y}={\boldsymbol x}{\bf A}^T + {\boldsymbol b}\) 꼴에서의 \({\bf A}\)와 \({\boldsymbol b}\)가 저장된다.
- \({\bf W} = {\bf A}^T\) 인 관계에 있으므로 l1.weight 가 우리가 생각하는 \({\bf W}\) 로 해석하려면 사실 transpose를 취해줘야 한다.
왜 이렇게..?
- 계산의 효율성 때문 (numpy의 구조를 알아야함)
- \({\boldsymbol x}\), \({\boldsymbol y}\) 는 수학적으로는 col-vec 이지만 메모리에 저장할시에는 row-vec 로 해석하는 것이 자연스럽다. (사실 메모리는 격자모양으로 되어있지 않음)
잠깐 딴소리!!
(예시1)
= np.array(range(4)).reshape(2,2) _arr
_arr.strides
(16, 8)
- 아래로 한칸 = 16칸 jump
- 오른쪽으로 한칸 = 8칸 jump
(예시2)
= np.array(range(6)).reshape(3,2) _arr
_arr.strides
(16, 8)
- 아래로 한칸 = 16칸 jump
- 오른쪽으로 한칸 = 8칸 jump
(예시3)
= np.array(range(6)).reshape(2,3) _arr
_arr.strides
(24, 8)
- 아래로 한칸 = 24칸 jump
- 오른쪽으로 한칸 = 8칸 jump
(예시4)
= np.array(range(4),dtype=np.int8).reshape(2,2) _arr
_arr
array([[0, 1],
[2, 3]], dtype=int8)
_arr.strides
(2, 1)
- 아래로한칸 = 2칸 (= 2바이트 jump = 16비트 jump)
- 오른쪽으로 한칸 = 1칸 jump (= 1바이트 jump = 8비트 jump)
진짜 참고..
- 1바이트 = 8비트
- 1바이트는 2^8=256 의 정보 표현
- np.int8은 8비트로 정수를 저장한다는 의미
2**8
256
print(np.array(55,dtype=np.int8))
print(np.array(127,dtype=np.int8))
print(np.array(300,dtype=np.int8)) # overflow
55
127
44
딴소리 끝!!
-
결과시각화2
= torch.concat([hidden,net(x).data,yhat],axis=1)
combined combined.shape
torch.Size([299, 7])
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
15],vmin=-7,vmax=7,cmap='bwr')
plt.matshow(combined[:range(7), labels=[r'$h$',r'$y=a?$',r'$y=b?$',r'$y=c?$',r'$P(y=a)$',r'$P(y=b)$',r'$P(y=c)$'],size=14)
plt.xticks(
plt.colorbar()15)
plt.gcf().set_figwidth(15)
plt.gcf().set_figheight(r"Vis2: $[h | net(x) | \hat{y}]$",size=25) plt.title(
Text(0.5, 1.0, 'Vis2: $[h | net(x) | \\hat{y}]$')
Exam3: abcd
data
= list('abcd')*100
txt 10] txt[:
['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b']
= txt[:-1]
txt_x = txt[1:] txt_y
5],txt_y[:5] txt_x[:
(['a', 'b', 'c', 'd', 'a'], ['b', 'c', 'd', 'a', 'b'])
하나의 은닉노드를 이용한 풀이 – 억지로 성공
-
데이터정리
= {'a':0,'b':1,'c':2,'d':3}
mapping = torch.tensor(f(txt_x,mapping))
x = torch.tensor(f(txt_y,mapping))
y 5],y[:5] x[:
(tensor([0, 1, 2, 3, 0]), tensor([1, 2, 3, 0, 1]))
-
학습
= torch.nn.Sequential(
net =4,embedding_dim=1),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),=1,out_features=4)
torch.nn.Linear(in_features
)= torch.nn.CrossEntropyLoss()
loss_fn = torch.optim.Adam(net.parameters()) optimizr
0].weight.data = torch.tensor([[-0.3333],[-2.5000],[5.0000],[0.3333]])
net[
-1].weight.data = torch.tensor([[1.5000],[-6.0000],[-2.0000],[6.0000]])
net[-1].bias.data = torch.tensor([0.1500, -2.0000, 0.1500, -2.000]) net[
for epoc in range(5000):
## 1
## 2
= loss_fn(net(x),y)
loss ## 3
loss.backward()## 4
optimizr.step() optimizr.zero_grad()
-
결과시각화1
= net[:-1](x).data
hidden = soft(net(x)).data yhat
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
-
결과시각화2
= torch.concat([hidden,net(x).data,yhat],axis=1)
combined combined.shape
torch.Size([399, 9])
15],vmin=-15,vmax=15,cmap='bwr')
plt.matshow(combined[:range(9), labels=[r'$h$',r'$y=a?$',r'$y=b?$',r'$y=c?$',r'$y=d?$',r'$P(y=a)$',r'$P(y=b)$',r'$P(y=c)$',r'$P(y=d)$'],size=14)
plt.xticks(
plt.colorbar()15)
plt.gcf().set_figwidth(15)
plt.gcf().set_figheight(r"Vis2: $[h | net(x) | \hat{y}]$",size=25) plt.title(
Text(0.5, 1.0, 'Vis2: $[h | net(x) | \\hat{y}]$')
두개의 은닉노드를 이용한 풀이 – 깔끔한 성공
-
데이터정리
= {'a':0,'b':1,'c':2,'d':3}
mapping = torch.tensor(f(txt_x,mapping))
x = torch.tensor(f(txt_y,mapping))
y 5],y[:5] x[:
(tensor([0, 1, 2, 3, 0]), tensor([1, 2, 3, 0, 1]))
-
학습
43052)
torch.manual_seed(= torch.nn.Sequential(
net =4,embedding_dim=2),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),=2,out_features=4)
torch.nn.Linear(in_features
)= torch.nn.CrossEntropyLoss()
loss_fn = torch.optim.Adam(net.parameters()) optimizr
for epoc in range(5000):
## 1
= net(x)
yhat ## 2
= loss_fn(yhat,y)
loss ## 3
loss.backward()## 4
optimizr.step() optimizr.zero_grad()
-
결과시각화1
= net[:-1](x).data
hidden = soft(net(x)).data yhat
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
-
결과시각화2
= torch.concat([hidden,net(x).data,yhat],axis=1)
combined combined.shape
torch.Size([399, 10])
15],vmin=-7,vmax=7,cmap='bwr')
plt.matshow(combined[:range(10), labels=[r'$h$',r'$h$',r'$y=a?$',r'$y=b?$',r'$y=c?$',r'$y=d?$',r'$P(y=a)$',r'$P(y=b)$',r'$P(y=c)$',r'$P(y=d)$'],size=14)
plt.xticks(
plt.colorbar()15)
plt.gcf().set_figwidth(15)
plt.gcf().set_figheight(r"Vis2: $[h | net(x) | \hat{y}]$",size=25) plt.title(
Text(0.5, 1.0, 'Vis2: $[h | net(x) | \\hat{y}]$')
Exam4: AbAcAd
data
= list('AbAcAd')*100
txt 10] txt[:
['A', 'b', 'A', 'c', 'A', 'd', 'A', 'b', 'A', 'c']
= txt[:-1]
txt_x = txt[1:] txt_y
5],txt_y[:5] txt_x[:
(['A', 'b', 'A', 'c', 'A'], ['b', 'A', 'c', 'A', 'd'])
두개의 은닉노드를 이용한 풀이 – 실패
-
데이터정리
= {'A':0,'b':1,'c':2,'d':3}
mapping = torch.tensor(f(txt_x,mapping))
x = torch.tensor(f(txt_y,mapping))
y 5],y[:5] x[:
(tensor([0, 1, 0, 2, 0]), tensor([1, 0, 2, 0, 3]))
-
학습
43052)
torch.manual_seed(= torch.nn.Sequential(
net =4,embedding_dim=2),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),=2,out_features=4)
torch.nn.Linear(in_features
)= torch.nn.CrossEntropyLoss()
loss_fn = torch.optim.Adam(net.parameters()) optimizr
for epoc in range(5000):
## 1
= net(x)
yhat ## 2
= loss_fn(yhat,y)
loss ## 3
loss.backward()## 4
optimizr.step() optimizr.zero_grad()
-
결과시각화1
= net[:-1](x).data
hidden = soft(net(x)).data yhat
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
-
결과시각화2
= torch.concat([hidden,net(x).data,yhat],axis=1)
combined combined.shape
torch.Size([599, 10])
15],vmin=-5,vmax=5,cmap='bwr')
plt.matshow(combined[:range(10), labels=[r'$h$',r'$h$',r'$y=A?$',r'$y=b?$',r'$y=c?$',r'$y=d?$',r'$P(y=A)$',r'$P(y=b)$',r'$P(y=c)$',r'$P(y=d)$'],size=14)
plt.xticks(
plt.colorbar()15)
plt.gcf().set_figwidth(15)
plt.gcf().set_figheight(r"Vis2: $[h | net(x) | \hat{y}]$",size=25) plt.title(
Text(0.5, 1.0, 'Vis2: $[h | net(x) | \\hat{y}]$')
- 실패
-
실패를 해결하는 순진한 접근방식: 위 문제를 해결하기 위해서는 아래와 같은 구조로 데이터를 다시 정리하면 될 것이다.
X | y |
---|---|
A,b | A |
b,A | c |
A,c | A |
c,A | d |
A,d | A |
d,A | b |
A,b | A |
b,A | c |
… | … |
-
순진한 접근방식의 비판: - 결국 정확하게 직전 2개의 문자를 보고 다음 문제를 예측하는 구조 - 만약에 직전 3개의 문자를 봐야하는 상황이 된다면 또 다시 코드를 수정해야함. - 그리고 실전에서는 직전 몇개의 문자를 봐야하는지 모름.
이것에 대한 해결책은 순환신경망이다. 다음시간에 설명
숙제
주어진 자료가 다음과 같다고 하자.
= list('abcde')*100
txt 10] txt[:
['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']
= txt[:-1]
txt_x = txt[1:] txt_y
5],txt_y[:5] txt_x[:
(['a', 'b', 'c', 'd', 'e'], ['b', 'c', 'd', 'e', 'a'])
아래 코드를 변형하여 적절한 네트워크를 설계하고 위의 자료를 학습하라. (깔끔한 성공을 위한 최소한의 은닉노드를 설정할 것)
= torch.nn.Sequential(
net =??,embedding_dim=??),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),=??,out_features=??)
torch.nn.Linear(in_features )
(풀이)
a,b,c,d,e 를 표현함에 있어서 3개의 은닉노드면 충분하다.
- 1개의 은닉노드 -> 2개의 문자를 표현할 수 있음.
- 2개의 은닉노드 -> 4개의 문자를 표현할 수 있음.
- 3개의 은닉노드 -> 8개의 문자를 표현할 수 있음.
= {'a':0,'b':1,'c':2,'d':3,'e':4}
mapping = torch.tensor(f(txt_x,mapping))
x = torch.tensor(f(txt_y,mapping))
y 5],y[:5] x[:
(tensor([0, 1, 2, 3, 4]), tensor([1, 2, 3, 4, 0]))
43052)
torch.manual_seed(= torch.nn.Sequential(
net =5,embedding_dim=3),
torch.nn.Embedding(num_embeddings
torch.nn.Tanh(),=3,out_features=5)
torch.nn.Linear(in_features
)= torch.nn.CrossEntropyLoss()
loss_fn = torch.optim.Adam(net.parameters()) optimizr
for epoc in range(5000):
## 1
= net(x)
yhat ## 2
= loss_fn(yhat,y)
loss ## 3
loss.backward()## 4
optimizr.step() optimizr.zero_grad()
-
결과시각화1
= net[:-1](x).data
hidden = soft(net(x)).data yhat
= plt.subplots(1,3,figsize=(15,5))
fig,ax 0].plot(hidden[:9],'--o'); ax[0].set_title('$h:=(tanh \circ linr_1)(x)$',size=15)
ax[1].plot(net(x).data[:9],'--o'); ax[1].set_title('$net(x):=(linr_2 \circ tanh \circ linr_1)(x)$',size=15)
ax[2].plot(yhat[:9],'--o'); ax[2].set_title('$\hat{y}$ = softmax$(net(x))$',size=15);
ax[r"Vis1: $h,net(x),\hat{y}$",size=20)
fig.suptitle( plt.tight_layout()
-
결과시각화2
= torch.concat([hidden,net(x).data,yhat],axis=1)
combined combined.shape
torch.Size([499, 13])
15],vmin=-5,vmax=5,cmap='bwr')
plt.matshow(combined[:range(13), labels=[r'$h$',r'$h$',r'$h$',
plt.xticks(r'$y=A?$',r'$y=b?$',r'$y=c?$',r'$y=d?$',r'$y=e?$',
r'$P(y=A)$',r'$P(y=b)$',r'$P(y=c)$',r'$P(y=d)$',r'$P(y=e)$'],size=13)
plt.colorbar()15)
plt.gcf().set_figwidth(15)
plt.gcf().set_figheight(r"Vis2: $[h | net(x) | \hat{y}]$",size=25) plt.title(
Text(0.5, 1.0, 'Vis2: $[h | net(x) | \\hat{y}]$')