class NewsClassifier(nn.Module):
def __init__(self, embedding_size, num_embeddings, num_channels,
hidden_dim, num_classes, dropout_p,
pretrained_embeddings = None, padding_idx = 0):
"""
매개변수:
embedding_size (int): 임베딩 벡터의 크기
num_embeddings (int): 임베딩 벡터의 개수
num_channels (int): 합성곱 커널 개수
hidden_dim (int): 은닉 차원 크기
num_classes (int): 클래스 개수
dropout_p (float): 드롭아웃 확률
pretrained_embeddings (numpy.array): 사전 훈련된 단어 임베딩
기본값은 None
padding_idx (int): 패딩 인덱스
"""
super(NewsClassifier, self).__init__()
if pretrained_embeddings is None:
self.emb = nn.Embedding(embedding_dim = embedding_size,
num_embeddings = num_embeddings,
padding_idx = padding_idx )
else:
pretrained_embeddings = torch.from_numpy(pretrained_embeddings).float()
self.emb = nn.Embedding(embedding_dim = embedding_size,
num_embeddings = num_embeddings,
padding_idx = padding_idx,
_weight = pretrained_embeddings)
self.convnet = nn.Sequential(
nn.Conv1d(in_channels = embedding_size,
out_channels = num_channels, kernel_size = 3),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3, stride = 2),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3, stride = 2),
nn.ELU(),
nn.Conv1d(in_channels = num_channels, out_channels = num_channels,
kernel_size = 3),
nn.ELU()
)
self._dropout_p = dropout_p
self.fc1 = nn.Linear(num_channels, hidden_dim)
self.fc2 = nn.Linear(hidden_dim, num_classes)
def forward(self, x_in, apply_softmax = False):
""" 분류기의 정방향 계산
매개변수:
x_in (torch.Tensor): 입력 데이터 텐서
x_in.shape는 (batch, dataset._max_seq_length)입니다.
apply_softmax (bool): 소프트맥스 활성화 함수를 위한 플래그
크로스-엔트로피 손실을 사용하려면 False로 지정합니다.
반환값:
결과 텐서. tensor.shape은 (batch, num_classes)입니다.
"""
# 임베딩을 적용하고 특성과 채널 차원을 바꿉니다.
x_embedded = self.emb(x_in).permute(0, 2, 1)
features = self.convnet(x_embedded)
# 평균 값을 계산하여 부차적인 차원을 제거합니다.
remaining_size = features.size(dim = 2)
#print(f"remaining_size: {remaining_size}")
features = F.avg_pool1d(features, remaining_size).squeeze(dim = 2)
features = F.dropout(features, p = self._dropout_p)
# MLP 분류기
intermediate_vector = F.relu(F.dropout(self.fc1(features), p = self._dropout_p))
prediction_vector = self.fc2(intermediate_vector)
if apply_softmax:
prediction_vector = F.softmax(prediction_vector, dim = 1)
return prediction_vector
주어진 `NewsClassifier` 모델은 PyTorch를 기반으로 한 뉴스 분류를 위한 신경망입니다. 주요 구조와 작동 방식을 아래에 정리했습니다.
---
### **주요 특징**
1. **임베딩 레이어**:
- `pretrained_embeddings`(사전 학습된 임베딩)이 제공되면 이를 사용하여 임베딩 레이어를 초기화합니다.
- 제공되지 않으면 새로 임베딩 레이어를 생성합니다.
- `padding_idx`는 패딩 토큰이 학습에 영향을 주지 않도록 설정합니다.
2. **합성곱 신경망(CNN)**:
- 여러 개의 `Conv1d` 레이어로 구성된 합성곱 구조를 통해 입력 데이터를 처리합니다.
- 각 합성곱 레이어 뒤에 `ELU` 활성화 함수가 적용됩니다.
- `stride`와 `kernel_size` 설정으로 시퀀스 길이를 점진적으로 줄입니다.
3. **글로벌 평균 풀링**:
- `avg_pool1d`를 사용하여 시퀀스 차원을 고정된 크기로 줄입니다.
- 이를 통해 합성곱 레이어에서 추출된 특징을 요약합니다.
4. **완전 연결 레이어 (MLP)**:
- 두 개의 선형 레이어(`fc1`, `fc2`)가 최종 분류기를 형성합니다.
- 드롭아웃 레이어를 사용하여 과적합을 방지합니다.
5. **소프트맥스 활성화 함수 (선택적)**:
- `apply_softmax` 플래그를 통해 소프트맥스를 출력에 적용할지 선택할 수 있습니다.
- 이는 확률 분포를 해석하거나 추론 시 유용합니다.
---
### **정방향 계산 과정**
1. **임베딩**:
- 입력 토큰을 임베딩 레이어를 통해 밀집 벡터(dense vector)로 변환합니다.
- Conv1d 레이어에 적합하도록 시퀀스 축과 채널 축을 교환합니다.
2. **합성곱 및 풀링**:
- 합성곱 레이어를 통해 특징을 추출하고 시퀀스 길이를 줄입니다.
- `avg_pool1d`로 시퀀스 차원을 완전히 제거해 고정 크기 벡터를 만듭니다.
3. **분류**:
- 완전 연결 네트워크를 통해 분류 작업을 수행합니다.
- 드롭아웃을 적용하여 과적합을 방지합니다.
- 최종 출력은 `(배치 크기, 클래스 개수)`의 텐서입니다.
4. **소프트맥스**:
- `apply_softmax=True`일 경우, 출력 텐서를 확률 분포로 변환합니다.
---
### **개선 가능성**
1. **합성곱에서 패딩 사용**:
- `padding="same"`을 적용하여 시퀀스 양 끝의 정보 손실을 방지할 수 있습니다.
2. **배치 정규화 (Batch Normalization)**:
- 합성곱 레이어 뒤에 배치 정규화를 추가하면 학습 안정성과 수렴 속도가 개선됩니다.
3. **파라미터 초기화**:
- Xavier 또는 Kaiming 초기화를 사용하면 모델 성능이 더 좋아질 수 있습니다.
4. **문서화**:
- 중간 텐서들의 예상 크기를 주석으로 추가하면 가독성이 높아집니다.
5. **에러 핸들링**:
- 입력 텐서의 차원을 검증하여 데이터 형태가 맞지 않을 경우 바로 에러를 출력하도록 설정합니다.
---
### **도움이 필요한 점이 있나요?**
위 모델을 개선하거나 학습에 사용할 코드를 추가적으로 작성해드릴까요? 😊