본문 바로가기
AI/딥러닝

[AI 부트캠프] DAY 69 - 딥러닝 5

by HOHHOH 2023. 10. 28.

[오늘의 일지]

딥러닝 실시간 강의 - CNN, RNN 실습

[상세 내용]

CNN, RNN 실습

-  실습에 들어가기에 앞서서 수업 때 사용한 라이브러리는 pytorch였습니다. 기존에 tensorflow를 사용해 본 경험이 있어서 그런지 pytorch가 훨씬 더 코드를 짜야할 부분이 많았고 귀찮은 부분이 많았습니다. 그래도 코드를 자주 사용하면서 연습한다는 생각으로 실습을 따라갔습니다.

 

CNN 실습 코드

# Conv -> ReLU -> Conv -> ReLU -> MaxPool -> fc1 -> fc2 -> fc3(output)        (model1)
# Conv block(Conv-ReLU x 2) -> MaxPool -> Conv block -> MaxPool -> fc(output) (model2)
class CNN(nn.Module):
    def __init__(self):
        # X = (N - F) / S + 1
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3,
                               out_channels=6,   # number of filters
                               kernel_size=3,
                               stride=1,
                               padding=1)   # (3, 32, 32) --> (6, 32, 32)
        self.conv2 = nn.Conv2d(6, 12, 3, 1, 1)    # (6, 32, 32) --> (12, 32, 32)
        self.maxpool1 = nn.MaxPool2d(kernel_size=2,
                                    stride=2) # (12, 32, 32) --> (12, 16, 16)
        self.conv3 = nn.Conv2d(12, 24, 3, 1, 1) # (12, 16, 16) --> (24, 16, 16)
        self.conv4 = nn.Conv2d(24, 48, 3, 1, 1) # (24, 16, 16) -- >(48, 16, 16)
        self.maxpool2 = nn.MaxPool2d(2, 2) # (48, 16, 16) --> (48, 8, 8)
        self.conv5 = nn.Conv2d(48, 48, 3, 1, 1) # (48, 8, 8) --> (48, 8, 8)
        self.conv6 = nn.Conv2d(48, 48, 3, 1, 1) # (48, 8, 8) --> (48, 8, 8)
        self.maxpool3 = nn.MaxPool2d(2, 2) # (48, 8, 8) --> (48, 4, 4)

        self.fc1 = nn.Linear(in_features=48*4*4,  # 768
                             out_features=128)
        #self.fc2 = nn.Linear(1024, 128)
        self.fc3 = nn.Linear(128, 10)
        self.relu = nn.ReLU()
        self.softmax = nn.Softmax(dim=1)


    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.relu(self.conv2(x))
        x = self.maxpool1(x)
        x = self.relu(self.conv3(x))
        x = self.relu(self.conv4(x))
        x = self.maxpool2(x)
        x = self.relu(self.conv5(x))
        x = self.relu(self.conv6(x))
        x = self.maxpool3(x)
        x = torch.flatten(x, 1) # (batch_size, 12, 14, 14) -> (batch_size, 12*14*14)
        x = self.relu(self.fc1(x))
        #x = self.relu(self.fc2(x))
        x = self.softmax(self.fc3(x))
        return x
        
        
# 학습
for epoch in tqdm(range(epochs)):
    n_correct = 0
    total_loss = 0.0
    for idx, data in enumerate(trainloader):

        optimizer.zero_grad()   # gradient 초기화.
        ## ReLU() ---> max(0, x)
        ## dReLU() --> if x < 0: 0, else: 1
        ## d(wx)/dw --> x (local gradient)

        #### feed forward ####
        #images, labels = data[0], data[1]  # CPU version
        images, labels = data[0].to(device), data[1].to(device)  # GPU version
        outputs = model(images) # forward(x)
        loss = criterion(outputs, labels) # compute loss (tensor)
        #print(f"Epoch {epoch} : {idx:4d} iteration -->\t{loss.item():.4f}") # loss value
        n_correct = n_correct + (torch.max(model(images), dim=1)[1] == labels).sum() # batch당 맞은 개수.
        total_loss += loss.item()

        #### back propagation ####
        loss.backward()  # loss를 가지고 backprop
        optimizer.step() # SGD를 이용해서 weight update를 수행함.

    print(f"Epoch {epoch}, Train Accuracy : {n_correct/len(trainset):4f}\
                        | Train (average)Loss : {total_loss/len(trainloader):4f}")

end = time()

print("Training Done.")
print(f"Elasped Time : {end-start:.4f} secs.")

 

RNN 실습 코드

# 전처리
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
# 스케일을 적용할 column을 정의합니다.
scale_cols = ['Open', 'High', 'Low', 'Volume', 'Close']
# 스케일 후 columns
df = samsung.loc[samsung.index > '20200101', scale_cols]
scaled = scaler.fit_transform(df)
scaled

# train와 test 분류
train = df.loc[df.index < '20230101']
###### 분류 시 변경 ######
X_train, y_train = train.drop("Close", axis=1), train.Close
test = df.loc[df.index > '20230101']
X_test, y_test = test.drop("Close", axis=1), test.Close
###### 분류 시 변경 ######
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)

# 데이터 전처리
from torch.utils.data import TensorDataset # 텐서데이터셋
from torch.utils.data import DataLoader # 데이터로더

seq_length = 30
batch_size = 32

# 20200102
# ...
# ...
# 20200214(open,high,low,close)
# -----> 20200215 (close)


# 데이터셋 생성 함수
def build_dataset(X, y, seq_length):

    X_data = []
    y_data = []

    for idx in range(0, len(X)-seq_length):
        # idx = 0 ~ len(X)-seq_length-1
        _X = X[idx:idx+seq_length] # 30개 feature vectors
        _y = y[idx+seq_length] # 1개 (31번째 target value, close)
        ###### 분류 시 변경 ######
        ## target value도 잘 만들어봅시다 ##
        ###### 분류 시 변경 ######
        #print(_X, '--->', _y)
        X_data.append(_X.values)
        y_data.append(_y)

    X_data = torch.FloatTensor(np.array(X_data))
    y_data = torch.FloatTensor(np.array(y_data))

    return X_data, y_data

trainX, trainY = build_dataset(X_train, y_train, seq_length)
testX, testY = build_dataset(X_test, y_test, seq_length)

# 텐서로 변환

# 텐서 형태로 데이터 정의
trainset = TensorDataset(trainX, trainY)
testset = TensorDataset(testX, testY)


# 데이터로더는 기본적으로 2개의 인자를 입력받으며 배치크기는 통상적으로 2의 배수를 사용
trainloader = DataLoader(trainset,
                         batch_size=batch_size,
                         shuffle=True,
                         drop_last=True)

testloader = DataLoader(testset,
                        batch_size=batch_size,
                        shuffle=False,
                        drop_last=True)
                        
# LSTM으로 모델 코드 짜기
class LSTM(nn.Module):
    # # 기본변수, layer를 초기화해주는 생성자
    def __init__(self, input_dim, hidden_dim, seq_len, output_dim, n_layers):
        super().__init__()
        self.input_dim = input_dim      # input feature vector dim
        self.hidden_dim = hidden_dim    # hidden layer node 개수 (= hidden state dim)
        self.seq_len = seq_len          # hidden state 개수 (=input sequence length)
        self.output_dim = output_dim    # output layer의 node 개수 (=output dim)
        self.n_layers = n_layers        # multi-layer로 구성할 때, (hidden, LSTM)layer 수

        self.lstm = nn.LSTM(input_size=input_dim, # Wxh   (input_dim x hidden_dim)
                            hidden_size=hidden_dim, # Whh (hidden_dim x hidden_dim)
                            num_layers=n_layers,
                            batch_first=True,
                            dropout=0.1, # hidden layer의 node중에 일부를 deactivate 시킴.
                            bidirectional=False)  # (batch_size, ~~~~)

        self.fc = nn.Linear(in_features=hidden_dim,
                            out_features=output_dim) # Why

        ###### 분류 시 변경 ######

        ######### TO-DO ###########
        # output layer를 디자인해봅시다.

        ###### 분류 시 변경 ######


        # self.rnn = nn.RNN(input_size=4,
        #                   hidden_size=10,
        #                   num_layers=1,
        #                   batch_first=True)
        # self.fc = nn.Linear(10, 1)

    # 예측을 위한 함수
    def forward(self, x):  # (N, L, H_in)
        # (n_layers, batch_size, hidden_dim)
        h0 = torch.zeros(self.n_layers, x.size(0), self.hidden_dim).to(device)
        c0 = torch.zeros(self.n_layers, x.size(0), self.hidden_dim).to(device)
        # input : (x, (h0, c0))
        # output : (x, (hn, cn))
        x, (hn, cn) = self.lstm(x, (h0, c0))  # (N, L, H_in) ---(LSTM)---> (N, L, H_out)
        # e.g. (batch_size, seq_len, hidden_dim)
        ## 마지막 출력결과(last_hidden_state) ---> (batch_size, hidden_dim)
        x = self.fc(x[:, -1, :]) # (batch_size, hidden_dim) ---> (batch_size, output_dim)  ## Linear Regression
        return x, (hn, cn)

 

[마무리]

 오늘은 cnn과 rnn의 실습 위주의 수업이 진행되었습니다. 우선은 강사님이 예시로 써주시는 코드를 따라 쓰기에 바빴지만 나중에 실전에서 사용할 때 어느 정도 능숙하게 사용할 수 있게 여러 번 반복해서 사용도 해보고 파라미터들도 많이 바꿔 가면서 기능도 익숙해지도록 노력해야겠습니다.

반응형

댓글