일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 파이썬
- 머신러닝
- chromeextention
- pandas
- pytorch
- sLLM
- mysql
- ai 캠프
- Python
- ai캠프
- 티스토리챌린지
- aws
- ai_캠프
- 정치기 필기
- djangorestframework
- Jupyterlab
- conda
- streamlit
- ML
- seaborn
- ollama
- lightsail
- 오블완
- team_project
- mifare
- Github
- finpilot
- django
- 로컬 런타임
- EC2
- Today
- Total
greatsangho의 이야기
캠프37일차 - 자연어 처리 기초(코러스, 문장구조 이해) 본문
- 딥러닝 기반 자연어 처리
- 트랜스퍼 러닝
- 특정 task를 학습한 모델을 다른 타스크 수행에 재사용하는 기법
- 배경지식을 많이 가진 모델을 이용
- 기존 모델의 학습 속도가 빨라지는 장점
- BERT : 빈칸 맞추기
- GPT : 다음 단어 맞추기
- 트랜스퍼 모델 문맥을 모델에 내재화 후 성능 향상
- 업스트림 task
- 다음 단어 맞추기 - GPT 이 태스크로 프리트레인을 수행 (티끌 모아 ??)
- 빈칸 채우기 - BERT 이 태스크로 프리트레인을 수행 (티끌 ?? 태산)
- 빈칸 채우기로 업스트림 task를 수행하는 모델을 마스크 언어 모델
- 비지도 학습
- 레이블을 달아주지 않는 비지도 학습 - 문맥으로 파악
- 문장을 주면 벡터를 통해 앞의 문장과 위치를 고려한 카운팅 진행함
- 어떤 단어 다음에 어떤 단어가 나왔는지 학습
- 단어 사이의 유사한 관계를 업데이트
- 수치로 판단, 1차원 벡터를 만들고 이를 2차원으로 만들어 학습함
- 대량의 데이터 뉴스, 웹문서, 백과사전과 같이 글만 있으면 다량의 데이터를 생성가능
- 데이터 안에서 정답을 만들고 이를 바탕으로 모델을 학습시키는 자기지도학습(self supervised learning)
- 다운스트림 task
- 프리트레인을 마친 모델을 그대로 사용하거나 또는 다른 task 모듈을 덧붙인 형태로 수행
- 본질은 분류 : 입력받은 문장이 어떤 범주에 해당하는지 확률 형태로 판단
- 학습 방법은 파인튜닝 : 프리트레인을 맞춘 모델을 다운스트림에 맞게 업데이트
- 예를 들어 문서를 분류 : 프리트레인을 마친 BRRT 모델 전체를 문서 분류 데이터로 업데이트, or 개체명 인식을 한다면 마찬가지로 BERT모델 전체를 해당 데이터로 업데이트
- 문서 분류
- 문장을 입력 받아서 해당 입력이 긍정 중립 부정에 속하는지 확률값
- 프리트레인을 마친 마스크 언어 모델 위에 작은 모듈을 하나 더 쌓는다
- 각 문장의 시작과 끝을 나타내는 특수기호 CLS, SEP 각각 붙여서 토큰화
- 자연어 추론
- 문장 두개를 입력 받아서 두 문장 사이의 관계가 참 거짓 중립 등 어떤 범주인지 확률
- 개체명 인식
- 자연어를 입력받아서 단어별로 기관명, 인명, 지명 등 어떤 개체명 범주에 속하는지 확률값
- 질의 응답
- 질문+정답(지문) 입력 받아서 각 단어가 정답의 시작일 확률과 끝일 확률을 반환
- 문장 생성
- 문장 생성은 GPT 계열 언어모델에 가장 많이 사용
- 자연어를 입력 받아서 문장 전체에 대한 확률값(다음 문장에 올 단어가 얼마나 적합한지)
- 파인튜닝
- 다운스트림 task 데이터 전체를 사용, 주어진 데이터에 맞게 모델 전체를 업데이트
- 프롬프트 튜닝(prompt)
- 다운스트림 task 데이터 전체를 사용, 주어진 데이터에 맞게 모델 일부를 업데이트
- 인컨텍스트 튜닝(in-contex)
- 다운스트림 task 데이터 일부만 사용, 모델을 업데이트 안 함
- 3가지 방식 : 다운스트림 데이터를 몇 번 참고하느냐의 차이가 있을 뿐 모두 모델을 업데이트 하지 않는다
- 제로샷 러닝
- 다운스트림 데이터를 전혀 사용 안함. 모델 바로 다운스트림 타스크를 수행
- 원샷 러닝
- 다운스트림 데이터를 1건만(1건도 용량 많음) 사용, 모델은 1건의 데이터가 어떻게 수행되는지 참고한다음 다운스트림 task를 수행
- 퓨샷 러닝
- 다운스트림 데이터를 몇 건 사용, 모델은 1건의 데이터가 어떻게 수행되는지 참고한다음 다운스트림 task를 수행
- 파인튜닝이 아닌 프롬프트 튜닝과 인컨텍스트 튜닝을 이용해 비용절감
학습 파이프라인 형태로 진행
send = ("휴일 인 오늘 도 서쪽 을 중심 으로 폭염 이 이어졌는데요, 내일 은 반가운 비 소식 이 있습니다.",
"폭염 을 피해서 휴일 에 놀러왔다가 갑작스런 비 로 인해 망연자실 하고 있습니 다.")
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(send) # 문장 벡터화
tfidf_matrix.toarray() # 2차원 배열로 변환
tfidf_vectorizer.idf_, tfidf_vectorizer.get_feature_names_out()
- 유사도(Simularity)
- 문장을 적당한 기법으로 수치벡터화를 해서 두개의 객체(문서, 문장, 벡터) 얼마나 비슷한지 표현
- 값이 높을수록 유사
- 코사인 유사도
- 두 벡터간의 각도에 기반, 각도가 0에 가까울수록 유사
- -1 ~ 1
- 0 연관 없음
- -1 정반대 방향(완전히 다른)
- 1 완벽히 동일방향(완벽하게 유사)
- A@B (dot product) 내적연산
- ||A|| 벡터의 크기(노름)
- A@B / ||A||||B||
- 유클리디안 거리
- 두 벡터간의 직선의 거리
- np.sqrt(mean((Ai - Bi)^2))
- 자카드 유사도: 두 집합간의 교집합과 합집합의 비율
- |A 교집합 B| / |A 합집합 B|
- 맨해튼 거리 : 두 벡터간의 각 차원에서 절대적인 차이값들의 합
- mean(|Ai - Bi|)
# 자카드
set1 = set(v1) ; set2 = set(v2)
len(set1.intersection(set2)) / len(set1.union(set2)) # 교집합
# 코사인 유사도
from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2]), cosine_similarity([v1],[v2])
# 유클리디안 거리
# 거리기반
# 정규화
from sklearn.preprocessing import StandardScaler
sc = StandardScaler().fit_transform(tfidf_matrix.toarray())
from sklearn.metrics.pairwise import euclidean_distances
euclidean_distances(sc[0:1], sc[1:2]), euclidean_distances([v1],[v2])
코사인 유사도는 각도를 본다. 유클리디안 거리는 거리 기반이므로 정규화 적용이 필요하다.
자연어 처리
데이터 불러오기
train_neg_path = glob('/content/datasets/aclImdb/train/neg/*.txt')
train_pos_path = glob('/content/datasets/aclImdb/train/pos/*.txt')
import pandas as pd
# review / sentiment(pos 1 neg 0)
# 파일로 목록에 있는 데이터를 읽어서 리스트에 추가한 후 데이터 프레임으로 변환
train_neg_list = []
train_pos_list = []
train_neg_path[0]
train_pos_path[0]
for filepath in train_neg_path:
with open(filepath, 'r', encoding='utf-8') as f:
train_neg_list.append([f.read(),0])
for filepath in train_pos_path:
with open(filepath, 'r', encoding='utf-8') as f:
train_pos_list.append([f.read(),1])
train_df = pd.DataFrame(train_neg_list + train_pos_list, columns=['review', 'sentiment'])
train_df
문자열 토큰화 하기
reviews = train_df['review'].values
reviews[0].split()
# 문자열을 토큰화
tokenizer_reviews = [ context.split() for context in reviews]
# tokenizer_reviews[0]
# 각 토큰화 된 리스트의 개수
review_len_by_token = [len(review) for review in tokenizer_reviews]
# 공백을 제거한 상태의 문장의 길이
review_len_by_token_len = [len(s.replace(' ','')) for s in reviews]
단어의 길이 시각화
# 토큰을 시각화해서 앞의 토큰 단위하고 비교, 데이터 간의 차이
import matplotlib.pyplot as plt
plt.hist(review_len_by_token, bins=50, alpha=0.5, color='r', label='word')
plt.hist(review_len_by_token_len, bins=50, alpha=0.5, color='b', label='alphabet')
plt.legend(loc='upper right')
plt.yscale('log')
plt.xlabel('Review Length')
plt.ylabel('Number of Reviews')
plt.show()
대표적인 통계값 구하기
# 적절한 문장의 길이 구하기
import numpy as np
# np.percentile(review_len_by_token, 95)
print(f'문장의 최대 길이:{np.max(review_len_by_token)}')
print(f'문장의 최소 길이:{np.min(review_len_by_token)}')
print(f'문장의 평균 길이:{np.mean(review_len_by_token)}')
# 중앙값(중위수) : 중간에 위치한 값, 평균은 이상치에 의해 왜곡될 수 있어서
print(f'문장의 중앙값 길이:{np.median(review_len_by_token)}')
# 표준편차 : 평균에서 떨어진 정도, 높은 표준편차는 문장의 길이의 분포가 넓다
print(f'문장의 표준편차:{np.std(review_len_by_token)}')
# 1사분위 : 하위 25%
print(f'문장의 1사분위:{np.percentile(review_len_by_token, 25)}')
# 3사분위 : 상위 25%
print(f'문장의 3사분위:{np.percentile(review_len_by_token, 75)}')
# 각각에 대해 boxplot
plt.boxplot(review_len_by_token)
plt.show()
워드 클라우드
from wordcloud import WordCloud
wordcloud = WordCloud(width=800, height=800, background_color='white').generate(' '.join(train_df['review']))
plt.figure(figsize=(10,10))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
정답 분포
# 정답에 대한 개수 분포
import seaborn as sns
train_df['sentiment'].value_counts()
sns.countplot(x='sentiment', data=train_df)
plt.show()
LLM을 위한 전처리
# 벡터화 한 데이터의 크기를 같게 맞추어 주어야 함
# 데이터 크기
# 개수
# 각 문자의 길이 분포
# 많이 사용된 단어
# 긍정 부정의 분포
# 단어개수
# 특수문자, 대소문자 비율
# 동시출현 행렬 : 고유단어 행렬, 각 단어의 쌍이 문장에서 동시에 나타난 횟수
# 윈도위 크기 : 윈도우 크기 기준으로 단어가 얼마나 자주 나타나는지.. 앞뒤로 2개까지 출현 횟수
# 고양이가 나무에 올라갔다
# 고양이가 개를 쫓았다
# 단어간의 관계를 분석
# 고양이가 나무에 올라갔다 개를 쫓았다
# 고양이 0 1 0 1 0
# 나무에 0 0 1 0 0
# 올라갔다
# 개를
# 쫓았다
이런 형태로 앞 뒤에 단어가 들어가 있는지 확인하여 표시한다.
따옴표가 포함된 csv 파일 열기
# 필드에 따옴표가 포함된 경우에는 따로 처리하지 않고그대로 사용 quoting=3
train_data = pd.read_csv('unlabeledTrainData.tsv', sep='\t',quoting=3) # 따옴표 무시
train_data.head()
문자열 길이 시각화
# 리뷰문자의 길이
# train_length = [len(review) for review in train_data['review']]
train_length = train_data['review'].str.len()
train_length.head()
train_length.hist(bins=200) # 빈도 vs 길이
# 자연어 데이터 전처리
# 불필요한 토큰 제거(불용어, 특수기호 등..)
# 전부 소문자로 변경
# 다시 해당 단어를 문장으로 결합(공백을 기준으로)
# 데이터 로드
import pandas as pd
train_df = pd.read_csv('labeledTrainData.tsv', sep='\t', quoting=3)
# html tag 제거
from bs4 import BeautifulSoup
train_df['review'] = train_df['review'].apply(lambda x: BeautifulSoup(x, 'html5lib').get_text())
# 모든 문자열은 소문자로 변환
train_df['review'] = train_df['review'].str.lower()
# 각 라인별 영문자 및 숫자만 존재하도록 정규화를 이용해서 수정
import re
train_df['review'] = train_df['review'].apply(lambda x: re.sub('[^a-z0-9 ]', '', x))
# 각 라인별 문자열을 공백을 기준으로 토큰화(공백 기준으로 split)
train_df['review'] = train_df['review'].str.split() # str 문자열, dt 날짜, apply와 같이 라인별로 적용됨
# 불용어(부사 전치사 등등) 리스트를 가져와서 해당 문자열의 각 단어에서 불용어가 아닌 토큰만 수집
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
stop_words = set(stopwords.words('english'))
train_df['review'] = train_df['review'].apply(lambda x: [word for word in x if word not in stop_words]) # str은 정해진 함수를 적용할 때
# 토큰들을 공백을 기준으로 합쳐
train_df['review'] = train_df['review'].apply(lambda x: ' '.join(x))
train_df['review']
# 단어빈도수 구하기
from collections import Counter
c = Counter()
for review in train_df['review'].values:
c.update(review.split())
c.most_common(10)
'프로그래밍 > SK AI 캠프' 카테고리의 다른 글
캠프52일차 - 프롬프트 엔지니어링 응용(랭체인, RAG(검색 증강 생성)) (1) | 2024.11.08 |
---|---|
캠프51일차 - 프롬프트 엔지니어링 응용(랭체인) (9) | 2024.11.07 |
캠프35~36일차 - 2차 팀프로젝트 (0) | 2024.10.18 |
WSL2 conda 환경에 Tensorflow2와 CUDA 연결하여 설치하기 (0) | 2024.10.13 |
도커를 활용한 colab 로컬 런타임 연결 (1) | 2024.10.12 |