1. DNN 모델 클래스화 하기
class NN(torch.nn.Module): #NN은 클래스의 이름 /torch.nn.Module는 상속받는 클래스(자식은 부모의 특성, 특징을 갖고있음. 부모 클래스의 모든 함수와 변수를 자식 클래스에서 사용가능)
def __init__(self): #def는 파이썬을 이용한 함수화 / init와 forward는 반드시 필요
super(NN,self).__init__() # 이부분 빼먹기 쉬운데 조심할 것
# 주의) self 빼먹지 말자! -> 클래스 안에서 self는 나 자신을 의미
self.linear1 = torch.nn.Linear(784,512,bias=True) #레이어 정의
self.linear2 = torch.nn.Linear(512,512,bias=True)
self.linear3 = torch.nn.Linear(512,512,bias=True)
self.linear4 = torch.nn.Linear(512,512,bias=True)
self.linear5 = torch.nn.Linear(512,10,bias=True)
self.relu = torch.nn.ReLU()
torch.nn.init.xavier_uniform_(self.linear1.weight) #클래스 안에 정의되어 있기 때문에 self꼭 써야한다
torch.nn.init.xavier_uniform_(self.linear2.weight)
torch.nn.init.xavier_uniform_(self.linear3.weight)
torch.nn.init.xavier_uniform_(self.linear4.weight)
torch.nn.init.xavier_uniform_(self.linear5.weight)
def forward(self,x): #명시적으로 입력과 출력을 정의해 줌으로써 모델의 방향성을 설정해줌
out = self.linear1(x) #out1,out2 해도 되나 메모리 낭비이다
out = self.relu(out)
out = self.linear2(out)
out = self.relu(out)
out = self.linear3(out)
out = self.relu(out)
out = self.linear4(out)
out = self.relu(out)
out = self.linear5(out)
return out
model = NN().to(device) #NN이라는 클래스호출함으로써 모델을 정의한다
L1 torch.nn.Module을 상속받는 파이썬 클래스
L2 __init__()은 모델의 구조와 동작을 정의하는 생성자 객체가 생성될 때 호출
L3 super() 함수를 부르면 여기서 만든 클래스는 nn.Module클래스의 속성들을 가지고 초기화 됨-> NN모듈 부모의 모든 속성을 받아서 나자체도 초기화(뺴먹으면 학습 잘 안된다)
L19 foward() 함수는 모델이 학습데이터를 입력 받아서 forward연산을 진행시키는 함수
이 forward() 함수는 model 객체를 데이터와 함께 호출하면 자동으로 실행
예를 들어 model이란 이름의 객체를 생성 후, model(입력데이터)와 같은 형식으로 객체를 호출하면 자동으로 forward연산이 수행
**H(x) 식에 입력 x로 부터 예측된 y를 얻는 것을 forward 연산이라고 함
FC레이어의 경우 초기화를 어떻게 하느냐에따라 학습에 영향미침 -> 모델 안에서 초기화 해주는 것이 좋음
<MNIST DNN>
class NN(torch.nn.Module):
def __init__(self):
super(NN,self).__init__() # 이부분 빼먹기 쉬운데 조심할 것
# 주의) self 빼먹지 말자!
self.linear1 = torch.nn.Linear(784,512,bias=True)
self.linear2 = torch.nn.Linear(512,512,bias=True)
self.linear3 = torch.nn.Linear(512,512,bias=True)
self.linear4 = torch.nn.Linear(512,512,bias=True)
self.linear5 = torch.nn.Linear(512,10,bias=True)
self.relu = torch.nn.ReLU()
torch.nn.init.xavier_uniform_(self.linear1.weight)
torch.nn.init.xavier_uniform_(self.linear2.weight)
torch.nn.init.xavier_uniform_(self.linear3.weight)
torch.nn.init.xavier_uniform_(self.linear4.weight)
torch.nn.init.xavier_uniform_(self.linear5.weight)
def forward(self,x):
out = self.linear1(x)
out = self.relu(out)
out = self.linear2(out)
out = self.relu(out)
out = self.linear3(out)
out = self.relu(out)
out = self.linear4(out)
out = self.relu(out)
out = self.linear5(out)
return out
model = NN().to(device)
# 손실함수와 최적화 함수
loss = torch.nn.CrossEntropyLoss().to(device) # softmax 내부적으로 계산
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
total_batch = len(data_loader)
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
# (1000, 1, 28, 28) 크기의 텐서를 (1000, 784) 크기의 텐서로 변형
X = X.view(-1, 28 * 28).to(device)
# one-hot encoding되어 있지 않음
Y = Y.to(device)
#%debug
# 그래디언트 초기화
optimizer.zero_grad()
# Forward 계산
hypothesis = model(X)
# Error 계산
cost = loss(hypothesis, Y)
# Backparopagation
cost.backward()
# 가중치 갱신
optimizer.step()
# 평균 Error 계산
avg_cost += cost / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
print('Learning finished')
# Test the model using test sets
with torch.no_grad():
X_test = mnist_test.test_data.view(-1, 28 * 28).float().to(device)
Y_test = mnist_test.test_labels.to(device)
prediction = model(X_test)
correct_prediction = torch.argmax(prediction, 1) == Y_test
accuracy = correct_prediction.float().mean()
print('Accuracy:', accuracy.item())
2. MNIST CNN model
view= 2d데이터를 1d로 바꿈 (레이어의 이름은 아니다! 기억하라고 넣어둔것)
파라미터는 실험적으로 결정
모델 재설정해서 가장 좋은거 찾게됨 -> 이 수업에서는 이미 정의되어 있는 모델을 잘 프로그래밍 할 수만 있으면 됨
주어진 대로 모델 정의!
커널사이즈와 패딩간의 관계, 스트라이드와의 관계 등 이런 변수들이 입력데이터와 출력데이터에 미치는 영향력정도는 알아야함 (예를들어 maxpool인데 사이즈가 2고 스트라이드가 2이면 28x28이 14x14 가 된다 / 커널사이즈가 3이고 스트라이드가 1이고 패딩이 1이면 패딩이 있기 떄문에 커널사이즈가 3이지만 28x28이 유지된다 등등..)
## 버전 1.0
class CNN(torch.nn.Module):
def __init__(self):
super(CNN,self).__init__() # 이부분 빼먹기 쉬운데 조심할 것
self.conv1 = torch.nn.Conv2d(1,32,kernel_size=3,stride=1,padding=1) #커널사이즈는 디폴트값없으니 반드시 넣어주어야함. 나머지는 디폴트 값있음 바꿀려면 써줘야함
self.relu1 = torch.nn.ReLU()
self.maxpool1 = torch.nn.MaxPool2d(kernel_size=2,stride=2)
self.conv2 = torch.nn.Conv2d(32,64,kernel_size=3,stride=1,padding=1)
self.relu2 = torch.nn.ReLU()
self.maxpool2 = torch.nn.MaxPool2d(kernel_size=2,stride=2)
self.fc = torch.nn.Linear(7*7*64,10,bias=True)
torch.nn.init.kaiming_uniform(self.fc.weight)
def forward(self,x):
out = self.conv1(x)
out = self.relu1(out)
out = self.maxpool1(out)
out = self.conv2(out)
out = self.relu2(out)
out = self.maxpool2(out)
out = out.view(out.size(0),-1) # out = Batch(0) x 7(1) x 7(2) x 64(3) -> (배치사이즈,7x7x64) #2d를 1d로 바꿔주기!
out = self.fc(out) #7x7x64가 10으로 바뀌는 fc레이어
return out
모듈을 묶고 싶을때-> 꼭 사용하지 않아도 됨
모델의 모듈화(좀 더 간단해짐)
# 버전 2.0
class CNN(torch.nn.Module):
def __init__(self):
super(CNN,self).__init__() # 이부분 빼먹기 쉬운데 조심할 것
self.layer1 = torch.nn.Sequential(
torch.nn.Conv2d(1,32,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2,stride=2)
)
self.layer2 = torch.nn.Sequential(
torch.nn.Conv2d(32,64,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2,stride=2)
)
self.fc = torch.nn.Linear(7*7*64,10,bias=True)
torch.nn.init.kaiming_uniform(self.fc.weight)
def forward(self,x):
out = self.layer1(x)
out = self.layer2(out)
out = out.view(out.size(0),-1) # out = Batch x 7 x 7 x 64
out = self.fc(out)
return out
L18 FC이전 feature Map은 2D 데이터임 (Nx7x7x64)
FC 레이어 입력은 7x7x64로 1D 데이터를 입력 받음
따라서 Maxpool2D ->FC 로 데이터가 넘어갈 떄 데이터 변형이 필요함 (2D->1D)
L24 View 함수를 사용하여 변형 가능
Out 데이터는 [배치크기x7x7x64]이다
Out.size(0)은 배치 크기
Out.size(1)은 7
Out.size(2)은 7
Out.size(3)은 64 이다.
++
stride(2,1)은 가로세로(높이 가로) 적용한게 다른거 -> 정방이 아니것을 디자인 할일은 지금 단계에서 없다!
model = CNN().to(device)
# mnist_dnn 예제와 동일
criterion = torch.nn.CrossEntropyLoss().to(device) # Softmax is internally computed.
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# mnist_dnn 예제와 동일: X데이터 View로 변환하지 않는 부분만 다름
# 주의: 2D => 1D로 변경할 필요 없음
# minst Dnn에서는 2d 데이터를 1d로 바꾸어야 했음( 설계한 FC레이어가 1d데이터만을 받아서 1d를 출력하기 때문
# cnn에서 부터는 공간정보를 얻기 위한 2d를 1d로 강제로 만드는 작업은 필요하지 않음
#train my model
total_batch = len(data_loader)
print('Learning started. It takes sometime.')
for epoch in range(training_epochs):
avg_cost = 0
for X, Y in data_loader:
# image is already size of (28x28), no reshape
# label is not one-hot encoded
X = X.to(device)
Y = Y.to(device)
optimizer.zero_grad()
hypothesis = model(X)
cost = criterion(hypothesis, Y)
cost.backward()
optimizer.step()
avg_cost += cost / total_batch
print('[Epoch: {:>4}] cost = {:>.9}'.format(epoch + 1, avg_cost))
print('Learning Finished!')
# # mnist_dnn 예제와 동일: X데이터 View로 변환하지 않는 부분만 다름
# 주의: 2D => 1D로 변경할 필요 없음
# Test model and check accuracy
with torch.no_grad():
X_test = mnist_test.test_data.view(len(mnist_test), 1, 28, 28).float().to(device)
Y_test = mnist_test.test_labels.to(device)
prediction = model(X_test)
correct_prediction = torch.argmax(prediction, 1) == Y_test
accuracy = correct_prediction.float().mean()
print('Accuracy:', accuracy.item())
'AI' 카테고리의 다른 글
합성곱신경망 2 -실습 (0) | 2022.12.01 |
---|---|
합성곱신경망 2 이론 (0) | 2022.12.01 |
합성곱신경망 이론 1 (0) | 2022.11.26 |
[심층신경망2] 이론 (0) | 2022.10.15 |
심층신경망-실습2 (0) | 2022.10.12 |