')">

인공지능 모형 만들기 2

Layer 모델링

Posted by Jong-June Jeon on June 27, 2024

layer 직렬 연결

가변인자를 받을 수 있는 함수의 정의해 봅니다. 가변인자를 받는 함수란 입력의 개수가 미리 정해지지 않은 함수를 말합니다.

# 가변인자를 받을 수 있는 함수의 정의
def my_function(*args):
    for arg in args:
        print(arg)

my_function(1, 2, 3)

가변인자 리스트를 받는 함수는 *list 를 이용하여 함수의 입력단에서 list 객체를 풀어서 전달할 수 있습니다.

# 예시
a = [1,2,3]
my_function(*a)

nn.Sequential 은 가변인자를 받을 수 있는 함수입니다. 입력개수가 정해지지 않아도 됩니다.

# 예시
layers = nn.Sequential(
        nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1),
        nn.BatchNorm2d(64),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=2, stride=2))

*list 를 이용하여 함수의 입력단에서 list 객체를 풀어서 전달할 수 있습니다.

# 예시
layers = [nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1),
    nn.BatchNorm2d(64),
    nn.ReLU(),
    nn.MaxPool2d(kernel_size=2, stride=2)]
model = nn.Sequential(*layers)
print(model)

x = torch.randn(20,1,5,10)
yhat = model(x)
yhat.shape

다음은 ModuleList 의 활용방법을 알아봅니다. ModuleList의 layer 리스트로 extend 혹은 append 기능 사용할 수 있습니다. 다음은 ModuleList를 활용하여 여러개의 hidden layer를 연결하는 FFN 을 만듭니다. 입력값으로 hidden layer 의 dim을 입력한 리스트를 입력값으로 받습니다. 예를 들면 입력 데이터 차원에서 잠재층의 차원이 10, 20, 30, 20 으로 하여 output 으로 변환되는 FFN 을 만드는 것을 생각해봅니다. 여기서 이 FFN을 만들때 [10, 20, 30, 20]을 입력값으로 하여 layer를 결합하고자 합니다. 이 작업은 두 단계로 이루어집니다.

  1. nn.ModuleList 를 이용하고 list comprehension 방법으로 layer 를 정의합니다.
  2. forward 단계에서 연결된 텐서를 만들어 FFN 을 만듭니다.
 
# ModuleList를 이용한 레이어의 연결
import torch
import torch.nn as nn
import torch.nn.functional as F

class MyModel(nn.Module):
    def __init__(self, input_dim, hidden_dims, output_dim):
        super(MyModel, self).__init__()
        # hidden_layers 확인
        self.hidden_layers = nn.ModuleList([nn.Linear(input_dim, hidden_dims[0])])
        self.hidden_layers.extend([nn.Linear(hidden_dims[i], hidden_dims[i+1]) for i in range(len(hidden_dims) - 1)])
        self.output_layer = nn.Linear(hidden_dims[-1], output_dim)

    def forward(self, x):
        for layer in self.hidden_layers:
            x = F.relu(layer(x))
        x = self.output_layer(x)
        return x

만든 class 로 모형을 만들고 실행해봅니다.

# 예제 문장
input_dim = 10
hidden_dims = [20, 20, 40, 40, 30, 10]
output_dim = 5
batch_size = 8

model = MyModel(input_dim, hidden_dims, output_dim)
input_data = torch.randn(batch_size, input_dim)
input_data.shape
output = model(input_data)
print(output)

layer 병렬 연결

범주형 변수가 여러개 주어진 경우 임베딩을 병렬적으로 결합하는 방법입니다. 여기서는 모든 범주형 변수의 레벨이 수가 같은 경우만 다룹니다

# 예제
class MyModel(nn.Module):
    def __init__(self, num_classes, embedding_dims):
        super(MyModel, self).__init__()
        # embeddings 확인 (List 형태로 관리)
        self.embeddings = nn.ModuleList([nn.Embedding(num_classes, embedding_dim) for embedding_dim in embedding_dims])

    def forward(self, x):
        # Embedding each categorical variable
        embedded_vars = [emb_layer(x[:, i]) 
                            for i, emb_layer in enumerate(self.embeddings)]
        concatenated_embeddings = torch.cat(embedded_vars, dim=-1)
        return concatenated_embeddings

실행해봅니다.


d = [3,4,5]
x = torch.randint(0,3, (10,3))       
model = MyModel(3,d)
model(x).shape

다음으로 입력데이터의 차원이 정해지지 않은 레이어의 정의합니다. init 단계에서 이름을 None 으로 정해놓고 입력값이 들어올때 정의합니다.

 # 예시
class FFN(nn.Module):
    def __init__(self):
        super(FFN, self).__init__()
        self.fc1 = None
        self.relu = nn.ReLU()
        self.fc2 = None
        self.fc3 = None
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        if self.fc1 is None:
            input_dim = x.shape[1]
            self.fc1 = nn.Linear(input_dim, 5).to(x.device)
            self.fc2 = nn.Linear(5, 5).to(x.device)
            self.fc3 = nn.Linear(5, 1).to(x.device)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.fc3(x)
        x = self.sigmoid(x)
        return x

실행해봅시다.

x = torch.randn(size = (10,20))
model = FFN()
model(x)