오늘은 딥러닝 NLP모델의 이해를 위한 실습과
딥러닝의 활성화 함수에 대한 수업을 진행했다.
내일쯤이면 딥러닝 파트가 끝난다고 한다.
넘나어려운것
목표
- NLP(자연어 처리 과정 이해)
- LLM의 기반
- 백터디비, RAG, 유사도 등등 연관성
- 토큰화 작업
- 말뭉치 -> ....... -> 토큰화
- LLM의 기반
- 전이학습 (누군가 만든 모델을 사용->시간절약, 빠르게 높은 성능 보장받을수 있음)
- 제로샷, 파인튜닝등 학습법 확인
- 성능 무시(고려 사항 아님)
연구목표
- AI기반 챗봇 구성
- 사용자 질문 -> 해당 질문 토큰화 -> 기존의 챗봇시트(백터(1차원, 1배열) 데이터를 가진 자료구조)에서 유사도 검사 -> 유사도 값이 가장 작은 값(질문과 가장 가까운 질문지) 선택 -> 이에 대응하는 답변 응답
- 챗봇시트 (ChatbotData.csv)
- 개인 작업자 작성후 공유한 데이터(출처 추후 표시)
- 시뮬레이션 - gradio 진행
데이터 획득
- 말뭉치(코퍼스) 획득 가능

이렇게 수많은 말뭉치들이 있다. 그 중 nsmc를 선택했다.
# 리뷰데이터 획득
corpus = Korpora.load('nsmc')
Korpora 는 다른 분들이 연구 목적으로 공유해주신 말뭉치들을
손쉽게 다운로드, 사용할 수 있는 기능만을 제공합니다.
말뭉치들을 공유해 주신 분들에게 감사드리며, 각 말뭉치 별 설명과 라이센스를 공유 드립니다.
해당 말뭉치에 대해 자세히 알고 싶으신 분은 아래의 description 을 참고,
해당 말뭉치를 연구/상용의 목적으로 이용하실 때에는 아래의 라이센스를 참고해 주시기 바랍니다.
# Description
Author : e9t@github
Repository : https://github.com/e9t/nsmc
References : www.lucypark.kr/docs/2015-pyconkr/#39
Naver sentiment movie corpus v1.0
This is a movie review dataset in the Korean language.
Reviews were scraped from Naver Movies.
The dataset construction is based on the method noted in
[Large movie review dataset][^1] from Maas et al., 2011.
[^1]: http://ai.stanford.edu/~amaas/data/sentiment/
# License
CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
Details in https://creativecommons.org/publicdomain/zero/1.0/
[Korpora] Corpus `nsmc` is already installed at /root/Korpora/nsmc/ratings_train.txt
[Korpora] Corpus `nsmc` is already installed at /root/Korpora/nsmc/ratings_test.txt
# 정답 확인
# 리뷰의 감정분석(긍정/부정) 대한 데이터임
set( corpus.get_all_labels() ) # {0:부정 1:긍정}
{0, 1}
len(corpus.train), len(corpus.test) # 데이터 20만개
(150000, 50000)
corpus.train.get_all_texts()[100], corpus.train.get_all_labels()[100]
('신카이 마코토의 작화와,미유와 하나카나가 연기를 잘해줘서 더대박이였다.', 1)
type(corpus.train.get_all_texts())
tuple
데이터 준비 + 분석(EDA)

훈련데이터를 준비해준다.


모델 구축
토크나이저를 이용한 토큰화
- 문장 -> 분절 -> 사전화 -> 백터화 -> 패딩 -> 임베딩
- '오늘 날씨는 너무 ...' -> .... -> [0, 312, 23, 1, 56, .... , 9]
- 텍스트 => 수치화 (규칙, 크기, 등등 정보필요) => 토큰화!!
- 토크나이저는 토큰화 처리 도구(위의 공정을 한번데 다 수행할수 있음)
- LLM이나 트랜스포머 계열 제품은 함수 호출로 전과정이 완료됨
분절화
- 방법
- 공백 기반 분절(분리, 분해)
- 알파벳, LLM쪽에서 사용하는 도구에서는 주로 공백기반임
- 형태소 분석기 통해 분절(한국어등 교착어 대상)
- 공백 기반 분절(분리, 분해)
# 1. 한국어 대상 형태소 분석기(교착어 중심) 설치
# 교착어 -> 자연어처리( 한국어 초기모델 )-> 성과 잘 안나옴
# LLM 이후 -> 한국어 처리 -> 공백 기반으로 명사 + 조사 통으로 학습
# -> 물량으로 처리 (GPT, 구글) -> 성과 잘 나옴
!pip install -q konlpy
# 2. 형태소 분석기 모듈 가져오기
from konlpy.tag import Okt
# 3. 분절만 담당하는 도구 => 실제 NLP에서는 백터화까지 모두 진행함
tokenizer = Okt()
# 4. 분절 확인
# 원 문장
train_df.sentence[99]
---------------------
'설정이 재밌고 새로운 에피소드 내에서 메인 스토리도 차차 나오는게 재밌음'
---------------------
# 분절
tokenizer.morphs( train_df.sentence[99] )
# 형태소 분석기 => "설정", "이"
# LLM기반 토큰 => "설정이"
---------------------
['설정',
'이',
'재밌고',
'새로운',
'에피소드',
'내',
'에서',
'메인',
'스토리',
'도',
'차차',
'나오는게',
'재밌음']
---------------------
# 형태소 분석기 기반으로 문장을 구성한다면 => 분절된 토큰 사이에 공백 개입 문장 완성
# 설정 이 재밌고 새로운 에피소드 내 에서 ... => LLM 은 이렇게 처리 하지 않음!!
# 형태소 분리해서 문장을 이해하는 것은 쉽이 않음
# => 대체 필요 (공백 기반 토큰화, 물량으로 해결(설정이, 설정을, ....):학습량으로 해결)
분절화(공백단위 진행)
from tensorflow.keras.preprocessing.text import Tokenizer
nlp_tokenizer = Tokenizer()
%%time
# 문장 => 분절(공백기반) => 사전화 구축 (토큰별로 숫자를 부여)
nlp_tokenizer.fit_on_texts( train_df.sentence )
사전화
- 분절 후 토큰(분절한 단어의 단위, 분절단위)으로 쪼개짐
- 토큰이 발견되면 순차적으로 라베링 수행함
- 영화 -> 1, 너무 -> 2, ...
- 토큰에 라벨을 부여하여 데이터를 준비 -> 사전화

백터화
- 문장 1개에 대해서 백터(1차원) 구성

백터화 이후 전처리의 개념으로 패딩 공정을 거쳐 보정해주어야한다.
패딩
- 모든 문장의 길이를 통일 -> 학습 가능한 형태가 됨
- 길이
- 설정한 최대 길이값?
- 특정 모델의 성능에 대한 성능제한을 둘 수 있음, 버전이 올라가면 더 많은 길이 제공 (업그레이드된 효과)
- 데이터 길이가 더 긴 경우 정보손실 나올수 있음
- 자르기를 통해서 (청크)단위 구성을 할 수 있음
- 데이터의 최대 길이? -> 데이터가 추가되거나 등등 하면 변경되수 있음
- 장점 : 정보 손실 없음
- 설정한 최대 길이값?
# 주어진 데이터의 최대 길이 획득
# 문장 전체 => 벡터화
#
x = nlp_tokenizer.texts_to_sequences(train_df.iloc[: , 0 ])
x

모든 말뭉치를 백터화했다.

가장 많은 토큰으로 구성된 문자의 길이값을 구하는 내용이다. 이것을 알아야 데이터 손실없이 패딩 공정이 가능하다.

패딩 공정 코드, 기본값들에 옵션들을 채워주고 아까 구한 59개의 토큰에서 안정적으로 +1 해준다, 안해도 되긴 한다.
이렇게 리스트를 패딩을 통해서 배열로 바꿔주어야 한다.

x_padding. nparray의 형태
임베딩
- 인공신경망에 데이터를 주입할 때 (학습 시) 임베딩 수행함 (압축 행위 수행, 필요시 원핫인코딩까지 진행함)
- 본 노트에서는 백터화된 데이터만 사용 (모델 사용 x) => 생략
인공신경망 구축 -> 학습 -> 평가, ... 생략
시스템 구축, 통합, 모델 덤프 및 서빙
벡터의 유사도 검사
- 문장(자연어) -> 백터화 (수치화됨)
- 원리
- 문장과 문장의 유사도는 벡터대 벡터간 거리를 기반 계산 -> 거리(양)추출됨
- 거리가 가장 작은 벡터간의 가장 유사한 내용임 -> 챗봇 시트내에 준비된 질문과 동일한 내용으로 간주
- 코사인 유사도 사용
- 방향성을 중시 => 내용의 유사성 중시
- 코사인 유사도 사용
- 참고
- 벡터 유사도 검사는 텍스트, 이미지 등 데이터를 숫자 벡터로 변환한 뒤, 이 벡터들 간의 거리나 방향을 측정하여 얼마나 비슷한지 평가하는 기술입니다. 주로 코사인 유사도를 사용해 두 벡터의 각도를 기반으로 유사도를 1 (완전 동일) ~ -1 (완전 반대) 사이의 값으로 측정하며, 추천 시스템, 검색 엔진, 자연어 처리 등에서 핵심적인 역할을 합니다.
- 벡터 유사도 검사의 주요 방식
- 코사인 유사도 (Cosine Similarity): 가장 흔히 사용되며, 벡터의 크기(길이)를 무시하고 방향만으로 유사도를 측정합니다.
- 원리: 두 벡터의 내적(dot product)을 각 벡터의 크기로 나눈 값으로, 1에 가까울수록 비슷하고, 0에 가까우면 직각(무관), -1에 가까우면 정반대입니다.
- 장점: 데이터의 절대적인 크기(예: 문서의 길이)보다는 내용의 유사성을 파악하는 데 효과적입니다.
- 유클리드 유사도 (Euclidean Similarity): 두 벡터의 좌표값 차이를 제곱하여 더한 후 제곱근을 씌운 '거리'를 기반으로 유사도를 측정합니다.
- 원리: 거리가 가까울수록 유사도가 높다고 판단합니다
- 코사인 유사도 (Cosine Similarity): 가장 흔히 사용되며, 벡터의 크기(길이)를 무시하고 방향만으로 유사도를 측정합니다.
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# 참고로 scipy, sklearn 등등 다양하게 제공됨
def cos_sim(AVec, BVec):
return np.dot(AVec, BVec) / ( np.linalg.norm(AVec) * np.linalg.norm(BVec) )
벡터의 유사도를 검사하는 코드이다,.
사용자 입력 => 백터화 함수
- 시나리오
- 사용자 입력 -> 벡터화 -> 패딩(최대길이 60) -> 챗봇 시트의 질문지와 유사도 검사 -> 값이 가장 작은 데이터 찾음 -. 답변 획득 -> 응답

사용자가 입력한 내용을 벡터화 해준다,
그 이후 패딩까지 처리해주는 인코더 함수를 정의해준다.
함수를 호출해보면 바로 배열까지 인코딩해주는 모습을 볼 수 있따.

다른 csv파일을 불러온다,

apply() 와 lambda 함수를 사용해서 모든 11823개의 데이터의 q 내용이 vec라는 파생 변수에 추가되도록 해준다.
# 유사도 검사 함수
def ckeck_answer_similar(question=''):
if not question:
return '정확하게 입력 후 질문하시기 바랍니다.'
# 1. 질문 -> 벡터화
q_vec = custom_encode(question)
# 2. 챗봇 시트 df에서 질문 -> x_padding 을 통해서 벡터화 구성되어있음
# x_padding 과 q_vec의 같은 코사인 유사도를 계싼하여서
# train_df의 파생변수(추가 컬럼)으로 'score'에 담으시오
chatbot_df['score'] = chatbot_df.vec.apply(lambda x : cos_sim(x, q_vec))
# cos_sim( 챗봇시트1개 질문벡터, q_vec)
# 3. 가장 유사한 질문 -> 코사인 유사도는 방향성 -> 가장 큰 값 취하면 됨
# 만약, 유클리드 -> 거리가 큰 값
# idxmax()해당 컬럼의 값이 가장 큰 데이터의 인덱스값 반환
# 사용자 질문에 가장 가까운 질문을 찾아서 거기에 대응하는 답변을 응답
return chatbot_df.loc[chatbot_df['score'].idxmax()]['A']
pass
# 사용자 질문을 입력받음
ckeck_answer_similar('아 진짜 돈까스')
-------------------------
'송장 번호를 확인해보세요.'
-------------------------
# 동문 서답의 이유 => 사전 구축(14만개의 리뷰), 응답(챗봇시트) => 상호 어휘량 다름
# 말뭉치의 양(장르,분야,등등 다양 대량), 토크나이저가 전문화될 필요
사전 학습된 모델(pre-trained model) 사용
- 토크나이저를 허깅페이스상 등록된 제품으로 교체
- 편의상 말뭉치를 챗봇시트로 교체하여 사전 구축
- 전이학습 전략 활용
- https://huggingface.co/sentence-transformers/xlm-r-100langs-bert-base-nli-stsb-mean-tokens
- Bert 계열
- sentence-Bert 모델을 업스트림으로 사용하여 카카오브레인의 STS,NLI 데이터셋으로 파인튜닝한 모델
- 한국어 데이터 샘플 소개
- 제작자가 시간과 비용을 투자하여 만든 모델을 그대로 가져와서 사용
- 해당 모델에는 토크나이저, 모델 준비됨
- 트랜스포머
# 트랜스포머 계열 모델이 가장 많이 등록된 커뮤니티 => 허깅페이스
!pip show sentence-transformers
from sentence_transformers import SentenceTransformer
# 허깅펭스 기반에 등록된 사전학습된 모델의 이름 or 경로
model_name = 'sentence-transformers/xlm-r-100langs-bert-base-nli-stsb-mean-tokens'
model = SentenceTransformer(model_name)
%%time
# 얘는 통합형 모델이기때문에 토크나이저랑 모델이 결합된 형태임(케이스 바이 케이스긴 함)
res = model.encode(['오늘 저녁은 물 한잔 드링킹'])
# (1, 768) 문장 1개에 대한 최대 토큰수 => 768
res.shape
# 기존 챗봇시트 => 인코드 함수를 통해서 벡터화 처리
chatbot_df.head(1)
# 사전 준비된 df 파일
# 파이썬에 했던 pickle로 저장한거임
import pickle
pre_data = '/content/drive/MyDrive/GoodNotes/t아카데미/7. data_analysis_ml_dl_llm/nlp/chatbot_df.dat'
# 로드처리 실습
with open(pre_data, 'rb') as f:
df = pickle.load(f)
df.head(2)

전체 문장 11823개를 모두 처리하기는 너무 오래걸려서 사전 준비된 데이터로 로드했다.
하면서 나름 pickle도 복습
# 유사도 계산하여 답변처리
def ckeck_answer_similar(question=''):
if not question:
return '정확하게 입력 후 질문하시기 바랍니다.'
q_vec = model.encode(question) # 토크나이저 변경 (768 토큰길이를 가진 토크나이저)
# df의 이름 변경됨, 벡터값을 가진 컬럼명 변경 'em'
df['score'] = df.em.apply(lambda x : cos_sim(x, q_vec))
return df.loc[df['score'].idxmax()]['A']
pass
ckeck_answer_similar('다시 돌아가고 싶어요?')
------------------------
돌아오길 바란다면 연락해보세요.
------------------------
좀 똑똑해졌다.
결론
- 자연어 처리, LLM 등등 자연어를 데이터로, 기반으로 추론/생성 등 행위를 하는 모델들은 반드시 자연어를 수치화하는 토크나이저가 필요하다
- 많은 언어를 커버할수로그 버전이 올라갈수록 토큰에 사용되는 사전의 수가 기하급수적으로 올라감 => 모델이 사용자의 질의를 더 잘 이해하게 되는 기반
- LLM 모델이 새로 나오면 표현 가능한 토큰수 체크
- 말뭉치 -> ... -> 임베딩된 백터 표현 : 과정이해
- 실제
- 스페셜 토큰 존재함
- 문장의 시작과 끝 표시
- 없는 토큰에 대한 표시
- 문장 구분들 표시
- ... => 통상 등 태그 형태로 표기함
- 스페셜 토큰 존재함
- 실제
개요
- Activation function
- 포지션
- 절차
- 데이터
- 모델
-
- 인공신경망구성(CNN,RNN등 신경망 구조 속에 활성화함수 활용)
- 직접 신경망 구성에 관여하지 않으면 접하지 못함.
-
- [학습회수(epoch),데이터크기(batch_size), 최적화도구(gd->..adam/nadam), 평가도구 세팅(정확도,손실)]
-
- 데이터주입 후 학습
-
- 절차
- 사용이유
- 인공신경망의 성능 향상(정확도 향상) 위해 사용.
- 최적화 도구
- GD->SGD -> ... -> ADAM -> ..
- 미세 조정을 통해 최적의 파라미터 W,b값 찾는 도구
- 활성화 함수 사용
- 은닉층 사용시
- 데이터를 전반적으로 조정
- 데이터를 선형(예측 정확도 높음)에서 비선형(예측 정확도 낮음)으로 변경등 분포 조정
- 이로 인해 층을 더 깊게 구성하는 이유가 됨
- 활성화를 미사용 -> 대부분 데이터가 조기에 선형 수준으로 조정 -> 과적합, 얕은 깊이의 구조가 됨
- 단점
- 정보 손실 발생
- 데이터를 전반적으로 조정
- 출력측 사용시
- (이진|다중)분류 처리등에 활용
- 이진 : 시그모이드
- 다중 : 소프트맥스
- (이진|다중)분류 처리등에 활용
- 은닉층 사용시
- 최적화 도구
- 인공신경망의 성능 향상(정확도 향상) 위해 사용.
sigmoid
- 머신러닝에서 개발, 초기 딥러닝 사용
- 입력 : 실수( -무한대 ~ +무한대)
- 출력 : 0 ~ 1 => 음수값 X
- 용도 : 이진 분류
- 출력층 사용
- 문제점
- 입력값이 커지거나 작아지면 거의 1.0, 0.0에 수렴
- 기울기 0이 됨 -> 학습 효과 X -> 학습을 통해 만들어진 신경망내의 가중치값 미반영 -> 죽은 뉴런 문제 발생
- 입력값이 커지거나 작아지면 거의 1.0, 0.0에 수렴


이진분류법에 사용되는 함수이다.
tanh
- sigmoid 개선
- 변동폭을 2배로 확장
- 출력 : -1 ~ 1
- 범위를 넓혀서 발생 빈도르 줄임 (죽은 뉴런)
- LSTM-GRU 에서 내부적으로 사용됨
- 해결 못함

relu
- 최근 많이 사용 (20여년)
- 장점
- 가장 빠르게 처리(연산 비용 적음)
- 단점
- 죽은 뉴런 미해결(x값이 음수일때) -> 음수일때 미응답 발생 가능성 있음

relu는 자주 사용되고 디벨롭도 relu 기준으로 많이 되었따.
leaky relu
- 음수대역에서 기울기를 0.01로 부여 -> 완만하게 죽은 뉴런이 발생하도록 조정

PRelu
- 0.01로 고정값이 아닌 파라미터를 받아서 처리
- 자유도 부여(음수대역 기울기) -> 유연성 부여

ELU
- 음수대역 -> 기울기 -> 미분적용
- 직선 x -> 커브 도입
- 단점 : 연산 비용 비싸짐

Maxout
- Relu의 장점 + 죽은 뉴런 문제 해결(학습이 안됨)
- 파라미터 많다 -> 연산비용이 상승 -> 학습 속도 저하

Softmax
- 전체에 대한 개별 비율 -> 다중(다항) 분류
- 확률의 총합 => 1.0
- 출력층 사용

사용자 정의 활성화함수 -> 발표?
- 사내용으로 비공개 용도로 존재할 수 있음
오늘의 수업은 여기까지
'ASAC-SK플래닛 T아카데미 데이터 엔지니어' 카테고리의 다른 글
| 25.12.17 50일차 [딥러닝 | AWS sagemaker , NO-CODE GUI 기반 딥러닝 실습 / LLM | Bedrock] (0) | 2025.12.17 |
|---|---|
| 25.12.16 49일차 [딥러닝_전이학습 | 딥러닝_NLP_트랜스포머기반_전이학습_GPT2기반_제로샷러닝_리뷰감정분석] (1) | 2025.12.16 |
| 25.12.12 47일차 [딥러닝 | 개요, NLP 모델] (0) | 2025.12.15 |
| 25.12.11 46일차 [머신러닝_비지도학습_군집화_차원축소] (0) | 2025.12.11 |
| 25.12.11 SK플래닛 T아카데미 | AI활용 데이터 엔지니어 과정 2기 모집 (0) | 2025.12.11 |