최종적으로 해결하고자 하는 작업을 의미합니다. Downstream이라는 말은 영어 그대로 직역 하면 '하류(下流)' 입니다.
물은 위에서 흘러 아래로 흘러갑니다. 즉, 상류(Upstream)에서 하류(downstream)로 흘러가는 순서가 존재합니다.
우리가 하는 작업에도 순서가 있는데, 먼저 해결해야 할 작업을 Upsteam task라 부르고 다음에 최종적으로 해결하고자 하는 작업을 Downstream task라고 합니다. 그렇다면 딥러닝에서의 Downstream task은 무엇을 의미할까요? 이는 전이학습 (Transfer Leanring)과 깊은 관련이 있습니다.
전이학습(Transfer learing) 이란, 모델을 처음부터 끝까지 (from scratch) 새로 훈련하는 것이 아니라, 미리 훈련된 (pre-trained) 모델로부터 학습을 시작하는 것을 의미합니다.
이를 up/down stream의 개념에 비유해보면, upstream은 미리 훈련된 pre-trained model이 될 것이고, downstream은 내가 최종적으로 만들고자 하는 모델이 될 것입니다.
마치 직장에서 후배가 선배의 보고서를 참조하는 것과 유사한데요, 선배가 보고서가 좋은 보고서라면 (good upstream), 후배가 보고서를 쓰기 훨씬 수월할 것입니다. (good down stream)
늑대와 호랑이를 분류하는 Downstream task를 생각해 볼까요? 개와 고양이를 분류하는 모델이 이미 학습되었다면, 이를 늑대와 호랑이를 분류하는 모델에 활용할 수 있을 것입니다. 늑대와 개 / 호랑이와 고양이는 서로 비슷한 특징을 가지고 있기 때문입니다!
딥러닝 분야에서 downstream이라는 말은 다양한 분야에서 쓰입니다. 자연어처리(NLP), 이미지 분류(image classification)등 많은 포스팅과 논문에서 Downstream이라는 단어가 등장합니다.
하지만 분야에 상관없이 모두 '내가 최종적으로 해결하고 싶은 문제', 'upstream을 거쳐 단계적으로 해결하는 것이 보다 좋은 문제'라는 점에서는 일맥상통하는 것 같습니다.
안녕하세요. 은공지능 공작소의 파이찬입니다! 정말 오랜만에 포스팅을 올리네요. 9월달은 정말 바쁘게 지낸 것 같습니다. 오늘은 tf-idf vectorizer를 생성할 때 필요한 여러가지 파라미터들에 대해 알아보겠습니다.
min_idf, analyzer, sublinear_tf, ngram_range, max_features 이렇게 5가지 파라미터들에 대해서 알아볼 것입니다.
1. 사전준비
from sklearn.feature_extraction.text import TfidfVectorizer
text = ['I go to my home my home is very large',
'I went out my home I go to the market',
'I bought a yellow lemon I go back to home']
tfidf_vectorizer = TfidfVectorizer()
우선 위와같이 데이터를 생성해 줍니다. 저번 시간에 썼던 데이터와 동일한 데이터 입니다. 오늘 사용할 파라미터는 TfidfVectorizer()의 괄호 안에 들어가는 것들입니다.
sublinear_tf를 구현해보는 간단한 함수를 만들어 보았습니다. 결과를 보시면 100은 5.6 정도로, 10000은 10.2 정도로 값이 확 줄어든 것을 확인하실 수 있습니다. 이처럼 sublinear_tf는 높은 TF값을 완만하게 처리하는 효과를 가지고 있습니다.
TF의 아웃라이어가 너무 심한 데이터의 경우, 이런 서브리니어 파라미터를 True로 바꿔주면 어느정도 효과를 기대할 수 있습니다. 간단히 코드 실습 후 넘어가겠습니다.
vectorizer = TfidfVectorizer(sublinear_tf = True) # defalut는 False입니다.
vectorizer.fit(text)
a = vectorizer.transform(text).toarray()
a
위와 같이 sublinear_tf를 True로 설정하면, 높은 TF값들에 대해서 스무딩 처리를 해줍니다. 하지만 저희 예제 데이터는 너무 작기 때문에, 해당 파라리터의 효과가 별로 없는 것 같네요. 'TF 값에 대해 아웃라이어 처리를 해준다'라는 효과 정도만 기억하고 넘어가시면 되겠습니다.
5. ngram_range 파라미터 이해하기
n-gram이라는 것은 단어의 묶음을 말합니다. 이 단어의 묶음을 범위를 설정하는 것이 ngram_range 파라미터입니다.
예를들어, ngram_range = (1, 1)이라면 단어의 묶음을 1개부터 1개까지 설정하라는 의미입니다. 단어사전에는 1개 단어묶음에 인덱스가 할당되겠죠. 이는 기존의 벡터라이저와 별 차이가 없는 결과를 내놓습니다.
만약 ngram_range = (1, 2)라고 한다면, 단어의 묶음을 1개부터 2개까지 설정하라는 뜻입니다. 단어사전에는 1개 단어묶음도 있고, 2개 단어묶음도 존재하게 되겠죠. 가령, 'go home', 'very good'과 같은 2개 짜리 묶음도 인덱스를 받게 되는 것입니다.
이번에는 ngram_range를 (1, 2)로 설정해보았습니다. 이는 단어묶음을 1개부터 2개까지로 세팅하겠다는 뜻입니다. 단어사전을 출력해보니, 단어 2개 묶음도 인덱스를 받은 것을 볼 수 있습니다.
사실 이번 포스팅은 이 ngram을 설명할고 하다가, 아예 기본적인 파라미터들을 다 설명해기로 하고 만든 것입니다 ^^
그럼 이 ngram_range를 사용하는 이유는 무엇일까요? 단어가 묶여야 비로소 의미를 가지는 것들이 있기 때문입니다. 예를들어 'very'라는 단어 하나만으로는 의미를 잘 알 수 없지만 'very good', 'very bad' 등과 같이 뒤에 오는 단어가 같이 오면 정확한 의미를 알 수 있습니다. 이렇게 묶여야 의미가 살아나는 녀석들 때문에, ngram_range를 사용한다고 볼 수 있습니다.
6. max_features 파라미터 알아보기
max_feature는 tf-idf vector의 최대 feature를 설정해주는 파라미터입니다. 해당 파라미터를 이해하려면, feature의 개념에 대해 아셔야 합니다.
머신러닝에서 feature란, 테이블의 컬럼에 해당하는 개념입니다. 또한 행렬의 열에 해당하는 것이기도 합니다.
TF-IDF 벡터는 단어사전의 인덱스만큼 feature를 부여받습니다. 그럼 구체적인 예시를 코드로 한 번 살펴보겠습니다.
text
output:
['I go to my home my home is very large',
'I went out my home I go to the market',
'I bought a yellow lemon I go back to home']
저희의 데이터는 위와 같이 생겼습니다. 모두 15 종류의 단어가 사용되었는데요. 그러므로 feature값은 15가 할당이 됩니다.
vectorizer = TfidfVectorizer()
a = vectorizer.fit_transform(text).toarray()
a.shape
output:
(3, 15)
벡터의 shape를 출력해보면 (3, 15)가 나옵니다. 이 15라는 값이 feature에 해당하는 것입니다. 이해가 되셨죠?
이제 max_features 파라미터를 통해, 이 feature값을 10으로 제한해보겠습니다.
vectorizer = TfidfVectorizer(max_features = 10)
a = vectorizer.fit_transform(text).toarray()
a.shape
output:
(3, 10)
feature의 값을 10으로 제한하니, 벡터의 모양이 변했습니다. (3, 10)으로 shape가 바뀐 것을 확인하실 수 있을 겁니다.
해당 파라미터는 어느 상황에 사용하게 될까요? 자연어처리 데이터를 다루다보면, 엄청 긴 데이터를 만날 수 있습니다.
예를 들어서 다른 데이터의 단어들은 10정도를 가지는데, 어떤 데이터만 단어 종류가 100이 넘어간다고 하면, 이 100에 맞추어 feature의 수가 엄청 늘어나게 됩니다. 그럴 경우, 모델 성능이 저하될 수도 있는 것이죠.
그렇기 때문에 사전에 EDA를 통해서 데이터의 length를 확인하시는 것이 중요합니다. 그렇게 되면 통계적으로 엄청 정확한 기준은 아닐지라도, 대략 해당 파라미터의 스타트 지점을 유추해 볼 수 있을 것입니다.
7. 마무리
네 이렇게 오늘은 tf-idf의 중요한 파라미터 5가지에 대해서 알아보았습니다. 도움이 되셨다면 포스팅 하단에 하트 버튼 한 번씩 눌러주시는 것 잊지 마세요~!
안녕하세요. 은공지능 공작소의 파이찬입니다. 오늘은 Tensorflow estimator의 2가지 에러를 해결하는 포스팅을 준비했습니다.
1. TypeError: Fetch argument 0 has invalid type <class 'numpy.int64'> must be string or Tensor 2. TypeError: TF_SessionRun_wrapper: expected all value in input dict to be ndarray
자신의 코드와 데이터에 문제가 없는데, 자꾸 위의 에러가 뜨시는 분들은 계속 포스팅을 봐주시길 바랍니다. 우선 간단한 요약부터 시작하겠습니다.
1. 트러블 슈팅 요약
pip uninstall numpy # numpy 없다고 뜰 때까지 계속 반복해주세요.
pip install numpy # 저는 1.17버전이 깔렸으니, 참고해주세요.
pip install cython # 이 부분은 스킵해도 될 수 있는데, 저는 실행하였기에 남겨둡니다.
Tensorflow estimator에서 TypeError가 뜬 이유는 Numpy 라이브러리 때문이었습니다. 1.15 버전과 1.16 버전이 충돌해서 문제가 발생하는 것 같았습니다. 위의 코드처럼 numpy를 지웠다가 다시 깔아주면 문제는 해결됩니다.
만약 더 자세한 설명이 필요하신 분들은 계속 봐주세요.
2-1. 문제 상황 (에러 메시지)
위와 같이 2가지 에러메시지가 뜨는 상황입니다. 각각 다른 코드인데, 해결법은 동일합니다.
2-2. 모든 프로그램 창 닫아주기 (주피터, 파이참 등)
반드시 모든 프로그램(파이참, 주피터 등)을 닫아주시길 바랍니다. 안 그러면, 위와 같은 PermissionError 메시지가 뜹니다...
그래도 Numpy가 제거는 됩니다 ㅎㅎ 위의 사진은 주피터 노트북을 킨 상태에서 pip uninstall numpy를 날려줬을 때의 모습입니다. 마지막 줄에 numpy 1.16 버전이 제거가 되었다고 뜬 것을 확인하실 수 있을 겁니다.
그래도 여러분들은 저같은 시행착오를 방지하기 위해서, 꼭 모든 프로그램을 닫고 명령어를 날려주시길 바랍니다. 계속 진행해보겠습니다.
2-3. pip uninstall numpy 명령어 실행
(numpy가 없다고 뜰 때까지 계속 반복)
다시 모든 프로그램을 종료하고 돌아왔습니다. 그리고 pip uninstall numpy 명령어를 날려줍니다.
역시 제거할 numpy가 남아있었네요. 아까 분명 numpy 1.16 버전이 제거가 되었다고 된 상태였음에도, 1.15버전이 남아있습니다. y를 눌러서 제거를 해주시면 됩니다.
numpy가 깔끔하게 제거되었는지 알아보기 위해, 간단한 테스트를 진행해보겠습니다. 위의 화면처럼 우선 python을 실행시켜주시길 바랍니다. 그냥 python이라고 치시면 돼요 ㅎㅎ
파이썬이 실행이 되었다면, '>>>'이런 표시가 코드에 나타나게 됩니다. 이 상태에서 import numpy 명령어를 통해, numpy 라이브러리를 불러와줍니다.
No module named 'numpy'라고 뜬 부분이 보이시나요? numpy라는 라이브러리가 성공적으로 제거가 되었다는 뜻입니다.
2-4. pip install numpy 명령어 실행
pip install numpy 명령어를 날려서, 다시 numpy를 설치해줍니다. 마지막줄을 보니, numpy 1.17.1 버전이 설치가 되었군요.
하지만 빨간색줄로 에러가 상당히 많이 떠서... 좀 거슬립니다. 그래서 cython만 우선 설치해보고 테스트를 해보기로 했습니다.
cython이 성공적으로 설치가 된 모습입니다. 이 부분은 스킵을 해도 상관 없을 것 같긴 합니다. 하지만 저는 실행시켜준 부분이기에, 혹시 몰라 이렇게 알려드리는 겁니다.
3. 코딩 테스트
다시 코드를 돌려보니, 에러가 났던 것이 정상적으로 작동합니다. 이 에러를 가지고 거의 3일동안 씨름했거든요.. ㅜㅜ 감개무량합니다.
이렇게 오늘은 텐서플로우 에스티메이터 TypeError를 해결해보았습니다. 여름이 끝나가는데, 다들 여름휴가는 다녀오셨나요? ㅎㅎ 가끔은 머리도 식히고, 휴식도 필요하다는 것 잊지 마세요~!
안녕하세요! 은공지능 공작소 운영자 파이찬입니다. 오늘은 TF-IDF 벡터화에 대한 내용을 다루겠습니다. 자연어처리를 하다 보면 많이 등장하는 Feature extraction 기법입니다.
1. TF-IDF의 개념
TF-IDF의 풀네임은 Term Frequency - Inverse Document Frequency입니다. TF, IDF의 의미를 각각 이해하시면 정확한 의미 파악이 가능합니다. 자세한 내용은 위의 그림을 참조해 주세요.
그럼 이 TF-IDF가 어떻게 사용되고, 어떤 맥락에서 등장하게 되었는지 이해해보도록 하겠습니다.
TF-IDF는 일종의 특징 추출(Feature extraction) 기법입니다. 특징 추출이란, 말 그대로 raw data에서 특징을 뽑아내는 것을 의미합니다.
좀 추상적으로 들릴 수도 있는데요, 한마디로 정의하자면 '수치화'입니다. 텍스트 데이터를 컴퓨터가 그대로 인식할 수는 없습니다. 컴퓨터가 인식하려면 이를 숫자의 형태로 바꾸어 주어야 합니다.
이렇게 숫자의 형태로 바꾸어 주는 과정에서, 어떻게 하면 사람이 인지하듯이, 데이터의 특징을 잘 담을 수 있을지 고민하게 되고 여러 가지 특징 추출 기법이 등장하는 것입니다.
여러가지 특징 추출 기법 중 가장 기본적이 count 기반 특징 추출기법입니다. python scikit에서 CountVectorizer가 바로 이것입니다.
하지만 위의 그림에서 나오듯이, 이 CountVectorizer는 한계점이 존재합니다. 단어의 빈도수를 기반으로 하기 때문에, 조사, 관사 등의 의미 없는 단어에 높은 수치를 부여할 수 있다는 것입니다.
이러한 단점을 해결할 수 있는 것이 TF-IDF입니다. 일반적으로 TF-IDF가 CountVectorizer 보다 좋은 결과를 내놓는 것으로 알려져 있습니다.
이제 다시 한번 정확하게, TF, DF, IDF의 의미를 짚고 넘어가겠습니다. 위의 그림을 통해 의미를 이해하시면 됩니다.
+ 유튜브 동영상에는 설명이 빠진 것이 있어 보충합니다. TF-IDF에서 한 글자의 단어(Term)는 단어 사전에서 제외됩니다. 위의 문서들에 등장하는 단어 중 'I' 나 'a' 같은 단어에 이에 해당됩니다.
DF의 개념은 혼동될 수 있으니 조심하셔야 합니다. TF가 '단어'의 빈도를 나타내었다면, 'DF'는 문서의 빈도를 나타냅니다.
위의 그림에서 home은 전체 문서에서 총 4번 등장합니다. 그렇다고 해서 DF = 4로 잡으시면 안 된다는 말씀입니다.
비록 단어의 등장 횟수는 4번이지만, 해당 단어를 가진 문서는 총 3개이기 때문에 여기서 home의 DF는 3으로 잡는 것이 정확합니다. 이러한 점을 숙지하시고 넘어가시면 되겠습니다.
마지막으로 IDF의 개념을 잡고 넘어가겠습니다. IDF는 DF에 Inverse를 붙여준 것입니다. 수학에서 Inverse는 '역수'라는 의미를 가지고 있습니다.
역수는 분모와 분자를 뒤집는 것을 의미합니다. 예를 들어 3을 3/1이라고 표현하고, 분모와 분자를 뒤집는다면, 1/3이라고 할 수 있습니다. 이것이 역수의 개념입니다.
역수를 취해주면, 원래는 큰 값이 작은 값으로 확 줄어드는 효과를 낼 수 있습니다. 이러한 방식으로 많이 등장하는 단어에 패널티를 주기 때문에 DF에 Inverse를 붙여서 IDF라고 이름이 붙여졌습니다. IDF를 구하는 수식은 위의 그림을 참조해주시면 됩니다.
from sklearn.feature_extraction.text import TfidfVectorizer
text = ['I go to my home my home is very large', # Doc[0]
'I went out my home I go to the market', # Doc[1]
'I bought a yellow lemon I go back to home'] # Doc[2]
tfidf_vectorizer = TfidfVectorizer() # TF-IDF 객체선언
이제 본격적으로 코드 실습을 시작하겠습니다. 설명자료에서 쓰인 문장들을 그대로 가져왔습니다. 총 3개의 문서가 담긴 데이터입니다.
위와 같은 방식으로 불용어 사전을 업데이트할 수 있습니다. output을 보시면 마지막에 stopwords1, stopwords2가 업데이트된 것을 확인하실 수 있을 겁니다.
이렇게 stopwords를 업데이트해주는 것은 바로 wordcloud를 그려줄 때 옵션으로 적용할 수 있습니다.
이제 html 제거와 stopwords 업데이트를 모두 이해했으니, 이를 영화 데이터에 적용시켜 봅시다.
3. IMDb 데이터에서 html 태그 제거해주기
def data_engineering(input):
from bs4 import BeautifulSoup
rst = [] # rst는 result의 줄임말
for i in input:
# html 태그 제거
data = BeautifulSoup(i, 'html5lib').get_text() # 필터 적용
rst.append(data) # 결과를 rst리스트에 계속 추가
return rst
train_data_html_out = data_engineering(train_data['txt'])
html 태그를 제거하는 함수를 하나 만들어 주고, 이름은 data_engineering으로 붙였습니다. 그리고 이 함수를 통해 train_data의 txt 컬럼을 정제하였습니다. 정제된 결과는 train_data_html_out에 담았고, 결과는 아래와 같습니다.
영화 리뷰 데이터에서 <br>과 같은 html 태그가 깔끔하게 사라진 모습입니다.
4. Stopwords(불용어) 업데이트해주기
위의 워드클라우드는 저번 시간에 그린 워드 클라우드입니다. html 태그도 제거 안되어있고, 불용어 처리도 기본적인 것들로만 되어 있습니다.
여기서 제거해주고 싶은 단어를 3가지 정도 찾아보겠습니다. 큰 글자일수록, 해당 단어가 데이터에 자주 등장함을 의미합니다.
여기서는 'movie', 'film', 'one' 세 가지 단어를 제거해보겠습니다. 그러기 위해서는 위 3 단어로 불용어 사전을 업데이트해줘야 합니다.
위에서 보시는 것처럼 'one', 'movie', 'film'이라는 3 단어를 불용어에 추가한 후 이를 extend 함수를 통해 업데이트해주었습니다. 업데이트된 결과는 아래와 같습니다.
빨간 박스를 보면 3가지 불용어가 잘 추가된 것을 확인하실 수 있습니다.
5. 워드클라우드 그려보기
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
%matplotlib inline
wordcloud = WordCloud(stopwords = stopwords_pychan,
background_color = 'black', #배경색
width = 800,
height = 600).generate(' '.join(train_data_html_out))
plt.figure(figsize = (15, 10)) # 각각 가로 세로 인치 입니다.
plt.axis("off") # 축에 표시되는 눈금을 제거하는 옵션
plt.imshow(wordcloud) # 이미지가 표시되도록 하는 옵션.
plt.show() # 최종으로 보여주는 옵션.
html이 제거된 데이터를 가지고 워드 클라우드를 그려보았습니다. 여기서 stopwords 옵션에 주목해주시길 바랍니다.
stopwords_pychan이라고 해준 것을 사용했습니다. 이는 위에서 저희가 'one', 'movie', 'film' 3가지 불용어를 추가해준 것입니다. 불용어 처리를 했기에 앞으로 그릴 워드클라우드에서는 해당 단어들이 보이면 안 되겠지요.
나머지 코드들은 지난 시간에 다 설명드린 내용이므로 넘어가겠습니다. 바로 결과를 확인해보시죠.
br 태그를 포함해서 film, movie, one이 사라진 워드클라우드가 나온 것을 확인하실 수 있습니다.
그런데 이런 것들을 제거해줬더니, 이번엔 show나 character 같은 엉뚱한 단어들이 수면위로 올라왔습니다.
이런 결과는 워드클라우드를 그린다 해도 별로 의미가 없을 것 같습니다. 제가 생각했을 때, 좀 의미가 있으려면 지역 명칭이 나온다던지, 영화배우 이름이 나온다던지 이런 고유명사가 나와준다면 워드클라우드가 의미가 있을 것 같은데, 이렇게 나오는 것은 좀 더 손을 많이 봐야 할 것 같습니다.
그렇다면 긍정, 부정 단어들로만 워드 클라우드를 딱딱 그릴 수는 없을까 고민을 해보았습니다. 위에서 했던 것처럼 stopwords를 일일이 손으로 추가하다가는 엄청 시간이 많이 걸릴 것 같습니다.
이런 방법이 다른 모델에 적용이 될지도 의심스럽구요. (여기서 제거된 단어가 다른 자연어 워드클라우드에서는 의미를 가질 수도 있으니까요.)
다행히도 방법이 있었습니다. 바로 긍정 단어, 부정 단어만 모아놓은 일종의 리스트를 적용시키는 것인데요. 구글링 결과 깃허브에 누가 이러한 단어들을 정리를 해두었습니다. 이제부터 그것을 적용시켜서 각각 긍정 워드클라우드, 부정 워드클라우드를 그려볼까 합니다.
6. 긍정, 부정 단어 리스트 적용하여 워드 클라우드 그리기
위의 깃허브에 긍정단어, 부정단어가 정리된 텍스트 파일이 있습니다. 프로필을 보니, 인도 프로그래머 Shekhar Gulati라는 분이네요 ㅎㅎ (Thank you for your Git :)
사이트에 들어가시면 위와 같은 화면이 뜹니다. 초록 단추를 누른 후, 위와 같이 웹주소를 복사해 줍니다.
conda install git
이제 아나콘다 프롬프트를 실행시켜 줍니다. 그리고 git 라이브러리를 설치하지 않으신 분들은 위와 같이, git 라이브러리를 설치하는 명령어를 날려줍니다.
위와 같은 방식으로 전처리를 조금 해줍니다. 각각 \n으로 구분자를 명시해서 쪼개 주고(split) 35번째 인덱스부터 다시 변수에 담아주는 방식입니다.
\n을 구분자로 쓴 이유는, 해당 txt 파일이 줄바꿈(엔터)로 구분되어 있기 때문입니다. 또한 35번째 index부터 긍정/부정 단어가 나오기 때문에, 인덱스를 [35:]로 설정해, [1:34]의 설명 부분을 제외시켰습니다.
def data_cleaning(input, pos):
clean_word = [] # 리턴값을 담아줄 리스트 선언
for i in input: # i에는 여러 문장들이 담김.
for j in i.split(): # i를 단어별로 쪼개 j에 담음
if pos: # pos가 True라면 실행
if j in pos_word: # 단어를 하나씩 positive-word와 비교
clean_word.append(j)
else: # pos가 False라면 실행
if j in neg_word: # 단어를 하나씩 negative-words와 비교
clean_word.append(j)
return clean_word
이제 위와 같이 데이터에서 긍정, 부정단어들을 필터링 해주는 함수를 만들어줍니다. input 변수로 리뷰 데이터를 받아서 return값으로 긍정/부정 단어가 담긴 리스트를 출력해주는 방식입니다.
자세한 설명은 코드 주석으로 대신하겠습니다 ^^; 참고로 제 유튜브 영상을 보시면 어떻게 생각하면서 함수를 짜는지 세세하게 설명이 되어있습니다.