Developer's Development
3.3.8 [NLP] 자연어 딥러닝(전이학습) 본문
전이학습
- 사전 훈련 방식
기존의 사전 훈련방식은 정적인 단어 임베딩(Word2Vec, Glove, FastText)을 사용하여 단어를 고정된 벡터로 표현하는 기법이다.
👉🏻 주요 알고리즘
1. Word2Vec
- CBOW: 주변 단어로 중심 단어 예측
- Skip-gram: 중심 단어로 주변 단어 예측
2. Glove: 단어 공기 행렬을 기반으로 임베딩 학습
3. FastText: 단어를 n-그램으로 분해해 희소 단어 처리 강화
👉🏻 장점: 효율적 학습과 사전 학습된 모델 재사용 가능
👉🏻 한계: 문맥을 반영하지 못해 동음이의어 처리 및 문장 표현이 어려움
- ELMO (Embeddings from Language Model)
문맥 기반 단어 임베딩(Contextualized Word Embedding)으로, 문맥에 따라 단어의 의미를 동적으로 표현한다.
👉🏻 특징
1. 양방향 LSTM 사용: Forward와 Backward LSTM으로 문맥 정보를 학습
2. 문자 수준 정보 포함: 희소 단어와 신조어 처리 가능
3. 문맥 반영: 같은 단어라도 문맥에 따라 다른 임베딩 생성
👉🏻 장점: 동음이의어 처리 및 문맥적 의미 반영, 다양한 NLP 작업에 활용 가능(텍스트 분류, NER 등)
👉🏻 한계: BiLSTM 기반으로 학습 비용이 높음. 글로벌 문맥 처리에서 Transformer에 비해 효율성 낮음
- Transformers
병렬 처리와 전역 문맥 이해를 통해 RNN의 한계를 극복한 딥러닝 모델로, 인코더-디코더 구조와 어텐션 메커니즘을 기반으로 한다.
👉🏻 주요 구성 요소
1. 인코더: 입력 시퀀스를 벡터로 변환
2. 디코더: 인코더의 벡터를 사용해 출력 시퀀스 생성
3. Multi-Head Attention: 단어 간 관계를 다각도로 학습
4. 포지셔널 인코딩: 단어 순서 정보 추가
👉🏻 장점: 병렬 처리 가능, 전역 문맥 학습
👉🏻 한계: 높은 연산 자원 필요
- BERT (Bidirectional Encoder Representations fro mTransformers)
인코더를 기반으로 한 모델로, 양방향 문맥을 학습해 단어의 앞뒤 의미를 모두 이해한다.
👉🏻 특징
1. 양방향 문맥 학습: 앞뒤 문맥을 모두 반영해 단어 의미 이해
2. 학습 방법
- Masked Language Model (MLM): 문장 일부를 [MASK]로 숨기고 예측
- Next Sentence Prediction (NSP): 두 문장이 연속되는지 판단
3. 사전 학습 + 미세 조정: 대규모 데이터로 학습 후 특정 작업에 활용
👉🏻 장점: 양방향 문맥 이해, 다양한 NLP 작업에 활용 가능
👉🏻 한계: 높은 계산 비용, 입력 길이 제한(512 토큰)
- GPT-2
Transformer 디코더를 기반으로 설계된 언어 생성 모델로, 이전 단어를 바탕으로 다음 단어를 예측하는 자기회귀 언어 모델이다.
👉🏻 특징
1. 자연스러운 텍스트 생성: 문맥을 이해해 논리적이고 일관된 텍스트 생성
2. 사전 학습: 대규모 데이터로 학습해 다양한 작업에 활용 가능
3. 디코더 기반: 입력 단어를 순차적으로 처리하며 출력 생성
👉🏻 장점: 자연스러운 텍스트 생성, 문맥 이해, 다양한 활용 가능
👉🏻 한계: 긴 텍스트 생성 시 품질 저하, 윤리적 문제 가능성
Hugging Face Join
👉🏻 Profile > Settings > Access Tokens에서 new token 발급
👉🏻 colab에선 이 키를 사용할 때, 왼쪽 아이콘 '보안 비밀'에서 추가하여 사용, 노트북 엑세스도 허용
Hugging Face – The AI community building the future.
The Home of Machine Learning Create, discover and collaborate on ML better. We provide paid Compute and Enterprise solutions. We are building the foundation of ML tooling with the community.
huggingface.co
👉🏻 추가 완료 후 아래와 같은 방식으로 사용 (colab만 해당)
from google.colab import userdata
HF_TOKEN = userdata.get('HF_TOKEN')
실습 (BERT 전이학습)
- 데이터 준비
from tensorflow.keras.utils import get_file
import pandas as pd
# 데이터 다운로드
ratings_train_path = get_file("ratings_train.text", "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt")
ratings_test_path = get_file("ratings_test.text", "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt")
# 데이터 로드
ratings_train_df = pd.read_csv(ratings_train_path, sep='\t')
ratings_test_df = pd.read_csv(ratings_test_path, sep='\t')
# display(ratings_train_df.head())
# display(ratings_test_df.head())
# 결측치 제거
ratins_train_df = ratings_train_df.dropna(how='any')
ratins_test_df = ratings_test_df.dropna(how='any')
# display(ratings_train_df.info())
# display(ratings_test_df.info())
# 샘플링
ratings_train_df = ratings_train_df.sample(n=15000, random_state=0)
ratings_test_df = ratings_test_df.sample(n=5000, random_state=0)
# ratings_train_df['label'].value_counts(), ratings_test_df['label'].value_counts()
X_train = ratings_train_df['document'].values.tolist()
y_train = ratings_train_df['label'].values.tolist()
X_test = ratings_test_df['document'].values.tolist()
y_test = ratings_test_df['label'].values.tolist()
- 토커나이저/모델 준비
bert 한국어 버전 사전학습 모델 klue/bert-base
from transformers import AutoModel, AutoTokenizer
model = AutoModel.from_pretrained('klue/bert-base')
tokenizer = AutoTokenizer.from_pretrained('klue/bert-base')
# 토큰화
X_train = tokenizer(X_train, padding=True, truncation=True)
X_test = tokenizer(X_test, padding=True, truncation=True)
# X_train[:3], X_test[:3]
# printX_train['input_ids'][0]
# print(X_train['input_ids'][0]) # input_ids: 단어 토큰화
# print(X_train['attention_mask'][0]) # attention_mask: 실제값/패딩 구분
# print(X_train['token_type_ids'][0]) # token_type_ids: 첫번째/두번째 문장 구분 (단일 문장이라 다 0)
- 데이터 파이프라인 생성
# type(X_train)
import tensorflow as tf
train_ds = tf.data.Dataset.from_tensor_slices((dict(X_train), y_train))
test_ds = tf.data.Dataset.from_tensro_slices((dict(X_test), y_test))
train_dataset = train_ds.shuffle(10000).batch(64).prefetch(tf.data.AUTOTUNE)
test_dataset = test_ds.batch(64).prefetch(tf.data.AUTOTUNE)
- 모델 학습
from transformers import TFBertForSequenceClassification
model = TFBertForSequenceClassification.from_pretrained('klue/bert-base', num_labels=2, from_pt=True)
from transformers import create_optimizer
num_train_steps = len(train_dataset) * 5
num_warmup_steps = int(num_train_steps * 0.1)
optimizer, _ = create_optimizer(
init_lr=5e-5, # 학습률 초기값
num_train_steps=num_train_steps, # 총 학습 step수
num_warmup_steps=num_warmup_steps, # warmup step수 (총 step수 1/10)
weight_decay_rate=0.1 # 학습률 감쇠 계수
)
model.compile(optimizer=optimizer, loss=model.hf_compute_loss, metrics=['accuracy'])
model.fit(train_dataset, epochs=5, validation_data=test_dataset, batch_size=64)
- 모델 저장
model.save_pretrained('nsmc_model/bert-base')
tokenizer.save_pretrained('nsmc_model/bert-base')
- 추론
# 텍스트 분류 라벨 값 지정
model.config.id2label = {
0: "부정",
1: "긍정"
}
from transformers import TextClassificationPipeline
sentiment_classifier = TextClassificationPipeline(
tokenizer=tokenizer,
model=model,
framework='tf',
return_all_scores=True
)
sentiment_classifier('인생 영화를 찾았습니다!!!')
"""
[[{'label': '부정', 'score': 0.0010393332922831178},
{'label': '긍정', 'score': 0.9989606142044067}]]
"""
- HuggingFace
👉🏻 push
from google.colab import userdata
HF_TOKEN = userdata.get('HF_TOKEN')
REPO_NAME = 'bert-base-nsmc'
model.push_to_hub(REPO_NAME, use_temp_dir=True, use_auth_token=HF_TOKEN)
tokenizer.push_to_hub(REPO_NAME, use_temp_dir=True, use_auth_token=HF_TOKEN)
👉🏻 load
from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained('squirreln/bert-base-nsmc')
model = AutoModel.from_pretrained('squirreln/bert-base-nsmc', from_tf=True)
from transformers import pipeline
sentiment_classifier = pipeline('text-classification', model='squirreln/bert-base-nsmc')
# 위 pipeline 코드에서 에러가 발생할 경우 대체
from transformers import pipeline, TFAutoModelForSequenceClassification
model = TFAutoModelForSequenceClassification.from_pretrained('squirreln/bert-base-nsmc')
sentiment_classifier = pipeline(
'text-classification',
model=model,
tokenizer=tokenizer,
framework='tf'
)
# 추론
sentiment_classifier([
'한국 영화는 이제 한물 갔어!',
'어쩌라고 나는 재미있던데?ㅋㅋㅋ',
'혜수 언니 사랑해요',
'평생 잊지 못할 영화를 만났어요... 감동...'
])
HuggingFace Pipeline
!pip install -q transformers datasets
!pip install -q sentencepiece
!pip install -q kobert-transformers
!pip install -q python-dotenv
💧
작업중인 동일 폴더에 .env 파일을 추가하고, HF_TOKEN=키값 넣고 저장
.env는 .gitignore에 포함하기 (github에 올라가는 거 방지)
from dotenv import load_dotenv
import os
load_dotenv()
HF_TOKEN = os.getenv('HF_TOKEN') # 정상적으로 토큰값 가져옴
- NLP Tasks
주어진 task에서 사전 훈련된 모델을 사용하는 가장 간단한 방법은 pipeline을 사용하는 것이다.
from transformers import pipeline
👉🏻 기계번역
!pip install tf-keras
pipeline('translation', model='Helsinki-NLP/opus-mt-ko-en')
translator([
'공부를 열심히 하시면 좋겠어요.',
'수업을 열심히 들으시면 좋겠고요.',
'실습도 열심히 해주시면 좋겠어요.'
])
"""
[{'translation_text': 'I hope you study hard.'},
{'translation_text': "I'd like you to take the class really hard."},
{'translation_text': "I'd like you to work hard on your practice."}]
"""
👉🏻 감성 분석
sentiment_clf = pipeline('sentiment-analysis')
sentiment_clf("I'm very happy!!!") # [{'label': 'POSITIVE', 'score': 0.9998722076416016}]
한국어
ko_seltiment_clf = pipeline('sentiment-analysis', model='sangrimlee/bert-base-multilingual-cased-nsmc')
ko_seltiment_clf([
"어제 배운 Attention이 어려워서 맥주를 한 잔 했어.",
"공부는 어렵지만 맥주는 시원하더라",
"하지만 나는 굴하지 않고 열심히 공부할거야!!!"
])
"""
[{'label': 'negative', 'score': 0.9047993421554565},
{'label': 'negative', 'score': 0.7013086676597595},
{'label': 'positive', 'score': 0.7580994367599487}]
"""
👉🏻 Zero Shot Classification
- shot == 예시
- 예시 없이 (학습 없이) 추론(분류)
zero_shot_clf = pipeline('zero-shot-classification')
zero_shot_clf(
"This is a course about the transformers library.",
candidate_labels=["education", "politics", "business"]
)
"""
{'sequence': 'This is a course about the transformers library.',
'labels': ['education', 'business', 'politics'],
'scores': [0.9053581953048706, 0.07259626686573029, 0.022045595571398735]}
"""
한국어
ko_zero_shot_clf = pipeline('zero-shot-object-detection', model='joeddav/xlm-roberta-large-xnli')
sequence_to_classify = "2025년에는 어떤 운동을 하시겠습니까?!"
candidate_labels = ["정치", "경제", "건강"]
hypothesis_template = "이 텍스트는 {}에 관한 내용입니다."
ko_zero_shot_clf(sequence_to_classify, candidate_labels, hypothesis_template=hypothesis_template)
"""
{'sequence': '2025년에는 어떤 운동을 하시겠습니까?!',
'labels': ['건강', '정치', '경제'],
'scores': [0.9117788672447205, 0.05924064293503761, 0.02898053266108036]}
"""
- 텍스트 생성
text_generator = pipeline('text-generation', model='distilgpt2')
text_generator(
"In this course, we will teach you how to",
max_length=30,
num_return_sequences=2
)
"""
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.
Both `max_new_tokens` (=256) and `max_length`(=30) seem to have been set. `max_new_tokens` will take precedence. Please refer to the documentation for more information. (https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)
[{'generated_text': 'In this course, we will teach you how to use the \u200cC++ language to build and run applications on C++ platforms, and how to use a language in any language. It will also give you some tips on how to use C++.\n\n\n\n\n- There are two types of language: C++ (C++) and C++ (C++) (C++).\nThe C++ language is a type-neutral language, which means that any language that uses an object type is not bound to that type. The C++ language is not bound to that type, so that all any language that uses a class type is not bound to that type.\nI will explain a little more in the C++ language.\nC++ is a language that uses the object type that is not bound to that type. It is a class type that is not bound to that type.\nThere are two types of C++ that are called C++:\nA type type that is not bound to that type. A type that is not bound to that type.\nA type that is not bound to that type. A type that is not bound to that type.\nThe C++ language is a type that is not bound to that type.\nA type that is not bound to that type'}, {'generated_text': "In this course, we will teach you how to generate the code for this course.\n\n\n\nSo, what are these results?\nThe result?\nThe results are the results of the course. We have a number of different values, each of which is different from the other.\nThe results are shown in the course.\nNext, we will implement the new function 'Fancy' which can define the numbers of the values.\nWe are using the function 'Fancy' which can define the numbers of the values.\nAnd then we can use the function 'Fancy' which will define the numbers of the values.\nWe are using the function 'Fancy' which can define the numbers of the values.\nAnd then we are using the function 'Fancy' which can define the numbers of the values.\nAnd then we are using the function 'Fancy' which is used to create the values for the values.\nAnd then we are using the function 'Fancy' which is used to create the values for the values.\nAnd then we are using the function 'Fancy' which is used to create the values for the values.\nAnd then we are using the function 'Fancy' which is used to create the values for the values.\nAnd then we"}]
"""
한국어
ko_text_generator = pipeline('text-generation', model='skt/ko-gpt-trinity-1.2B-v0.5')
ko_text_generator('오늘 점심에는')
# [{'generated_text': '오늘 점심에는 뭐 먹었어\n 답변:저는 배부르게 먹었답니다. 제가 맛있는 메뉴 추천해드릴께요 메뉴 추천해줘"라고 말씀해보세요~"'}]
- Fill Mask
unmasker = pipeline('fill-mask')
unmasker('This course will teach you all about <mask> model.', top_k=3)
"""
[{'score': 0.09073042869567871,
'token': 265,
'token_str': ' business',
'sequence': 'This course will teach you all about business model.'},
{'score': 0.072625532746315,
'token': 30412,
'token_str': ' mathematical',
'sequence': 'This course will teach you all about mathematical model.'},
{'score': 0.049304164946079254,
'token': 5,
'token_str': ' the',
'sequence': 'This course will teach you all about the model.'}]
"""
- NER
ner = pipeline('ner', model='dslim/bert-base-NER', grouped_entities=True)
ner('My name is Squirrel and I work at Playdata in Seoul')
"""
[{'entity_group': 'PER',
'score': 0.98995215,
'word': 'S',
'start': 11,
'end': 12},
{'entity_group': 'PER',
'score': 0.46767735,
'word': '##qui',
'start': 12,
'end': 15},
{'entity_group': 'PER',
'score': 0.72662497,
'word': '##rrel',
'start': 15,
'end': 19},
{'entity_group': 'ORG',
'score': 0.986338,
'word': 'Playdata',
'start': 34,
'end': 42},
{'entity_group': 'LOC',
'score': 0.9994649,
'word': 'Seoul',
'start': 46,
'end': 51}]
"""
- Q&A
qna = pipeline('question-answering')
qna(
question="Where do I work?",
context="My name is Squirrel and I work at Playdata in Seoul"
)
# {'score': 0.8710189713747241, 'start': 34, 'end': 42, 'answer': 'Playdata'}
한국어
ko_qna = pipeline('question-answering', model='klue/roberta-base')
ko_qna(
question="1931년 어떤 진단을 받았나요?",
context="""그러던 1931년, 그는 갑작스럽게 폐결핵을 진단받았다. 이상은 하루에 담배를 50개피 이상 피는 것을 자신의 일과라고 표현했을 정도로 엄청난 골초였는데, 그 때문인지 병세는 날이 갈수록 악화되어 담당의가 그의 폐를 확인하고는 형체도 안 보인다며 혀를 내둘렀을 정도였다. 결국 1933년부터는 각혈까지 시작되었고, 건축기사 일을 지속하기 어렵다고 판단한 이상은 조선총독부에서 퇴사하고 황해도에 있는 배천 온천으로 요양을 간다."""
)
"""
{'score': 0.0003369680780451745,
'start': 49,
'end': 75,
'answer': '이상 피는 것을 자신의 일과라고 표현했을 정도로'}
"""
# help(ko_qna)
'LLM' 카테고리의 다른 글
| 3.3.10 [LLM] 실습 (OpenAI API) (4) | 2025.09.01 |
|---|---|
| 3.3.9 [LLM] 기초 및 응용 (10) | 2025.09.01 |
| 3.3.7 [NLP] 자연어 딥러닝(신경망 기계 번역) (7) | 2025.08.26 |
| 3.3.6 [NLP] 자연어 딥러닝(언어 모델링) (0) | 2025.08.22 |
| 3.3.5 [NLP] 자연어 딥러닝(텍스트 분류) (0) | 2025.08.22 |