(7주차) 10월21일
Pytorch CNN (MNIST 3,7)
- 강의영상
- import
- data
- 기존의 MLP 모형
- 선형변환 대신에 2d convolution with windowsize=5
- ReLU() 대신 MaxPool2d + ReLU
- 여기에서 그냥 시그모이드에 태우자.
- networks 설계
- 숙제
-
(1/2) CNN 모형구축 (MNIST 3,7)
-
(2/2) 과제설명
import torch
from fastai.vision.all import *
import graphviz
def gv(s): return graphviz.Source('digraph G{ rankdir="LR"'+ s + ';}')
-
download data
path = untar_data(URLs.MNIST_SAMPLE)
path.ls()
-
list
threes=(path/'train'/'3').ls()
sevens=(path/'train'/'7').ls()
-
list $\to$ image
Image.open(threes[4])
-
image $\to$ tensor
tensor(Image.open(threes[4]))
- 여기에서 tensor는 파이토치가 아니라 fastai에서 구현한 함수임
-
여러개의 리스트를 모두 텐서로 바꿔보자.
seven_tensor = torch.stack([tensor(Image.open(i)) for i in sevens]).float()/255
three_tensor = torch.stack([tensor(Image.open(i)) for i in threes]).float()/255
-
$X$와 $y$를 만들자.
seven_tensor.shape, three_tensor.shape
y=torch.tensor([0.0]*6265+ [1.0]*6131).reshape(12396,1)
X=torch.vstack([seven_tensor,three_tensor]).reshape(12396,-1)
X.shape, y.shape
${\bf X} \to {\bf WX+b} \to f({\bf WX+b}) \to \dots \to {\bf y}$
- ${\bf X}=12396 \times 784$ matrix
- ${\bf y}=12396 \times 1$ (col) vector
-
교재의 모형
gv('''
splines=line
subgraph cluster_1{
style=filled;
color=lightgrey;
"x1"
"x2"
".."
"x784"
label = "Layer 0"
}
subgraph cluster_2{
style=filled;
color=lightgrey;
"x1" -> "node1"
"x2" -> "node1"
".." -> "node1"
"x784" -> "node1"
"x1" -> "node2"
"x2" -> "node2"
".." -> "node2"
"x784" -> "node2"
"x1" -> "..."
"x2" -> "..."
".." -> "..."
"x784" -> "..."
"x1" -> "node30"
"x2" -> "node30"
".." -> "node30"
"x784" -> "node30"
label = "Layer 1: ReLU"
}
subgraph cluster_3{
style=filled;
color=lightgrey;
"node1" -> "y"
"node2" -> "y"
"..." -> "y"
"node30" -> "y"
label = "Layer 2: Sigmoid"
}
''')
-
왜 28$\times$28 이미지를 784개의 벡터로 만든 다음에 모형을 돌려야 하는가?
-
기존에 개발된 모형이 회귀분석 기반으로 되어있어서 결국 회귀분석 틀에 짜 맞추어서 이미지자료를 분석하는 느낌
-
observation의 차원은 $784$가 아니라 $1\times (28\times 28)$이 되어야 맞다.
X.shape
X=X.reshape(12396,1,28,28)
X.shape
plt.imshow(X[776][0])
c1=torch.nn.Conv2d(1,16,5) # 입력채널=1 (흑백이므로), 출력채널=16, 윈도우크기5
X.shape, c1(X).shape
fig, axs = plt.subplots(4,4)
k=0
for i in range(4):
for j in range(4):
axs[i,j].imshow(c1(X)[776][k].data)
k=k+1
fig.set_figheight(8)
fig.set_figwidth(8)
fig.tight_layout()
fig
m1=torch.nn.MaxPool2d(2)
X.shape,c1(X).shape,m1(c1(X)).shape
fig, axs = plt.subplots(4,4)
k=0
for i in range(4):
for j in range(4):
axs[i,j].imshow(m1(c1(X))[776][k].data)
k=k+1
fig.set_figheight(8)
fig.set_figwidth(8)
fig.tight_layout()
a1=torch.nn.ReLU()
X.shape,c1(X).shape, m1(c1(X)).shape, a1(m1(c1(X))).shape
fig, axs = plt.subplots(4,4)
k=0
for i in range(4):
for j in range(4):
axs[i,j].imshow(a1(m1(c1(X)))[776][k].data)
k=k+1
fig.set_figheight(8)
fig.set_figwidth(8)
fig.tight_layout()
torch.manual_seed(1)
_A= torch.randn((3,3))
_A
a1(_A)
-
현재상황
a1(m1(c1(X))).shape
-
펼치자
a1(m1(c1(X))).reshape(12396,-1).shape
-
2304의 디멘젼을 1로 만들자.
l1=torch.nn.Linear(in_features=2304,out_features=1)
l1(a1(m1(c1(X))).reshape(12396,-1))
-
시그모이드를 걸자.
a2=torch.nn.Sigmoid()
a2(l1(a1(m1(c1(X))).reshape(12396,-1)))
net = nn.Sequential(
c1, # 컨볼루션(선형)
m1, # 맥스풀링(비선형) -- 효과? 이미지를 계층적으로 파악할 수 있게함
a1, # 렐루(비선형)
a1(m1(c1(X))).reshape(12396,-1), ## 이걸 구현해야하는데??
l1)
## 마지막의 a2는 생략한다. torch.nn..BCEWithLogitsLoss()에 내장되어 있을것이므로
net = nn.Sequential(
c1, # 컨볼루션(선형)
m1, # 맥스풀링(비선형) -- 효과? 이미지를 계층적으로 파악할 수 있게함
a1, # 렐루(비선형)
# a1(m1(c1(X))).reshape(12396,-1), ## 이걸 구현해야하는데??
l1)
## 마지막의 a2는 생략한다. torch.nn..BCEWithLogitsLoss()에 내장되어 있을것이므로
-
결국 주석처리한 부분을 구현해야함.
-
c1
,m1
,a1
,l1
의 공통점
- 무언가를 상속받는 클래스에서 생성된 인스턴스이다.
- forward메소드가 있다.
-
custom layer를 만드는 방법
- torch.nn.Module을 상속받아서 클래스를 하나 만든다.
- forward 메소드를 정의한다. (다음레이어로 리턴할 값)
class Flatten(torch.nn.Module):
def forward(self,x):
return x.reshape(12396,-1)
flatten=Flatten()
flatten(a1(m1(c1(X)))).shape
-
잘 구현이 된것 같다.
net = nn.Sequential(
c1, # 컨볼루션(선형)
m1, # 맥스풀링(비선형) -- 효과? 이미지를 계층적으로 파악할 수 있게함
a1, # 렐루(비선형)
flatten,# a1(m1(c1(X))).reshape(12396,-1), ## 이걸 구현해야하는데??
l1)
## 마지막의 a2는 생략한다. torch.nn..BCEWithLogitsLoss()에 내장되어 있을것이므로
-
손실함수와 옵티마이저 정의
loss_fn=torch.nn.BCEWithLogitsLoss()
optimizer= torch.optim.Adam(net.parameters())
-
step1~4
for epoc in range(200):
## 1
yhat=net(X)
## 2
loss=loss_fn(yhat,y)
## 3
loss.backward()
## 4
optimizer.step()
net.zero_grad()
plt.plot(y)
plt.plot(a2(yhat.data),'.')
ypred=a2(yhat.data)>0.5
sum(ypred==y)/12396
-
좀 더 성능이 좋아졌다. (이미 좋았는데 약간 더 좋아짐)
-
torch.nn.MaxPool2d(2) 대신 torch.nn.MaxPool2d(3) 을 사용하여 모형을 학습해보고 결과비교