사실 그동안 딥러닝보다는 머신러닝에 집중하던 경향이 있었다. 내가 주변에서 쉽게 찾을 수 있는 데이터는 머신러닝만으로도 그럭저럭 만족할 성능이 나왔기 때문에, 낮설고 생소하고 만지기 무서운 딥러닝 프레임워크에는 손이 잘 가지 았았다.
그나마 pytorch를 깔짝이며 생짜베기 심층 신경망으로 dacon의 연습 대회 데이터를 만지작거려 본 게 전부다. 그래도 개인 프로젝트로 진행하고 있는 비트코인 오토트레이딩 모델 개발을 위해서라도 pytorch와 더 친해질 필요가 있으므로, 이번에 시간이 난 김에 약간의 검색 끝에 만만해 보이는 예제를 찾아내어 본격적인 삽질에 도전하였다.
라이브러리에 대한 지식도 적고, 자연어 데이터를 처음 접하는 입장에서 혼돈 그 자체인 상태로 일단 이 강좌를 그대로 따라해보기로 했...지만 구 버전 torchtext
라이브러리 기준으로 설명되어 있어 현재 최신 버전에서는 제대로 돌아가지 않았다.
버전을 낮춰 강좌대로 돌리는 방법이 가장 편한 방법이었지만, 최신 버전의 기능을 사용하는 것이 바람직하다고 판단하여 자료를 뒤져본 결과 한국어 torchtext 예제를 발견하였고, 이 예제로부터 몇 가지를 얻어낼 수 있었다.
나는 순차적인 데이터에 강하다는 RNN과 LSTM을 사용하고 싶었지만 이 예제는 원본 데이터도, 사용하는 모델도 달랐다. 여기서 삽질이 시작되었다 아래는 그 삽질의 결과를 정리한 것이다.
데이터 출처
2011년 어떤 공부 엄청 잘하는 사람이 쓴 논문에서 활용했던 데이터라고 하며 Kaggle이나 각종 입문 강좌에서도 예제로 많이 사용하는 데이터라 매우 구하기 쉽다.
데이터는 (label: integer, text: string)
으로 구성되며
label
은 1
과 2
의 값을 가지며, 전자는 평점 7점 이상, 후자는 평점 4점 이하를 의미한다.text
는 평가 내용이며 특수문자와 html 태그 등이 섞여 있다.자연어 비정형 데이터는 모델에 학습시키기 위해 반드시 변환 과정을 거쳐야 하며 크게 토큰화, 벡터화로 나뉜다.
문장을 특정 단위로 쪼개 단어(또는 형태소 등)의 집합으로 변환하는 과정이다.
pytorch 생태계에서 torchtext.data.utils.get_tokenizer 메서드로 매우 간편하게 토큰화를 진행시킬 수 있다.
보통 데이터의 크기가 매우 큰 경우가 많으므로 generator 형태로 구현하는 것이 일반적이라고 한다.
쪼개진 토큰들은 컴퓨터가 알아먹기 쉽게 숫자 데이터에 매핑해주는 작업이 필요하다. 이를 벡터화라고 하며 여러 방법이 있다.
pytorch 생태계에서는 torchtext.vocab 모듈를 활용하면 벡터화 작업을 날로 먹을 수 있다 할 수 있다.
(엄밀히 말하면 실제 실수 벡터로 매핑하는 벡터화는 torch.nn.Embedding이 진행하지만, 벡터화를 위해 진행하는 작업 중 일부이므로 이 글에서는 벡터화 섹션에 소개한다.)
예제 코드는 한국어 torchtext 예제에 있다.
공식 튜토리얼에서는 이렇게 처리한 데이터를 DataLoader에 적재하여 다루기를 권장하고 있는데, 앞에서 언급했던 구 버전 torchtext와의 가장 큰 차이점이다. 공식 튜토리얼에서 DataLoader에 적재하는 과정이 잘 나타나 있으니 참고하자.
간단히 설명하자면 DataLoader의 collate_fn을 배치 길이만큼의 라벨 데이터, 전처리된 1차원 텍스트 데이터, 오프셋(텍스트 데이터 텐서의 각 리뷰들의 시작 인덱스 번호 정보를 담은 텐서) 세 정보를 반환하도록 정의한다.
이후 모델 내부에서 Embedding 작업을 추가로 진행한 후, 오프셋 데이터와 Embedding 처리된 텍스트 데이터를 가지고 학습을 진행한다.
항상 직접 모델을 정의하여 사용해오다가 pytorch에서 제공하는 모델 클래스를 처음 사용해보았다.
nn.RNN의 출력층이 RNN의 hidden state를 반환하는데,이 경우 추가적으로 nn.Linear을 씌워 출력을 시키는 것이 일반적이라고 한다.
하지만 이진 분류 문제에서는 RNN의 마지막 step의 hidden state가 갖는 실수 범위의 값을, softmax 같은 이진화 함수를 씌워 0, 1로 구분시킬 수 있으므로 적어도 이 IMDB 데이터에서는 신경쓰지 않아도 되는 문제라고 한다.
내가 작성했던 전체 코드는 여기서 볼 수 있다.