Path: blob/master/site/ko/tutorials/keras/text_classification.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
영화 리뷰를 사용한 텍스트 분류
이 튜토리얼은 디스크에 저장된 일반 텍스트 파일에서 시작하는 텍스트 분류를 보여줍니다. IMDB 데이터세트에 대한 감정 분석을 수행하도록 이진 분류기를 훈련합니다. 노트북의 마지막에는 스택 오버플로에서 프로그래밍 질문에 대한 태그를 예측하도록 다중 클래스 분류기를 훈련하는 연습을 시도해볼 수 있습니다.
감정 분석
이 노트북은 리뷰 텍스트를 사용하여 영화 리뷰를 긍정적 또는 부정적으로 분류합니다. 중요하고 널리 적용 가능한 머신러닝 문제인 이진 분류의 예입니다.
IMDB 데이터세트에는 인터넷 영화 데이터베이스에서 가져온 50,000개의 영화 리뷰 텍스트가 포함되어 있습니다. 훈련용 리뷰 25,000개와 테스트용 리뷰 25,000개로 나뉩니다. 훈련 및 테스트 세트는 균형을 이룹니다. 즉, 동일한 수의 긍정적인 리뷰와 부정적인 리뷰가 포함되어 있습니다.
데이터세트 다운로드 및 탐색하기
데이터 세트를 다운로드하여 추출한 다음 디렉터리 구조를 살펴보겠습니다.
aclImdb/train/pos
및 aclImdb/train/neg
디렉토리에는 각각 단일 영화를 리뷰한 많은 텍스트 파일이 포함되어 있습니다. 그 중 하나를 살펴보겠습니다.
데이터세트 로드하기
다음으로, 디스크에서 데이터를 로드하고 훈련에 적합한 형식으로 준비합니다. 이를 위해 다음과 같은 디렉토리 구조를 예상하는 유용한 text_dataset_from_directory 유틸리티를 사용합니다.
이진 분류를 위한 데이터세트를 준비하려면 디스크에 class_a
및 class_b
에 해당하는 두 개의 폴더가 필요합니다. 이것들은 aclImdb/train/pos
및 aclImdb/train/neg
에서 찾을 수 있는 긍정적 영화 리뷰와 부정적 영화 리뷰입니다. IMDB 데이터세트에는 추가 폴더가 포함되어 있으므로 이 유틸리티를 사용하기 전에 제거합니다.
다음으로 text_dataset_from_directory
유틸리티를 사용하여 레이블이 지정된 tf.data.Dataset
를 만듭니다. tf.data는 데이터 작업을 위한 강력한 도구 모음입니다.
머신러닝 실험을 실행할 때 데이터세트를 train, validation 및 test의 세 부분으로 나누는 것이 가장 좋습니다.
IMDB 데이터세트는 이미 훈련과 테스트로 나누어져 있지만 검증 세트가 부족합니다. 아래 validation_split
인수를 사용하여 훈련 데이터를 80:20으로 분할하여 검증 세트를 생성해 보겠습니다.
위에서 볼 수 있듯이 training 폴더에는 25,000개의 예제가 있으며 그 중 80%(또는 20,000개)를 훈련에 사용할 것입니다. 잠시 후에 알 수 있겠지만 데이터세트를 model.fit
에 직접 전달하여 모델을 훈련할 수 있습니다. tf.data
를 처음 사용하는 경우 데이터세트를 반복하고 다음과 같이 몇 가지 예를 출력할 수도 있습니다.
리뷰에는 <br/>
와 같은 간헐적 HTML 태그와 구두점을 포함한 원시 텍스트가 포함되어 있다는 점에 주목하세요. 다음 섹션에서 이를 처리하는 방법을 보여줍니다.
레이블은 0 또는 1입니다. 이들 중 어느 것이 긍정적이고 부정적인 영화 리뷰에 해당하는지 확인하려면 데이터세트에서 class_names
속성을 확인할 수 있습니다.
다음으로, 검증 및 테스트 데이터세트를 만듭니다. 검증을 위해 훈련 세트의 나머지 5,000개 리뷰를 사용합니다.
참고: validation_split
및 subset
인수를 사용할 때 검증 및 훈련 분할이 겹치지 않도록 임의 시드를 지정하거나 shuffle=False
를 전달하는 것을 잊지 마세요.
훈련을 위한 데이터세트 준비하기
다음으로, 유용한 tf.keras.layers.TextVectorization
레이어를 사용하여 데이터를 표준화, 토큰화 및 벡터화합니다.
표준화는 일반적으로 구두점이나 HTML 요소를 제거하여 데이터세트를 단순화하기 위해 텍스트를 전처리하는 것을 말합니다. 토큰화는 문자열을 여러 토큰으로 분할하는 것을 말합니다(예: 화이트스페이스에서 분할하여 문장을 개별 단어로 분할). 벡터화는 토큰을 숫자로 변환하여 신경망에 공급될 수 있도록 하는 것을 말합니다. 이러한 모든 작업을 이 레이어에서 수행할 수 있습니다.
위에서 볼 수 있듯이 리뷰에는 <br />
와 같은 다양한 HTML 태그가 포함되어 있습니다. 이러한 태그는 TextVectorization
레이어의 기본 표준화 도구로 제거되지 않습니다(텍스트를 소문자로 변환하고 기본적으로 구두점을 제거하지만 HTML은 제거하지 않음). HTML을 제거하기 위해 사용자 정의 표준화 함수를 작성합니다.
참고: 훈련-테스트 왜곡(훈련-제공 왜곡이라고도 함)를 방지하려면 훈련 및 테스트 시간에 데이터를 동일하게 전처리하는 것이 중요합니다. 이를 용이하게 하기 위해 TextVectorization
레이어를 모델 내에 직접 포함할 수 있습니다. 본 튜토리얼에서 나중에 이 내용을 알아봅니다.
다음으로 TextVectorization
레이어를 만듭니다. 이 레이어를 사용하여 데이터를 표준화, 토큰화 및 벡터화합니다. 각 토큰에 대해 고유한 정수 인덱스를 생성하도록 output_mode
를 int
로 설정합니다.
기본 분할 함수와 위에서 정의한 사용자 지정 표준화 함수를 사용하고 있습니다. 명시적 최대값인 sequence_length
와 같이 모델에 대한 몇 가지 상수를 정의하여 레이어가 시퀀스를 정확히 sequence_length
값으로 채우거나 자르도록 합니다.
다음으로, 전처리 레이어의 상태를 데이터세트에 맞추기 위해 adapt
를 호출합니다. 그러면 모델이 문자열 인덱스를 정수로 빌드합니다.
참고: adapt를 호출할 때 훈련 데이터만 사용하는 것이 중요합니다(테스트세트를 사용하면 정보가 누출됨).
이 레이어를 사용하여 일부 데이터를 전처리한 결과를 확인하는 함수를 만들어 보겠습니다.
위에서 볼 수 있듯이 각 토큰은 정수로 대체되었습니다. 레이어에서 .get_vocabulary()
를 호출하여 각 정수에 해당하는 토큰(문자열)을 조회할 수 있습니다.
모델을 훈련할 준비가 거의 되었습니다. 최종 전처리 단계로 이전에 생성한 TextVectorization 레이어를 훈련, 검증 및 테스트 데이터세트에 적용합니다.
성능을 높이도록 데이터세트 구성하기
다음은 I/O가 차단되지 않도록 데이터를 로드할 때 사용해야 하는 두 가지 중요한 메서드입니다.
.cache()
는 데이터가 디스크에서 로드된 후 메모리에 데이터를 보관합니다. 이렇게 하면 모델을 훈련하는 동안 데이터세트로 인해 병목 현상이 발생하지 않습니다. 데이터세트가 너무 커서 메모리에 맞지 않는 경우, 이 메서드를 사용하여 성능이 뛰어난 온 디스크 캐시를 생성할 수도 있습니다. 많은 작은 파일보다 읽기가 더 효율적입니다.
.prefetch()
는 훈련 중에 데이터 전처리 및 모델 실행과 겹칩니다.
데이터 성능 가이드에서 두 가지 메서드와 데이터를 디스크에 캐싱하는 방법에 관해 자세히 알아볼 수 있습니다.
모델 생성
이제 신경망을 만들 차례입니다.
층을 순서대로 쌓아 분류기(classifier)를 만듭니다:
첫 번째 레이어는
Embedding
레이어입니다. 이 레이어는 정수로 인코딩된 리뷰를 입력 받고 각 단어 인덱스에 해당하는 임베딩 벡터를 찾습니다. 이러한 벡터는 모델이 훈련되면서 학습됩니다. 이들 벡터는 출력 배열에 차원을 추가합니다. 최종 차원은(batch, sequence, embedding)
이 됩니다. 임베딩에 대해 보다 자세히 알아보려면 단어 임베딩 튜토리얼을 확인하세요.그다음
GlobalAveragePooling1D
층은sequence
차원에 대해 평균을 계산하여 각 샘플에 대해 고정된 길이의 출력 벡터를 반환합니다. 이는 길이가 다른 입력을 다루는 가장 간단한 방법입니다.마지막 층은 하나의 출력 노드(node)를 가진 완전 연결 층입니다.
sigmoid
활성화 함수를 사용하여 0과 1 사이의 실수를 출력합니다. 이 값은 확률 또는 신뢰도를 나타냅니다.
손실 함수와 옵티마이저
모델이 훈련하려면 손실 함수(loss function)과 옵티마이저(optimizer)가 필요합니다. 이 예제는 이진 분류 문제이고 모델이 확률을 출력하므로(출력층의 유닛이 하나이고 sigmoid
활성화 함수를 사용합니다), binary_crossentropy
손실 함수를 사용하겠습니다.
이제 최적화 기와 손실 함수를 사용하도록 모델을 구성합니다.
모델 훈련하기
dataset
개체를 fit 메서드에 전달하여 모델을 훈련합니다.
모델 평가하기
모델의 성능을 확인해 보죠. 두 개의 값이 반환됩니다. 손실(오차를 나타내는 숫자이므로 낮을수록 좋습니다)과 정확도입니다.
이 상당히 단순한 접근 방식은 약 86%의 정확도를 달성합니다.
정확도와 손실 그래프 그리기
model.fit()
은 훈련 중에 발생한 모든 것을 가진 사전을 포함하는 History
객체를 반환합니다.
네 개의 항목이 있습니다. 훈련과 검증 단계에서 모니터링하는 지표들입니다. 훈련 손실과 검증 손실을 그래프로 그려 보고, 훈련 정확도와 검증 정확도도 그래프로 그려서 비교해 보겠습니다:
이 그래프에서 점선은 훈련 손실과 훈련 정확도를 나타냅니다. 실선은 검증 손실과 검증 정확도입니다.
훈련 손실은 각 epoch마다 감소하고 훈련 정확성은 각 epoch마다 증가합니다. 경사 하강 최적화를 사용할 때 이와 같이 예상됩니다. 모든 반복에서 원하는 수량을 최소화해야 합니다.
하지만 검증 손실과 검증 정확도에서는 그렇지 못합니다. 훈련 정확도 이전이 피크인 것 같습니다. 이는 과대적합 때문입니다. 이전에 본 적 없는 데이터보다 훈련 데이터에서 모델이 더 잘 동작합니다. 이 지점부터는 모델이 과도하게 최적화되어 테스트 데이터에서 일반화되지 않는 훈련 데이터의 특정 표현을 학습합니다.
여기에서는 과대적합을 막기 위해 단순히 검증 정확도가 더 이상 증가하지 않는 경우에 훈련을 중단할 수 있습니다. 이를 수행하는 한 가지 방법은 tf.keras.callbacks.EarlyStopping
콜백을 사용하는 것입니다.
모델 내보내기
위의 코드에서는 모델에 텍스트를 제공하기 전에 TextVectorization
레이어를 데이터세트에 적용했습니다. 모델이 원시 문자열을 처리할 수 있도록 하려면(예: 배포를 단순화하기 위해) 모델 내부에 TextVectorization
레이어를 포함할 수 있습니다. 이를 위해 방금 훈련한 가중치를 사용하여 새 모델을 만들 수 있습니다.
새로운 데이터로 추론하기
새로운 예에 대한 예측을 얻으려면 간단히 model.predict()
를 호출하면 됩니다.
모델 내부에 텍스트 전처리 논리를 포함하면 배포를 단순화하고 훈련/테스트 왜곡 가능성을 줄이는 프로덕션용 모델을 내보낼 수 있습니다.
TextVectorization 레이어를 적용할 위치를 선택할 때 염두에 두어야 할 성능 차이가 있습니다. 레이어를 모델 외부에서 사용하면 GPU에서 훈련할 때 비동기 CPU 처리 및 데이터 버퍼링을 수행할 수 있습니다. 따라서 GPU에서 모델을 훈련하는 경우 모델을 개발하는 동안 최상의 성능을 얻기 위해 이 옵션을 사용하고 배포 준비가 완료되면 모델 내부에 TextVectorization 레이어를 포함하도록 전환할 수 있습니다.
모델 저장에 대해 자세히 알아보려면 이 튜토리얼을 방문하세요.
연습: 스택 오버플로 질문에 대한 다중 클래스 분류
이 튜토리얼은 IMDB 데이터세트에서 이진 분류자를 처음부터 훈련하는 방법을 보여주었습니다. 연습으로, 이 노트북을 수정하여 스택 오버플로에서 프로그래밍 질문의 태그를 예측하도록 다중 클래스 분류자를 훈련할 수 있습니다.
스택 오버플로에 게시된 수천 개의 프로그래밍 질문(예: "Python에서 값을 기준으로 사전을 정렬할 수 있는 방법은?")의 본문이 포함된 데이터세트가 준비되어 있습니다. 이들 각각은 정확히 하나의 태그(Python, CSharp, JavaScript 또는 Java)로 레이블이 지정됩니다. 여러분이 할 작업은 질문을 입력으로 받아 적절한 태그(이 경우 Python)를 예측하는 것입니다.
작업할 데이터세트에는 1,700만 개 이상의 게시물이 포함된 BigQuery의 훨씬 더 큰 공개 스택 오버플로 데이터세트에서 추출한 수천 개의 질문이 포함되어 있습니다.
데이터세트를 다운로드해 보면 이전에 작업한 IMDB 데이터세트와 유사한 디렉터리 구조를 가지고 있음을 알 수 있습니다.
참고: 분류 문제의 난이도를 높이기 위해 프로그래밍 질문에서 Python, CSharp, JavaScript 또는 Java라는 단어의 출현은 blank라는 단어로 대체되었습니다(많은 질문에 해당 언어가 포함됨).
이 연습을 완료하려면 다음과 같이 수정하여 스택 오버플로 데이터세트와 함께 작동하도록 이 노트북을 수정해야 합니다.
노트북 상단에서, 미리 준비된 스택 오버플로 데이터세트를 다운로드하는 코드로 IMDB 데이터세트를 다운로드하는 코드를 업데이트합니다. 스택 오버플로 데이터세트는 유사한 디렉터리 구조를 가지므로 많이 수정할 필요가 없습니다.
이제 4개의 출력 클래스가 있으므로
Dense(4)
를 읽도록 모델의 마지막 레이어를 수정합니다.모델을 컴파일할 때 손실을
tf.keras.losses.SparseCategoricalCrossentropy
로 변경합니다. 이것은 각 클래스의 레이블이 정수일 때(이 경우 0, 1, 2 또는 3일 수 있음) 다중 클래스 분류 문제에 사용할 올바른 손실 함수입니다. 또한 이것은 다중 클래스 분류 문제이기 때문에 메트릭을metrics=['accuracy']
로 변경합니다(tf.metrics.BinaryAccuracy
는 이진 분류자에만 사용됨).시간 경과에 따른 정확도를 표시할 때
binary_accuracy
및val_binary_accuracy
를 각각accuracy
및val_accuracy
로 변경합니다.이러한 변경이 완료되면 다중 클래스 분류자를 훈련할 수 있습니다.
더 알아보기
이 튜토리얼은 텍스트 분류를 처음부터 알아보았습니다. 일반적인 텍스트 분류 워크플로에 대해 자세히 알아보려면 Google Developers의 텍스트 분류 가이드를 확인하세요.