336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

저번주 토요일, 어제 갑작스런 코딩테스트 이메일을 받아서 계속 알고리즘 공부를 했다. 그래서 오랜만에 글을 쓰게 된다.

 

자소설에서 자소서를 148명이나 작성했으니 최소 2~3배를 뽑는다고 하면 많게 잡으면 450명 정도 쓴거 같은데 서류를 붙었다는게 신기했다. 자소설 대화방에서도 탈락했다는 사람이 거의 없는 걸 보니 코테를 보고나서 결정하는게 아닌가 싶었다.

 

자기소개서 내용도 솔직히 첫번째 말고는 차별화해서 쓸 게 없었다. 직무에서 NLP도 한다는 내용이 있어서 관심을 가지고 내용을 작성했다.

 

 

 

자기소개소 질문

 

- 회사와 직무를 선택한 이유는 무엇이며, 만약 입사하게된다면 어떻게 회사 발전에 기여할 수 있을지 기술해주시기 바랍니다.(700)

- 지원하신 직무와 관련된 역량을 키우기 위해 노력한 경험 및 결과에 대해 작성해주시기 바랍니다. (700, 최대 3개까지 작성 가능) (예시) [관련 경험 제목] 작성 후 ①역량을 키우기 위한 노력한 경험에 대한 내용과 기간을 작성 ②교내활동(강의/교내 프로젝트/논문/스터디/동아리/학회 등)과 교외활동(공모전/개인학습/프로젝트 등) 등으로 나누어 자유롭게 선택 가능

- CJ올리브네트웍스가 '취업준비생이 가장 가고싶은 회사 1위'가 되기 위해서 어떤 부분이 필요하다고 생각하는지 기술해주시기 바랍니다. (100)

 

 

 

 

과제 테스트 총 2문제 120분

 

CJ올리브네트웍스는 특이하게 인적성이 아닌 인성검사만 봤다. 적성까지 더했으면 아마 큰일 났을 듯... 그리고 프로그래머스로 처음 시험을 보다 보니 이거저거 세팅할 것이 많았다. 그랠도 친절하게 하는 안내서까지 보내주셔서 쉽게 따라할 수 있었다. 다른 곳에서는 코딩 테스트라고 하지만 CJ는 데이터 분석 과제라고 해서 2시간 동안 2문제를 푸는 것이었다. 

 

ML/AL 쪽은 검색을 안 하고 외워서까지 할 실력은 아닌데 처음에 멘붕이었다. 다른 사람들도 외워서 하기 힘들다고 얘기를 하고 있었는데 채용담당자님께서 메일 하나를 더 보내주셨다.

 

 

 

오픈북으로 시험을 본다는 것이다. 구글, 네이버에서 검색은 가능하지만, 절대 깃허브에 들어가면 안 된다는 내용이다. 문제 유형에 대해서 간단하게 언급을 하자면, 첫번째 문제는 데이터를 가지고 연산을 할 수 있으면 된다. 자주 다루셨던 분이라면 그래도 금방 하실 수 있을 것 같다. 저는 하나 헷갈리는 부분이 있어서 중간에 삥삥 돌아서 시간을 많이 뺏겼다.

 

두번째 문제는 여러 모델들을 사용해 예측을 해서 정확도를 높이면 됩니다. 오픈 카톡 인원 중에 상반기 때 시험을 보고, 하반기 때도 합격은 했는데 다른 회사랑 겹쳐서 힌트를 주셨다. 그래서 준비기간동안 캐글 데이터셋을 가지고 데이터 분석을 했다. 저는 시각화를 사용해서 데이터를 보고, 어떻게 하면 정확도를 높일 수 있을까 뻘짓을 하다가... 마지막에 데이터가 꼬여서 문제를 제대로 제출하지 못 했다 ㅠㅠ 우선 간단하게 해서 제출부터 하시는 것을 추천 드려요.

 

후기를 보면 정확도가 거의 비슷비슷했다. 그리고 거의 합격컷이 2솔이 아닐까 싶다. 처음 보는 코테라 어떻게 해야할지 몰라서 당황했다는 건 핑계고, 준비가 부족했던 것 같다. 신기하게 서류를 붙여주는 곳들이 있어서 다음에는 다른 코테 후기를 써보겠습니다.

 

 

 

 

 

 

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

지금 크롤링을 하고 있어서 시간이 나는 김에 글을 작성합니다. 크롤링도 크롤링이지만 이 데이터를 어떻게 정제할지가 더 고민이네요. 지난 번 글들을 활용해서 작성하오니 본인의 목적에 맞게끔 수정해서 사용하면 됩니다!

 

 

 

 

 

 

유튜브 크롤링(1) - 셀레니움 페이지 자동 번역, api 번역기 없이 가능! (키 입력, 마우스 입력)

유튜브로 새로운 수익모델을 찾기위한 채널 분석을 시도하고 있다. (기존 채널에 영상을 새로 올려야 하는데 요즘 못 올리고 있다 ㅠㅠ) 솔직히 노가다를 해도 되는데 파이썬을 배웠으면 자동화

0goodmorning.tistory.com

기능

- 특정 유튜브 채널에서 동영상 목록의 링크를 가져오기 (채널명, 구독자수)

- 제목, 조회수, 날짜, 좋아요 수, 싫어요 수, 댓글 개수

- 댓글 크롤링 (번역 기능 추가)

- 자동번역 자막 추출

 

 

 

 

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
32
33
34
35
from selenium import webdriver
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
 
options = webdriver.ChromeOptions() # 크롬 옵션 객체 생성
user_agent = "Mozilla/5.0 (Windows NT 4.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36 "
options.add_argument('user-agent=' + user_agent)
options.add_argument('headless'# headless 모드 설정
options.add_argument("window-size=1920x1080"# 화면크기(전체화면)
options.add_argument("disable-gpu"
options.add_argument("disable-infobars")
options.add_argument("--disable-extensions")
options.add_argument("--mute-audio"#mute
options.add_argument('--blink-settings=imagesEnabled=false'#브라우저에서 이미지 로딩을 하지 않습니다.
options.add_argument('incognito'#시크릿 모드의 브라우저가 실행됩니다.
options.add_argument("--start-maximized")
 
#1
prefs = {
  "translate_whitelists": {"en":"ko"},
  "translate":{"enabled":"true"}
}
options.add_experimental_option("prefs", prefs)
 
#2
prefs = {
  "translate_whitelists": {"your native language":"ko"},
  "translate":{"enabled":"True"}
}
options.add_experimental_option("prefs", prefs)
 
#3
options.add_experimental_option('prefs', {'intl.accept_languages''ko,ko_kr'})
cs

기본 셀레니움 webdriver 세팅입니다. prefs 기능은 영어를 번역할 때 필요한 기능이라서 끄셔도 상관 없습니다. 그리고 처음에 어떻게 돌아가는지 궁금하시면 # options.add_argument('headless') headless 기능을 꺼주세요.

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import os
import pandas as pd
import winsound
 
ytb = pd.read_csv('youtube_link.csv')
ytb_link = ytb.link.to_list()
 
for i in ytb_link :
    
    driver = webdriver.Chrome('chromedriver.exe', options= options)
    driver.get(i)
 
    # 스크롤 다운
    time.sleep(1.5)
   endkey = 4 # 90~120개 / 늘릴때 마다 30개
    while endkey:
        driver.find_element_by_tag_name('body').send_keys(Keys.END)
        time.sleep(0.3)
        endk -= 1
 
    channel_name = driver.find_element_by_xpath('//*[@id="text-container"]').text
    subscribe = driver.find_element_by_css_selector('#subscriber-count').text
    channel_name = re.sub('[=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…《\》]''', channel_name)
    # print(channel_name,subscribe)
 
    # bs4 실행    
    html = driver.page_source
    soup = BeautifulSoup(html, 'lxml')
 
    video_list0 = soup.find('div', {'id''contents'})
    video_list2 = video_list0.find_all('ytd-grid-video-renderer',{'class':'style-scope ytd-grid-renderer'})
 
    base_url = 'http://www.youtube.com'
    video_url = []
 
    # 반복문을 실행시켜 비디오의 주소를 video_url에 넣는다.
    for i in range(len(video_list2)):
        url = base_url+video_list2[i].find('a',{'id':'thumbnail'})['href']
        video_url.append(url)
 
    driver.quit()    
 
    if subscribe :
        channel = channel_name + ' - ' + subscribe
    else :
        channel = channel_name
        
    
    directory = f'data/{channel}/subtitle'
    if not os.path.exists(directory):
        os.makedirs(directory)
        
    print(channel, len(video_url))
    
    ytb_info(video_url, channel)
    print()
    winsound.PlaySound('sound.wav', winsound.SND_FILENAME)
cs

ytb_link : 본인이 수집하고자하는 채널을 리스트 형식으로 만들어주세요. 저는 csv 파일로 만들어서 컬럼 이름을 'link'로 하여 생성을 했습니다. 

 

channel : 채널 이름으로 폴더를 만들기 때문에, 폴더 이름에 들어가면 오류가 생기는 부호들을 미리 전처리 합니다. subtitle까지 만든 건 미리 자막 파일을 저장할 수 있는 폴더도 같이 만들어놨습니다.

 

# 한 채널이 끝날 때마다 윈도우 플레이사운드로 알려줍니다. 시끄럽다고 생각하시면 끄면 됩니다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
import time
 
last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
 
while True:
    driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
    time.sleep(0.5)
    
    if new_page_height == last_page_height:
        break
    last_page_height = new_page_height
    time.sleep(0.75)
cs

endkey : 본인이 수집하고자 하는 채널의 링크 개수를 결정합니다. 현재 설정으로는 90~120개를 수집합니다. time.sleep(2)으로 설정하시면 180개까지 크롤링을 합니다. endkey 개수를 늘리면 30개씩 추가가 됩니다. 에라 모르겠다하고 모든 링크를 크롤링하시려면 위에 코드를 입력해주세요.

 

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 정보만 크롤링하고 싶을 때
from bs4 import BeautifulSoup
import pyautogui
import pandas as pd
import re
 
def ytb_info2(video_url,channel) :
    print(f'{channel}',' 크롤링 시작')
    driver = webdriver.Chrome('C:/work/python/Asia_GAN/myproject/youtube/chromedriver.exe', options= options)
 
    #데이터 넣을 리스트
    date_list = []
    title_list = []
    view_list = []
    like_list = []
    dislike_list = []
    comment_list = []
    
    #각 채널별 영상으로 크롤링
    for i in range(len(video_url)):
        start_url = video_url[i]
        print(start_url, end= ' / ')
        driver.get(start_url)
        driver.implicitly_wait(1.5)
                
        body = driver.find_element_by_tag_name('body')
        
        #댓글 null 값 방지 
        num_of_pagedowns = 2
        while num_of_pagedowns:
            body.send_keys(Keys.PAGE_DOWN)
            time.sleep(0.5)
            num_of_pagedowns -= 1
            time.sleep(0.5)
        
        #크롤링 요소    
        try : 
            info = driver.find_element_by_css_selector('.style-scope ytd-video-primary-info-renderer').text.split('\n')
 
            if '인기 급상승 동영상' in info[0] :
                info.pop(0)
            elif '#' in info[0].split(' ')[0] :
                info.pop(0)
        
            title = info[0]
            divide = info[1].replace('조회수 ','').replace(',','').split('회')
            view = divide[0]
            date = divide[1].replace(' ','')
            like = info[2]
            dislike = info[3]    
            
            driver.implicitly_wait(1)  
                  
            try:
                comment = driver.find_element_by_css_selector('#count > yt-formatted-string > span:nth-child(2)').text.replace(',','')
            except:
                comment = '댓글x'
                
            #리스트에 추가
            title_list.append(title)
            view_list.append(view)
            date_list.append(date)
            like_list.append(like)
            dislike_list.append(dislike)
            comment_list.append(comment) 
            
            # 크롤링 정보 저장    
            new_data = {'date':date_list, 'title':title_list, 'view':view_list, 'comment': comment_list, 'like':like_list, 'dislike':dislike_list}
            df = pd.DataFrame(new_data)
            df.to_csv(f'data/{channel}/{channel}.csv', encoding='utf-8-sig')
        except :
            continue
        
        # 확인용
        print(title, view, date, like, dislike, comment)
   
    driver.quit()
cs

자막과 댓글이 필요 없을 경우

제목, 날짜, 조회수, 좋아요 수, 싫어요 수, 댓글 수만 크롤링을 합니다. 정보 양이 많지 않기 때문에 셀레니움만으로도 가능합니다. html_source를 bs4로 넘겼을 때와 비교해도 얼마 차이가 나지 않습니다.

 

# print(title, view, date, like, dislike, comment) 만약 어떤 정보가 나오는지 확인할 필요가 없으시면 비활성화해주세요. 

 

 

 

 

나는 댓글과 자막도 필요하신 분들은

밑으로

 

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from youtube_transcript_api import YouTubeTranscriptApi
from konlpy.tag import Kkma
from pykospacing import Spacing
 
def ytb_subtitle(start_url, title) :
    try:
        code = start_url.split('=')[1]
        srt = YouTubeTranscriptApi.get_transcript(f"{code}", languages=['ko']) #한글로, 딕셔너리 구조
 
        text = ''
 
        for i in range(len(srt)):
            text += srt[i]['text'+ ' '
            
        text_ = text.replace(' ','')
 
        #문장 분리 / kss 사용해도 무방
        kkma = Kkma()
 
        text_sentences = kkma.sentences(text_)
 
        #종결 단어
        lst = ['죠','다','요','시오''습니까','십니까','됩니까','옵니까','뭡니까',]
 
        df = pd.read_csv('not_verb.csv',encoding='utf-8')
        not_verb = df.stop.to_list()
 
        #단어 단위로 끊기
        text_all = ' '.join(text_sentences).split(' ')
 
        for n in range(len(text_all)) :
            i = text_all[n]
            if len(i) == 1 : #한글자일 경우 추가로 작업x
                continue
            
            else :
                for j in lst : #종결 단어
                    #질문형
                    if j in lst[4:]:
                        i += '?'
                    
                    #명령형                
                    elif j == '시오' :
                        i += '!'
                    
                    #마침표    
                    else :
                        if i in not_verb : #특정 단어 제외
                            continue
                        else :        
                            if j == i[len(i)-1] : #종결
                                    text_all[n] += '.'
                                    
 
        spacing = Spacing()
        text_all_in_one = ' '.join(text_all)
 
        text_split = spacing(text_all_in_one.replace(' ','')).split('.')
        text2one= []
        for t in text_split:
            text2one.append(t.lstrip())  
            
        w = '. '.join(text2one)
                        
        f = open(f'data/{channel}/subtitle/{title}.txt','w',encoding='utf-8')
        f.write(w)
        f.close()
        print('O')
    except:
        print('X')
cs
 

유튜브 크롤링(2) - ㄹㅇ 초간단 유튜브 자막 다운 & 추출 (문장분리까지)

유튜브 크롤링 글에 제목, 조회수, 댓글, 좋아요를 크롤링하는 방법에 대해서 글을 써야 하는데, 요즘 자소서를 쓰고 알고리즘 공부도 하고 이것저것 하다보니 글을 쓸 시간이 많지 않았다. 유튜

0goodmorning.tistory.com

유튜브 자막 추출 다운과 관련해서는 이전 글을 참고해주시면 좋을 것 같습니다. not_verb.csv 파일의 경우 '다', '요'로 끝나는 단어 중 동사가 아닌 명사, 형용사 단어를 stop 컬럼으로 추가하시면 됩니다.

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# 영어 번역 없음
import winsound as sd
from bs4 import BeautifulSoup
import pyautogui
import pandas as pd
import re
 
def beepsound():
    fr = 2000    # range : 37 ~ 32767
    du = 1000     # 1000 ms ==1second
    sd.Beep(fr, du) # winsound.Beep(frequency, duration)
 
def ytb_info(video_url,channel) :
    print(f'{channel}',' 크롤링 시작')
    driver = webdriver.Chrome('chromedriver.exe', options= options)
    # new_data = {'date': '', 'title': '', 'view': '', 'comment': '', 'like':'', 'dislike':''}
    
    count = 1
    
    #데이터 넣을 리스트
    date_list = []
    title_list = []
    view_list = []
    like_list = []
    dislike_list = []
    comment_list = []
    
    try:
        #각 채널별 영상으로 크롤링
        for i in range(len(video_url)):
            start_url = video_url[i]
            print(start_url, end= ' / ')
            driver.get(start_url)
            driver.implicitly_wait(1.5)
                    
            body = driver.find_element_by_tag_name('body')
            
            #댓글 null 값 방지 
            num_of_pagedowns = 1
            while num_of_pagedowns:
                body.send_keys(Keys.PAGE_DOWN)
                time.sleep(0.5)
                num_of_pagedowns -= 1
                driver.implicitly_wait(1)
            
            #크롤링 요소    
            try : 
                info = driver.find_element_by_css_selector('.style-scope ytd-video-primary-info-renderer').text.split('\n')
 
                if '인기 급상승 동영상' in info[0] :
                    info.pop(0)
                elif '#' in info[0].split(' ')[0] :
                    info.pop(0)
            
                title = info[0]
                divide = info[1].replace('조회수 ','').replace(',','').split('회')
                view = divide[0]
                date = divide[1].replace(' ','')
                like = info[2]
                dislike = info[3]    
                        
                try:
                    comment = driver.find_element_by_css_selector('#count > yt-formatted-string > span:nth-child(2)').text.replace(',','')
                except:
                    comment = '댓글x'
                    
                #리스트에 추가
                title_list.append(title)
                view_list.append(view)
                date_list.append(date)
                like_list.append(like)
                dislike_list.append(dislike)
                comment_list.append(comment) 
                
                # 크롤링 정보 저장    
                new_data = {'date':date_list, 'title':title_list, 'view':view_list, 'comment': comment_list, 'like':like_list, 'dislike':dislike_list}
                df = pd.DataFrame(new_data)
                df.to_csv(f'data/{channel}/-{channel}.csv', encoding='utf-8-sig')
 
            except :
                continue
 
            # print(title, view, date, like, dislike, comment)
            
            num_of_pagedowns = 1
            while num_of_pagedowns:
                body.send_keys(Keys.PAGE_DOWN)
                time.sleep(0.5)
                num_of_pagedowns -= 1
                
            #페이지 다운
            last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
 
            while True:
                driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
                # driver.implicitly_wait(2) #오류남
                time.sleep(0.5)
                new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
 
                if new_page_height == last_page_height:
                    break
                last_page_height = new_page_height
                # driver.implicitly_wait(1)
                time.sleep(0.75)
            
            time.sleep(0.5)
 
            
            # 댓글 크롤링
            html = driver.page_source
            soup = BeautifulSoup(html, 'lxml')
            
            users = soup.select("div#header-author > h3 > #author-text > span")
            comments = soup.select("yt-formatted-string#content-text")
            
            user_list=[]
            review_list=[]
 
            for i in range(len(users)):
                str_tmp = str(users[i].text)
                str_tmp = str_tmp.replace('\n''')
                str_tmp = str_tmp.replace('\t''')
                str_tmp = str_tmp.replace('              ','')
                str_tmp = str_tmp.replace('            ','')
                user_list.append(str_tmp)
 
                str_tmp = str(comments[i].text) 
                str_tmp = str_tmp.replace('\n''')
                str_tmp = str_tmp.replace('\t''')
                str_tmp = str_tmp.replace('            ''')
 
                review_list.append(str_tmp)        
 
            
            # 댓글 추가    
            pd_data = {"ID":user_list, "Comment":review_list}
            youtube_pd = pd.DataFrame(pd_data)
            
            title = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…《\》]''', title)
            youtube_pd.to_csv(f"data/{channel}/{title}.csv", encoding = 'utf-8-sig')#,index_col = False)
            print('ㅁ',end='')
 
            # 자막 추출
            ytb_subtitle(start_url, title)
            
            # 광고 끄기
            if count :
                # time.sleep(1)
                try:
                    driver.implicitly_wait(0.5)
                    driver.find_element_by_css_selector("#main > div > ytd-button-renderer").click()
                    count -=1
                except:
                    continue
 
    except :
        driver.quit()
        beepsound()
    driver.quit()
    beepsound()
cs

기본 정보 / 댓글 / 자막까지 

기본 정보 크롤링 밑으로 추가된 기능은 스크롤 다운 후, html page_source를 bs4로 넘겨서 댓글을 크롤링 합니다. 양이 많기 때문에 셀레니움보다 가볍고 빠른 bs4를 사용하시는 것을 추천드립니다.

 

댓글을 다 크롤링하고, 자막까지 받았을 때 영상 1개당 33초 정도 걸렸습니다. 컴퓨터, 인터넷 사양에 따라서 다를 거라 생각합니다. 한 채널이 끝날 때마다 소리가 나게 했습니다. 필요 없으면 꺼주세요!

 

 

 

 

*주의사항 *

유튜브 댓글은 기본적으로 인기 댓글순으로 정렬이 되어있기 때문에, 뒤에 있는 댓글일수록 공감을 적게 받거나 관심이 적은 댓글일 확률이 높습니다. 저는 모든 댓글이 필요하지 않기 때문에, 가장 크롤링이 빠르면서 댓글들 정보를 모을 수 있게 시간 설정을 했습니다. 댓글이 적으면 모든 댓글을 크롤링하지만, 많아지면 60~90% 정도만 크롤링을 하게 됩니다.

 

모든 댓글들이 필요하신 분들은, time.sleep을 1초 이상으로 해주세요. driver.implicitly_wait의 경우 스크롤은 내려가는데 댓글들이 로딩이 되지 않는 경우가 있어서 time.sleep을 사용했습니다. 

 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#영어 번역
import pyautogui
import pandas as pd
import re
 
def ytb_info(video_url,channel) :
    print(f'{channel}',' 크롤링 시작')
    driver = webdriver.Chrome('chromedriver.exe', options= options)
    df = pd.DataFrame()
 
    count = 1
    
    #각 채널별 영상으로 크롤링
    for i in range(len(video_url)):
        start_url = video_url[i]
        print(start_url, end= '/ ')
        driver.implicitly_wait(1)
        driver.get(start_url)
        
        #영어 번역
        pyautogui.hotkey('shift','F10')
        for i in range(7):
            pyautogui.hotkey('down')
        pyautogui.hotkey('enter')
        
        body = driver.find_element_by_tag_name('body')
        
        #댓글 null 값 방지 
        num_of_pagedowns = 1
        while num_of_pagedowns:
            body.send_keys(Keys.PAGE_DOWN)
            time.sleep(.75)
            num_of_pagedowns -= 1
            driver.implicitly_wait(1)
        
        #크롤링 요소    
        info = driver.find_element_by_css_selector('.style-scope ytd-video-primary-info-renderer').text.split('\n')
 
        if '인기 급상승 동영상' in info[0] :
            info.pop(0)
        elif '#' in info[0].split(' ')[0] :
            info.pop(0)
        
        title = info[0]
        divide = info[1].replace('조회수 ','').replace(',','').split('회')
        view = divide[0]
        date = divide[1].replace(' ','')
        like = info[2]
        dislike = info[3]    
                
        try:
            comment = driver.find_element_by_css_selector('#count > yt-formatted-string > span:nth-child(2)').text.replace(',','')
        except:
            comment = '댓글x'
   
        
        # 크롤링 정보 저장    
        new_data = {'date':date, 'title':title, 'view':view, 'comment': comment, 'like':like, 'dislike':dislike}
        df = df.append(new_data, ignore_index=True)
        df.to_csv(f'data/{channel}/{channel}.csv', encoding='utf-8-sig')
        # print(title, view, date, like, dislike, comment)
        
        #페이지 다운
        last_page_height = driver.execute_script("return document.documentElement.scrollHeight")
 
        while True:
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
            time.sleep(1)
            new_page_height = driver.execute_script("return document.documentElement.scrollHeight")
 
            if new_page_height == last_page_height:
                break
            last_page_height = new_page_height
            time.sleep(1)
        
        time.sleep(0.5)
        
        #댓글 크롤링
        review_list = []
        user_list =[]
        reviews = driver.find_elements_by_css_selector('#content-text')
        users = driver.find_elements_by_css_selector('h3.ytd-comment-renderer a span')
        num = 0
        for i in range(len(users)):
            review = reviews[i].text.replace('\n'' ')
            review_list.append(review)
            
            user = users[i].text
            user_list.append(user)
            
        # 댓글    
        pd_data = {"ID":user_list, "Comment":review_list}
        youtube_pd = pd.DataFrame(pd_data)
        
        title = re.sub('[-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…《\》]''', title)
        youtube_pd.to_csv(f"data/{channel}/{title}.csv", encoding = 'utf-8-sig')
        print('ㅁ',end='')
 
        # 자막 추출
        ytb_subtitle(start_url, title)
        
        # 광고 끄기
        if count :
            # time.sleep(1)
            try:
                driver.implicitly_wait(0.5)
                driver.find_element_by_css_selector("#main > div > ytd-button-renderer").click()
                count -=1
            except:
                continue
        
    driver.quit()
cs

해외 번역

단점 : headless으로 하면 안 된다. 마우스를 사용하지 못 한다. 시간이 진짜아아아아 엄처어어어엉 오래 걸린다. 굳이 이렇게 안 해도 될 거라고 생각이 드는데 혹시나 필요하신 분들을 위해서 남긴다.

 

가장 문제가 되는 부분이 번역을 한 정보는 bs4로 넘어가지 않는다. 셀레니움으로 모든 댓글과 닉네임들을 모아야 하기 때문에 시간이 오래 걸리는 것이다.

 

 

 

이 데이터들을 어떻게 사용할 것인지는 아직까지는 비밀.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

유튜브 크롤링 글에 제목, 조회수, 댓글, 좋아요를 크롤링하는 방법에 대해서 글을 써야 하는데, 요즘 자소서를 쓰고 알고리즘 공부도 하고 이것저것 하다보니 글을 쓸 시간이 많지 않았다. 유튜브 관리도 제대로 안 되고 있어서 돈만 날리고 있다 ㅠㅠ

 

 

 

유튜브 크롤링(3) 올인원 - 채널 제목, 댓글, 조회수, 자막까지

지금 크롤링을 하고 있어서 시간이 나는 김에 글을 작성합니다. 크롤링도 크롤링이지만 이 데이터를 어떻게 정제할지가 더 고민이네요. 지난 번 글들을 활용해서 작성하오니 본인의 목적에 맞

0goodmorning.tistory.com

다른 분들도 친절하게 크롤링 방법에 대해서 언급을 하고 있어서 일단 관련 글은 미루다가 작성(9.29 수정), 구글 검색을 해도 잘 나오지 않는 유튜브 자막 다운 방법에 대해서 쓰겠습니다. 검색을 했을 때 pytube3로도 다운이 가능하다고 되어있으나 2020년 글들이고 오류가 나서 사용을 하지 못 했습니다. 사용 방법을 아시면 알려주세요 :)

 

pip install youtube-transcript-api

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
from youtube_transcript_api import YouTubeTranscriptApi
# 오징어 게임 url https://www.youtube.com/watch?v=ysz5Sl3msyk
 
srt = YouTubeTranscriptApi.get_transcript("ysz5Sl3msyk", languages=['ko'])
 
with open("subtitles.txt""w", encoding='utf-8'as f:  
    for i in srt:
        # writing each element of srt on a new line
        f.write("{}\n".format(i))


# {'text': '저는...', 'start': 0.0, 'duration': 0.584} 이런 식으로 저장됨
cs

이걸로 srt 느낌의 자막을 다운로드 받을 수 있습니다. 쉽죠? 자막 다운이 급하신 분들을 위해서 먼저 설명을 드렸고, 딱 자막 부분만 필요하신 분들은 더 따라와 주세요. 오타나 인식이 잘못된 부분은 구글의 SST를 탓하세요! 

 

 

※ 야매 주의 ※

(야매가 싫으시면 뒤로가기 버튼을)

 

 

[사용]

pykospacing(맞춤법), kkma.sentence(kss도 가능!)

 

[시도]

kss(문장분리) / mecab, kkma, okt pos

 

[순서]

자막 다운 -> 띄어쓰기 제거, kkma.sentence -> 야매 문장 분리 -> 띄어쓰기 제거, spacing

-kss 시도를 해봤지만, 문장 부호가 없으면 시간이 많이 걸리고 모든 문장으로 안 나뉘어지는 단점 // 다시 해보니 0.3초 뭐지...

-spacing을 먼저 해봤으나 맞춤법 전문이라 제대로 안 나뉘어짐 ('~요' 인식이 잘 안 됨)

-꼬꼬마로 문장을 어느정도 나누고, 문장 부호를 추가하니 그나마 나아짐

 

 

 

1
2
3
4
5
6
7
from youtube_transcript_api import YouTubeTranscriptApi
# 오징어 게임 url https://www.youtube.com/watch?v=ysz5Sl3msyk
 
srt = YouTubeTranscriptApi.get_transcript("ysz5Sl3msyk", languages=['ko'])
 
for i in srt :
    print(i)
cs

어떤 식으로 자막이 이루어졌는지 확인을 해보기 전에, 영상이 자막을 지원하는 영상인지 아닌지부터 확인을 합니다. 자동생성 자막을 지원하지 않을 경우 에러가 납니다.

 

 

 

 

결과를 확인해보면 리스트 형식 안에 딕셔너리 형식이 있습니다. 우리는 'text'만 필요하기 때문에 딕셔너리에서 'text' 부분만 가져오면 됩니다. 

 

 

 

 

1
2
3
4
5
6
text = ''
 
for i in range(len(srt)):
    text += srt[i]['text'+ ' ' # text 부분만 가져옴
    
text_ = text.replace(' ','')
cs

간단하게 가져왔지만 문제가 하나 있습니다. 띄어쓰기가 제대로 되어 있지 않아서 잘 알아볼 수가 없습니다. 한국어 전처리 패키지인 PyKoSpacing을 바로 사용하려고 했으나, 문장 부호가 없어서 잘 되지 않습니다. 영어의 경우 친절하게 '.'을 찍어주는데 한국은 차별하는게 아닌가... 

 

kss 한국어 문장 분리기를 사용해보았으나 특정 어휘(EX : 처음)에서 이상하게 분리를 하고, 모든 문장을 나눠주지는 않았다. 글 쓰기 전에 kss를 사용하는데 상당한 시간이 걸려서 사용하지 않았는데, 글 쓰는 중에 다시 테스트를 하니 깔끔하게 잘 나뉘어서 당황스럽다. 그래서 Kkma.sentence()를 사용했던건데 어떤 것을 사용하든 상관은 없어보인다. 

 

그 후 종결어미인지 확인하기 위해서 mecab, kkma, okt를 사용해서 확인을 하려고 했으나 case를 나눌 것들이 너무 많아서 야매를 사용했다. kkma는 품사 분류표가 너무 복잡하고 pos로 나눌 때 명사가 포함되면 종결어미인지 분간이 잘 안 갔다. okt의 경우 품사 분류표가 간단하지만 (verb, noun 등..) 얘도 생각보다 case가 많았다.

 

 

 

 

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
32
33
34
35
36
37
38
39
from konlpy.tag import Kkma
import pandas as pd
 
#문장 분리 / kss 사용해도 무방
kkma = Kkma()
text_sentences = kkma.sentences(text_)
 
#종결 단어
lst = ['죠','다','요','시오''습니까','십니까','됩니까','옵니까','뭡니까',]
 
df = pd.read_csv('not_verb.csv',encoding='utf-8')
not_verb = df.stop.to_list()
 
#단어 단위로 끊기
text_all = ' '.join(text_sentences).split(' ')
 
for n in range(len(text_all)) :
    i = text_all[n]
    if len(i) == 1 : #한글자일 경우 추가로 작업x
        continue
    
    else :
        for j in lst : #종결 단어
            #질문형
            if j in lst[4:]:
                i += '?'
            
            #명령형                
            elif j == '시오' :
                i += '!'
            
            #마침표    
            else :
                if i in not_verb : #특정 단어 제외
                    continue
                else :        
                    if j == i[len(i)-1] : #종결
                            text_all[n] += '.'
                            print(text_all[n], end = '/ ')
cs

여기서부터 야매 방법이다.

 

종결형 단어를 뽑아서 lst로 만들었다. 구어체는 제외하고 뉴스기사를 여러개 찾아보면서 거의 웬만한 종결형 단어를 넣었다. 문제가 있으면 추가로 집어넣으면 된다. 그리고 문장을 모두 단어로 쪼개서 실행을 했다. 

 

처음에는 '죠, 다, 요'로만 구성하려고 했으나 질문, 감탄형 문장부호도 필요할 것 같아서 추가했다. 마지막 단어에 '다, 요'가 쓰인 경우, 무조건 종결형 어미가 아니라서 특정 단어를 제외했다. 바다, 날마다, 우간다, 노가다 / 필요, 수요, 중요, 노동요  ... 같은 단어를 찾아서 csv파일에 추가했다. 다로 끝나는 단어는 10만개가 넘어서 추후에 더 추가하면 될 듯 하다.

 

 

 

결과를 보면 나쁘지 않다. 걸러지는 걸 보여주면 효과가 더 좋아보일텐데 일단 변경되는 것만 보여드립니다. 그리고 나서 한국 전처리 기본 패키지인 pykospacing을 사용하게 되면 나름 괜찮게 결과가 나온다.

 

 

 

1
2
3
4
5
from pykospacing import Spacing
 
spacing = Spacing()
text_all_in_one = ' '.join(text_all)
print(spacing(text_all_in_one.replace(' ','')))
cs

단점은 마침표 다음에 띄어쓰기가 안 되어 있는 경우도 있어서. split으로 나누고 다시 붙이면 된다.

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

 

6-1 파이널 프로젝트 : 자연어처리, kogpt2를 이용한 슬로건 생성

목차 1. SKT-AI/KoGPT2와 자연처(NLP) 2. 데이터 전처리 (나무위키, 블로그) 3. KoGPT2와 기능구현 (인풋 아웃풋 조정) 4. 짧은 텍스트 / 문장유사도 5. 배포 (구글 애즈, GA, AWS) 모바일로 보니 너무 불편해서.

0goodmorning.tistory.com

분명 8월 중순 쯤에 임시저장한 글인데 파이널 프로젝트와 1일 1깃을 도전해본다고 글 쓰는 것이 느려졌다. ko-gpt2 관련된 글 유입이 늘기 시작하면서.. 구글에서도 노출될만한 글들을 추가로 쓰면 좋을 것 같아서 먼저 GPT-3 사용법과 설치 방법, 시크릿 키를 받는 방법을 간단하게 설명하고자 한다. (completion, classify text, search, answer questions 등이 가능하다.)

 

 

 

 

 

 

https://share.hsforms.com/1Lfc7WtPLRk2ppXhPjcYY-A4sk30

 

share.hsforms.com

GPT3가 처음에는 무료였다가 작년부터 유료가 돼서, 무료로 사용하려면 시크릿키부터 받아야 한다. 시크릿키는 위 링크를 타고 들어가면 되는데 간단한 인적사항을 입력하면 된다. 이게 사람마다 다른데, 짧게는 하루에서 길게는 몇 주까지 걸린다고 하니 추천 방법으로는 여러 메일을 통해서 신청을 하자. 그리고 모델 생성? 모델 불러오는 횟수도 1달에 10번정도로 제한되어 있으니 미리 여러 개로 신청을 해놓자. 

 

그리고 이번에 국립국어원에서 인공지능 능력평가를 한다는데, baseline model로 'ko-gpt-trinity-1.2B-v0.5'을 사용한다. 아직 베타버전인거 같은데 SKT에서 GPT-3 아키텍처를 복제하여 설계된 transformer model이라고 한다. 파이토치 모델.bin 파일만해도 4기가 넘는다... 어떻게 불러야할지 몰라서 일단 KoGPT3라고 하는데 아직 사용방법은 모르겠다.

 

 

 

 

 

OpenAI API

An API for accessing new AI models developed by OpenAI

beta.openai.com

OpenAI GPT3는 친절하지 않다. 가이드라인이 있긴 하지만 처음에는 헷갈린다. 그리고 중요한건 우리가 직접 조정할 수 있는 값들이 많지 않다. 결국 데이터를 잘 정제하고, 효율적으로 넣어야 좋은 결과값들이 나온다. 

 

 

 

 

 

 

WSL2(Windows Subsystem for Linux 2) 설치 및 사용 방법

지난 5월 윈도우10의 대규모 업데이트가 있었습니다. 이번 업데이트에는 WSL2 정식 릴리스가 포함되어있습니다. WSL은 경략 가상화 기술을 통해 윈도우에서 리눅스 배포판을 사용할 수 있게 도와

www.44bits.io

우선 파인튜닝을 위해서 우분투를 설치해준다. 링크를 따라가면 쉽게 설명을 해주고 있어서 대체한다.

 

 

 

 

설치를 했으면 windows PowerShell에 들어가서 Ubuntu를 실행한다. 우선 파이썬이 깔려있는지 보기 위해서 $ python3 --version을 확인한다. 파이썬이 없으면 파이썬을 설치한다. $ sudo apt-get upgrade python3 

 

 

 

 

$ pip install --upgrade openai 를 입력하여 openai를 설치한다.

$ export OPENAI_API_KEY="시크릿 키" 입력한다. 아무런 반응이 없는게 정상이다. 

 

 

 

 

이런 형식으로 jsonl 로 만들어주면 되는데, 인풋 데이터(prompt)와 아웃풋 데이터(completion)를 어떻게 할지 잘 정해야 한다. 그래야  나중에 결과값이 좋아진다 ㅠㅠㅠ

 

cd를 사용해서 jsonl을 만들어줄 파일이 있는 위치로 간다. 

$ openai tools fine_tunes.prepare_data -f 파일이름.확장자

 

 

 

 

그러면 창에서 파일을 분석해준다. 본인의 파일에 따라서 내용이 달라지니 어떤 항목을 Y로 할지 N로 할지 정해야 한다.

 

 

 

Based on the analysis we will perform the following actions:
- [Necessary] Your format `CSV` will be converted to `JSONL`
- [Recommended] Remove 4 duplicate rows [Y/n]: y
- [Recommended] Lowercase all your data in column/key `prompt` [Y/n]: y
- [Recommended] Add a suffix separator ` ->` to all prompts [Y/n]: n
- [Recommended] Add a suffix ending `\n` to all completions [Y/n]: n
- [Recommended] Add a whitespace character to the beginning of the completion [Y/n]: y

 

Your data will be written to a new JSONL file. Proceed [Y/n]: y

jsonl 파일이 완성이 됐다. 이제 파인튜닝을 할 차례다.

 

$ openai api fine_tunes.create -t "생성된 파일 이름.jsonl" -m curie

마지막 curie는 base_model인데 ada, babbage, curie가 있는데 curie가 성능이 더 좋다고 들었다.

 

 

 

openai api fine_tunes.follow -i <YOUR_FINE_TUNE_JOB_ID>

자신의 파인튜닝된 모델 이름이 표시가 된다. 잘 기억해야 한다. 나중에 jsonl 파일로 만들어진 모델인지 헷갈릴 수가 있다. 그리고 문제가 되는 부분은 본인의 시크릿키에서만 파인튜닝한 모델이 작동이 된다.

 

 

 

 

openai api completions.create -m curie:ft-user-본인의모델이름 -p 인풋데이터

이렇게 결과를 확인할 수 있다! 뭔가 결과가 잘 안 나왔는데 여러번 확인하면 더 좋은 결과가 나올 것으로 보인다.

 

 

 

 

gpt3.ipynb

Run, share, and edit Python notebooks

colab.research.google.com

 

https://colab.research.google.com/github/kes76963/myproject/blob/main/gpt3_edit.ipynb

계속 우분투에서 활용할 수 없기 때문에, 파인튜닝한 모델을 구글 코랩에서 사용하는 방법은 위 링크를 따라하면 된다. 생각보다 좋은 결과값은 안 나오는 것 같다. GPT3 활용 사례들을 보면 압도적인 결과물들이 나오는데, 더 괜찮은 모델을 써서 그런건지.. 아니면 gpt2랑 토크나이징 방식이나 훈련 방법이 달라서 그런건지.. 모델을 뜯어볼 수가 없어서 약간 답답한 느낌이다. 

 

마무리는 gpt3 사용방법을 알려주는데 도움을 준 분께서 만드신 동화이야기 영상입니다.

 

 

 

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

유튜브로 새로운 수익모델을 찾기위한 채널 분석을 시도하고 있다. (기존 채널에 영상을 새로 올려야 하는데 요즘 못 올리고 있다 ㅠㅠ) 솔직히 노가다를 해도 되는데 파이썬을 배웠으면 자동화를 하는게 맞지 않을까 싶고, 재밌는 실험들을 해보고 싶어서 코드를 짜고 있다.

 

셀레니움으로 페이지 자동 번역, 키 입력 정보가 필요하신 분들은 밑으로 내려주세요!

 

진행할 목록

- 페이지 성별 분석 (이름 데이터셋 수집 완료, CNN 카테고리 분류 완료, 검증 단계) => 얘 때문에 자동번역이 필요했음

- 페이지 연령 분석, 댓글 문체로 분류 도전 (자체 유튜브 조회수 100만 영상들에서 댓글 크롤링 후, 연령, 성비 분석 후 학습)

- 댓글로 영상 주제 분석 (긍정, 부정, 어떤 반응으로 영상이 화제가 됐는지 체크)

- 어그로 확인 (같은 주제, 같은 업로드 날짜 => 왜 다른 조회수? 썸네일, 키워드)

 

 

 

 

셀레니움 자동 번역 필요했던 이유?

연령대가 있는 층들은 대부분 유튜브 계정 닉네임이 본인 이름으로 되어 있어서 성별 분석하기가 조금 수월해 보였다. 하지만 영어로 이름을 입력하신 분들도 있어서 이걸 자동으로 번역해서 닉네임을 크롤링 해야 했다. 문제는 셀레니움으로 자동 번역이 잘 되지 않았다.

 

-파이썬에서 셀레니움 웹 사이트 언어 변경

-Translate the webpage opened via Selenium Webdriver to English

-Translate webpage language using Selenium

-Select an Option from the Right-Click Menu in Selenium Webdriver

-Modifying the language option in selenium

 

이렇게 다양하게 검색을 했는데도 문제가 잘 해결 되지 않았다. (구글이 PageRank를 활용한 알고리즘이라고 하는데 SEO 시스템을 잘 몰라서 외국에서 검색이 될지는 모르겠지만 그래도 찾아주시는 분들은 도움이 됐으면 좋겠다.) 일단 시도했던 것들에 대해서 간단하게 보여주자면

 

 

 

 

1
2
3
4
5
from selenium import webdriver
 
options = webdriver.ChromeOptions()
options.add_argument("--lang=ko_KR")
options.add_argument("--lang=ko")
cs

셀레니움에서 크롬옵션으로 기본 언어를 설정하면 된다고 하지만 내 경우는 되지 않았다. --lang=en 영어로도 안 된다는 사람들이 많았다. 그래서 계속 구글링을 시도했다.

 

 

 

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from selenium import webdriver
 
#1
prefs = {
  "translate_whitelists": {"en":"ko"},
  "translate":{"enabled":"true"}
}
options.add_experimental_option("prefs", prefs)
 
#2
prefs = {
  "translate_whitelists": {"your native language":"ko"},
  "translate":{"enabled":"True"}
}
options.add_experimental_option("prefs", prefs)
 
#3
options.add_experimental_option('prefs', {'intl.accept_languages''ko,ko_KR'})
 
cs

translate_whitelists에서 en -> ko로 바꿔주면 된다고 친절하게 설명이 되어있는데 이것 또한 되지 않았다. 그래서 영어권에서는 2번, 3번 방법의 경우를 추천했는데 이것 또한 되지 않았다^^ 

 

 

 

그래서 생각한 방법이 오른쪽 마우스로 번역하면 되겠거니 싶었다. 마우스 좌표 값을 설정해서 오른쪽 버튼을 클릭하기 번거로워서, 키보드로 마우스 오른쪽 버튼을 누르는 방법이 있나 찾아보니 shift + f10이라고 구글에서 친히 알려주신다. 그리고 Translate에 'T' 앞 글자를 따서 단축키를 만들지 않았을까 하고 T를 눌러보니 번역이 됐다!

 

그리고 send_keys(Keys.SHIFT + Keys.F10 + 't')를 해봤더니 t가 눌리지 않았다. 이런... 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
 
#1
body = driver.find_element_by_tag_name('body')
body.send_keys(Keys.SHIFT, 'a')
 
#2
action = webdriver.ActionChains(driver)
 
# 한번에 버튼 누르기
action.send_keys(Keys.SHIFT, Keys.F10, 't').perform()
 
# 키를 누르고 떼기
action.key_down(Keys.SHIFT).key_down(Keys.F10).send_keys("t").key_up(Keys.SHIFT).key_up(Keys.F10).perform()
cs

ctrl + f, shift + a 처럼 '페이지 내 검색어 찾기', '전체 선택'같이 셀레니움에서 번역이 아닌 단순 키 입력을 원하시는 분이라면 1번 방법을 사용하시면 됩니다. 이것도 안 돼서 더 찾아보니, ActionChains를 활용하면 된다고 해결책으로 제시했는데 이것도 되지 않았다. 

 

 

 

1
2
3
4
5
6
import pyautogui
 
pyautogui.hotkey('shift','F10')
for i in range(7):
    pyautogui.hotkey('down')
pyautogui.hotkey('enter')
cs

그래서 가장 원초적인 방법을 사용했다. 이전에 파이썬으로 계산기 들어가서 숫자 계산할 때 사용했던, 마우스 / 키보드 자동 조작 모듈을 사용했다. 

 

 

 

 

되긴 됐다. 자동으로 한국어 번역이...!

 

다만 단점이 있다면 headless로 작업이 되지 않다는 점과 pyautogui를 사용하기 때문에 초반에 다른 걸 만지면 안 된다. 좋게 생각하면 셀레니움으로 크롤링이 잘 작동되고 있구나를 확인한다고 생각하자.

 

다음은 유튜브 정보, 댓글 크롤링 방법들에 대한 포스팅을 진행하려고 한다. 요즘 유튜브가 지속적으로 페이지 UI랑, 아이콘 설정들을 조금씩 바꾸고 있어서 며칠 전 됐던 코드도 오류가 났다. 그래서 오늘 조금 수정을 했는데 글쓰는데 시간이 걸려서...

 

 

 

 

유튜브 크롤링(2) - ㄹㅇ 초간단 유튜브 자막 다운 & 추출 (문장분리까지)

유튜브 크롤링 글에 제목, 조회수, 댓글, 좋아요를 크롤링하는 방법에 대해서 글을 써야 하는데, 요즘 자소서를 쓰고 알고리즘 공부도 하고 이것저것 하다보니 글을 쓸 시간이 많지 않았다. 유튜

0goodmorning.tistory.com

 

유튜브 크롤링(3) 올인원 - 채널 제목, 댓글, 조회수, 자막까지

지금 크롤링을 하고 있어서 시간이 나는 김에 글을 작성합니다. 크롤링도 크롤링이지만 이 데이터를 어떻게 정제할지가 더 고민이네요. 지난 번 글들을 활용해서 작성하오니 본인의 목적에 맞

0goodmorning.tistory.com

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

목차

1. SKT-AI/KoGPT2와 자연처(NLP)

2. 데이터 전처리 (나무위키, 블로그)

3. KoGPT2와 기능구현 (인풋 아웃풋 조정)

4. 짧은 텍스트 / 문장유사도

5. 배포 (구글 애즈, GA, AWS)

 


드디어 파이널 프로젝트 글도 마무리 ㅠㅠㅠ 프로젝트 중 안 좋은 일이 있어서 서비스 배포 기간에 참석을 하지 못 했다. 원래는 GPT3를 활용하여 기업 설명을 완성시켜주는 서비스도 만드려고 했으나 불가능했고, 프로젝트 이후에나 GPT3를 다뤄봐야겠다고 생각했다.

 

 

 

서비스 이름도 조금 더 찰떡 같은 이름을 지으려고 했으나 막상 지어보니 별로라서 그냥 그대로 유지했다. copylight (카피의 한 줄기 빛이 되다.) copyfast (카피를 빠르게! - 근데 패스트 발음을 하면 전염병 의미가 있어서 패스), copydai (ai로 카피 만들기 좋은 날 카피데이) 등등 ..

 

예전에 카피라이팅에 도전을 많이 했었는데 아무리 생각해도 언어유희나 임팩트 있는 문구를 창작하는 건 재능이지 않을까 싶다. 노력으로는 되지 않아서 우리가 만든 것이 인공지능 카피라이팅이 아닐까? 

 

 

 

Django를 이용해 웹 구현을 했고, 나는 디자인 부분에서 조금 도움을 줄 수 있었다. 원래는 로딩창 부분에서 Tip이나 튜토리얼 부분을 gif로 만들어서 심심하지 않게 하려고 했다. 하지만 장고 개발하던 팀원이 좀 무리지 않냐고 해서 수용했다.

 

 

 

 

 

 

 

추가적으로 장고로 로컬을 이용한 연결이 끝이 아닌, AWS를 통해 인스턴스를 생성하여 우분투 서버를 사용하여 웹 서비스를 배포했다. 파파고로 한국어를 영어로 자동 번역하는 서비스도 있었는데 여기서 API 키를 그대로 노출시면 안 되다고 해서.. 중간에 과정이 많이 있던 걸로 기억한다. 

 

그리고 aws에서 얻은 탄력적 ip주소를 사용하여 접속하는 것 보다 도메인 주소를 지정하여, 서비스 내용을 알 수 있게끔 가비아 사이트를 이용해 도메인을 연결하였다. 나중에 서비스 이름을 바꿀 수도 있어서 간단하게 990원짜리를 이용하였다.

 

 

 

예전에 유튜브를 보면서 이 부분은 꼭 해봐야겠다 생각이 들어서, GA와 구글 애즈를 사용해야 된다고 강력하게 주장했다. 이유를 설명하자면 국비지원 교육의 단점에 대해서도 잠깐 얘기를 해야하는데.. (검색을 하고 우연히 들어오시는 분들을 위해서 적어두겠습니다.)

 

- SSAFY처럼 커리큘럼이 체계적이지 않고, 생각보다 몇몇 강사분들은 전문적이지 않다. 

- 포트폴리오용 토이프로젝트를 많이 진행하는데 이걸로는 메리트가 없어보인다. 본인이 해야한다. 공부든 뭐든 원래 그렇듯이

(학부생이나 관련 개발자들은 최소 몇 개월에 걸쳐서 프로젝트를 진행할텐데, 고작 일주일의 프로젝트로 뭐를 했다고 할 수 있을까?)

 

위 유튜버의 말대로, 남들 다 하는 토이프로젝트에서 남들과는 차별점을 둘 수 있는 것이 배포를 해보고, 유저의 피드백이나 오류들을 개선하는 과정이지 않을까 싶다. 그리고 유저의 피드백을 받기 위해서 구글 애즈로 현업자들 상대로 광고를 집행해 노출도 시키고, 직접적인 피드백 받기가 어려우면 GA로 어떤 페이지에서 오래 머물렀고, 이탈이 있었는지 등을 분석하면 좋을거라 생각했다.

 

 

 

 

광고 캠페인 집행 : 유튜브와 구글에서 검색을 통해서 금방 제작이 가능했다. 물론 효율적인 광고를 위해서는 세부적으로 다뤄야할 부분들이 많았다. 처음 광고를 해봐서 그런지 약간 돈만 날린 부분도 있었고, 다른 광고 캠페인들처럼 전환이 이뤄졌다할만한 결과가 없기 때문에 성과 측정은 어려웠다.

 

 

 

 

 

구글애널리틱스 자격증은 혹시나 필요할까봐 따긴 땄는데, 직접 이런 식으로 통계를 본 적은 처음이다. 물론 유튜브로 구독자 분석, 채널 분석을 많이 하긴 했지만 그거와는 조금 다른 분야였다. GA 코드는 <head> 태그 바로 뒤에 복붙하면 됩니다. 이것도 GA 자격증을 따기 위해서 나오는 문제중 하나입니다. ㅋㅋㅋ

 

원래는 사이트 주소를 오픈하면 좋은데, 현재 서버에 문제가 좀 있어서 수정중이라고 들었습니다. 

 

앞으로 할 부분은 자연어 공부를 조금 더 하면서 유튜브 채널, 구독자 분석을 진행하려고 합니다. 감사합니다.

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

목차

1. SKT-AI/KoGPT2와 자연처(NLP)

2. 데이터 전처리 (나무위키, 블로그)

3. KoGPT2와 기능구현 (인풋 아웃풋 조정)

4. 짧은 텍스트 / 문장유사도

5. 배포 (구글 애즈, GA, AWS)

 


KoGPT2로 슬로건, 광고문구를 생성하고 이를 어떻게 개선할 것인가에 대해서 이어서 작성하겠습니다. 처음에 포스팅 하나에 넣으려고 했는데 생각보다 길어져서 나눴습니다. 이번 포스팅은 아웃풋과 인풋을 어떻게 조정했는지에 대해서 쓰겠습니다.

 

 

 짧은 텍스트 / 문장 유사도 찾기 

사용 이유 와 목적 : 인풋 데이터에 '금융'과 관련된 설명을 넣었는데, 갑자기 '좋은 일자리 만들어주세요'라는 문구가 뜬금없이 튀어나오게 된다. 데이터가 충분하면 이런 일이 없겠지만 추가로 모을 수는 없어서.. 이러한 결과값들을 최대한 배제하는 방법에 대해서 생각했다. 

 

- TF-IDF, CNN을 활용을 활용한 슬로건 분류

- Word2Vec을 사용해서 자주 등장하는 단어와 유사한 값을 지닌 단어가 포함된 문장을 노출

- 문장 유사도 (키워드, 요약, sentence transformer)

 

 

 

 

4-3 파이썬 팀프로젝트 CNN 카테고리 분류 모델 학습 및 평가

네 번째 프로젝트 1. 간단한 intro 2. 웹 크롤링 및 전처리 3. 모델 학습 및 평가 프로젝트를 하면서 느낀 보완사항은 : -데이터의 길이가 너무 짧으면 단어를 추출하는데 한계가 있고, 과적합이 발

0goodmorning.tistory.com

TF-IDF, CNN 카테고리 분류

슬로건, 광고문구에 인풋 값과 관련 없는 결과가 나올 확률은 크지 않기 때문에(이후에 보여드립니다), 카테고리(y)와 슬로건(x)을 학습시켜서 모델링을 해봤다.(이전 코드 참고)

 

하지만 아무리 수정을 해도 CNN 모델의 성능은 좋아지지 않았다. 40% 정확도가 최선으로 나왔는데, 이를 생각해보면 카테고리와 슬로건의 상관관계가 거의 않아서 정확도 개선이 되지 않는 것으로 보인다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from konlpy.tag import Kkma
import collections 
 
slogan_list2 = []
for slogan in slogan_list :
    kkma = Kkma()
    slogan_ = kkma.nouns(slogan)
    slogan_list2.append(slogan_)
 
#중첩 리스트 제거
list_removed = sum(slogan_list2, []) 
 
#단어 카운팅
dict={} 
dict=collections.Counter(list_removed) 
dict = sorted(dict.items(), key=lambda x: x[1], reverse=True)
#print(dict)
 
#가장 많이 나오는 
keyword = next(iter(dict))[0#사전 첫번째 단어
print(keyword)
cs

꼬꼬마로 형태소 분류를 해서 가장 자주 나오는 명사들의 개수를 카운팅하고, 단어 : 개수를 딕셔너리로 만든다.

 

 

 

1
2
3
4
5
6
7
from gensim.models import Word2Vec
 
model = Word2Vec(slogan_list2, vector_size=100, window=4,
                           min_count=2, workers=4, epochs=50, sg=1
 
#가장 많이 나오는 단어와 유사한 단어
model.wv.most_similar(keyword,topn=10)
cs

결과값을 확인 했을 때, 나쁘지 않게 나왔지만.. 이 단어들로이 포함되지 않는 문구를 필터링한다면, 걸러져야할 광고문구보다 괜찮은 광고문구들도 대부분 걸러질 것으로 보여서 다른 방법을 또 고민했다.

 

텍스트 유사도를 구할 때, 추천 시스템에서 사용했던 TF-IDF, 코사인 유사도를 사용하려고 했다. 하지만 파이널 프로젝트에는 적용하기 힘들었던 이유가 비교할 문장이 길지 않고, 한 문장으로 이루어졌기 때문이다. 프로젝트가 끝나고 현재 Textrank나 문장 요약, 키워드 추출 등을 공부하고 있는데, 이 방법도 적합하지 않은 방법이었다.

 

 

 

그래서 찾게 된 것이 Sentence Transformer다. 그런데 생각보다 구글에는 예시가 많지 않았다. 영어 모델은 유사도 높게 나왔는데, 한글의 경우 위의 사진처럼 '한 남자가'라는 단어가 일치한다고 유사도 94퍼센트가 나오는 아이러니한 현상이 발견됐다. 구글링을 더 하다가 Ko-Sentence-BERT-SKTBERT 모델이 나왔는데 오류 때문에 잘 되지 않았다.

 

 

 

 

 

Pretrained Models — Sentence-Transformers documentation

We provide various pre-trained models. Using these models is easy: Multi-Lingual Models The following models generate aligned vector spaces, i.e., similar inputs in different languages are mapped close in vector space. You do not need to specify the input

www.sbert.net

더 검색하다가 발견한 모델! 유사도가 SKTBERT에서 테스트한 예제들과 결과가 비슷하게 나와서 사용하기로 했다.

 

 

 

 

결과가 좋다! 그리고 예상했던대로 인풋데이터와 관련이 없는 결과(슬로건, 광고문구)는 다른 문구들과 비교했을 때 전체적으로 유사도가 높지 않음을 확인할 수 있다. / RPG 게임에 웬 패션 스타일인가?

 

하지만 여기서도 또 문제 아닌 문제가 생겼다. 필터링 되는 슬로건 중에서도 키워드만 바꾸면 괜찮아보이는 슬로건들이 있다. 그래서 이걸 살리는 것도 좋지 않겠냐는 멘토님의 말씀이 있어서.. 사용자가 직접 민감도를 설정해 필터링의 할 수 있는 기능을 추가했다. 

 

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#문장 유사도
#개별 추출
from sentence_transformers import SentenceTransformer, util
import numpy as np
import random
import pandas as pd
 
#모델 불러오기
model = SentenceTransformer('distiluse-base-multilingual-cased-v1')
 
#회사 리스트
company = pd.read_csv('datasets\company_list.csv')
company_list = company.company.values.tolist() #회사명을 리스트로
 
#비교할 슬로건 선택 
no_sim_list = [] #관련 없는 슬로건 추출
total_slogan = [] #슬로건 전체를 담는 리스트 / 중첩리스트용
= 0
try : #n이 증가하지 않을 경우 무한루프? 
    while n < 5 :
        #유사도 비교할 리스트
        corpus = kor_list
        corpus_embeddings = model.encode(corpus, convert_to_tensor=True)
        
        #유사도 비교할 문장
        query = random.sample(kor_list, 1)
        print("Query : ", query)
        
        #코사인 유사도 사용하여 5개 유사한 슬로건 찾기
        top_k = 6 #query 포함 top 5개
        query_embedding = model.encode(query, convert_to_tensor=True)
        cos_scores = util.pytorch_cos_sim(query_embedding, corpus_embeddings)[0]
        cos_scores = cos_scores.cpu()
        top_results = np.argpartition(-cos_scores, range(top_k))[0:top_k] # np 사용 이유 : 순위를 순서대로 맞추기 위함
        
        #민감도 비교하기 위한 유사도 더하기      
        sum = 0
        for idx in top_results[1:top_k]:
            sum += cos_scores[idx]
        f_sum = float(sum)/5 #tensor to float
        print(f_sum)
        
        #사용자 인풋 민감도 비교    
        sim_list = [] #유사 슬로건 담을 리스트
        sim_list2 = [] #수정된 슬로건 담을 리스트
        if f_sum >= input_sim / 100 :
            for idx in top_results[0:top_k-1]:
                copy_ = corpus[idx].strip()
                sim_list.append(copy_)
            
            print(sim_list)
            sim_list2 = sim_list    
            for i in range(len(sim_list2)) :
                for c in company_list :
                    if c in sim_list2[i] :
                        sim_list2[i] = sim_list2[i].replace(c,'*'*len(c))
       
            total_slogan.append(sim_list2)
            kor_list = differ_sets(kor_list, sim_list)
            n += 1
            #print(len(kor_list))
            
        else : 
            no_sim_list.append(query)
            kor_list = differ_sets(kor_list, query)  #kor_list에서 query를 제거 
            print('관련이 없는 슬로건 데이터 추가'
  
                
                
except :
    print('데이터가 부족합니다.')
    
print('완료')
#print(no_sim_list)
 
print(total_slogan)
cs

우선 슬로건 문구를 포함한 리스트에서 영어로만 이뤄진 슬로건을 제외해 kor_list를 만들었다. 영어가 포함된 문장의 경우 유사도가 얼추 비슷하게 나왔는데, 영어로만 이루어진 문장은 문장 유사도 성능이 떨어져서 아예 제외시켰다. 이후 한 개를 랜덤으로 뽑아서 유사도가 비슷한 값 5개를 뽑아서 평균을 냈을 때, input_sim과 크기를 비교해서 살릴지 버릴지 고민을 했다.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#차집합 함수
def differ_sets(a,b) : 
    lst = list(set(a)-set(b))
    return lst
    
 
#영어 슬로건 따로 추출
import re
 
eng_list = []
for slogan in slogan_list :
    slogan_ = re.sub('[^A-Za-z가-힣]''',slogan) #영어 한글만 남기기
    slogan_ = re.sub('[^가-힣]',' ', slogan_) #영어는 공백으로 남긴다
    if slogan_.isspace():    #isalpha()는 영어 또는 한글 유무를 찾아서 안 됨
        eng_list.append(slogan)
        
print(eng_list)
 
#차집합 
kor_list = differ_sets(slogan_list, eng_list) #한국 슬로건만 있는 리스트
cs

영어로만 이루어진 문장을 뽑는데 애를 먹었다. isalpha()를 사용하게 되면 영어로만 이루어진게 아니라, 한글이 있을 때도 True를 반환하기 때문에 다른 방법을 사용해야했다. 우선 공백을 없애고, 한글만을 남게한다. 만약 영어로만 이루어졌으면 isspace()함수에서 True를 반환하기 때문에 영어만 포함된 문장을 뽑을 수 있다. 반대로 한글로만 이뤄진 문장이 필요하면 '^가-힣' 대신 '^A-Za-z'을 활용하면 된다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
company_list = company.company.values.tolist()
len(company_list)
 
for c in company_list :
    for i in range(len(total_slogan) :
           if c in total_slogan[i] :
            # print(c)
            slogan_edit = total_slogan[i].replace(c,'*'*len(c))
            # print('수정')
 
slogan_edit
cs
기업, 제품, 서비스 광고문구를 크롤링했기 때문에, 슬로건 자체에 회사명, 제품, 서비스가 들어가는 경우가 있다. 그래서 이를 별표처리를 해줬다. 여기서 문제가 끝난 줄 알았는데.... 아웃풋뿐만 아니라 인풋 데이터도 조정해야 했다. 토크나이징을 할 때 문제가 있었다. 우리는 손크롤링을 할 때 회사 설명에 주로 명사 위주의 키워드를 넣었는데, 토크나이징을 할 때 띄어쓰기 유무에 따라서 결과값이 많이 달라졌다.
 
 
예를 들어 '패션의류'의 경우, 우리는 '패션 의류'를 설명에 입력했는데 토크나이저가 패션(명사) 의(조사) 류(명사) 이런 식으로 인식하기도 하고 제각각 달랐다. 그래서 명사 띄어쓰기 필요성이 느껴져서 형태소 분류를 진행했다. mecab, okt, kkma를 사용해봤는데 전체적인 성능은 mecab이 좋았으나, 명사 추출은 kkma가 조금 더 딱딱하게 잘 끊어냈다.

 

 
 
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
"""
** 가이드 **
-input_sim
0~15 : 가장 자유로움 
15~30 : 자유로움
30~45 : 조금씩 걸러짐
45~60 : 많이 걸러짐   / 강제로 기업 설명을 인식시켜서 더 제한적인 슬로건
60~ : 거의 다 걸러짐  / 슬로건 100개를 했을 경우 유사율 평균 70 이상은 거의 없음
 
-input_text
최대한 명사 위주의 설명
영어를 쓸경우 뒤에 나오는 단어와 붙여쓰면 더 좋은 결과 ex) 'LED 마스크'보다는 'LED마스크' 
"""
 
input_sim = 40  # input data 유사성 민감도 지정 / 숫자가 작을수록 관련 없는게 나올 확률이 커짐 / 최소 50이상 설정
input_text = '커피전문기업'
input_text_list = input_text.split(' '# input data 띄어쓰기로 나누기
eng_text = re.sub('[^a-zA-z]',' ',input_text).strip()
 
kkma = Kkma() #꼬마를 작용시 분모가 중복 되는 경우가 생김, 이를 제거해야 함
copy=[]
for txt in input_text_list :
    txt_ = kkma.nouns(txt)
    # print(txt_)
 
    if len(txt_) > 1 : #(명사가 쪼개졌을 경우)
        max_string = max(txt_, key=len#가장 긴 값을 제거 (중복값)
        txt_.remove(max_string)    
    
    copy += txt_
# print(copy)
 
if len(copy) >3 : 
    del_list = []
    for i in range(math.ceil(len(copy)-2)) : 
        overlap_txt = ''.join((itemgetter(i,i+2)(copy))) # abc를 kkma로 쪼갤 경우 =>  a, ab, abc, b, c => abc 제거 => ab를 제거하는 과정 
        if overlap_txt in copy :
            del_list.append(overlap_txt) 
    #print(del_list)
    [i for i in del_list if not i in copy or copy.remove(i)] #차집합인데 순서가 안 바뀜 
text = ' '.join(copy)
 
if input_sim > 45 :
    text += ',' #,를 넣을 경우 강제로 기업설명으로 인식시켜서 조금 더 제한적인 슬로건 등장 
 
#영어 슬로건이 포함 된 경우 초기상태로
if eng_text :
    if eng_text in input_text :
        text = input_text
    
print(text)
cs
이번에도 산 넘어 산이었다. kkma가 딱딱하게 명사를 잘 끊어내는 것과 달리, 만약 합성어가 ab이면 우리는 a와 b 결과만 나오면 되는데 a, ab, b로 쪼개지면서 다시 ab값이 등장해서 문제가 됐다. 그래서 단어 길이가 최대인 값을 지우면 되겠거니 했는데.... abc의 경우 a, ab, abc, b, c로 쪼개져서 abc 뿐만 아니라 ab를 지워야했다. 이를 어떻게 해야할까 하다가 저 코드가 나오게 됐다. 리스트끼리 뺐을 때도 리스트 순서는 바뀌지 않으면서 리스트를 유지하는 법도 배웠다.
 
또 영어도 한글과 붙어 있으면 값이 다르게 나왔는데, 이게 gpt2가 현재 단어 다음에 나올 단어의 확률을 예측하는 방식으로 학습했기 때문에 ㅠㅠ 붙여쓰는 것과 띄어쓰기를 하는 것은 결과가 달랐다. 원래 이것도 하나하나 코드를 짜려다가 조금 더 사용자에게 자율성을 주자고 조교님이 그러셔서 영어가 포함이 되면 인풋 데이터 그대로 모델에 입력이 됐다.
 
아직도 공부할 부분은 많은 것 같다..
 

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

목차

1. SKT-AI/KoGPT2와 자연처(NLP)

2. 데이터 전처리 (나무위키, 블로그)

3. KoGPT2와 기능구현 (인풋 아웃풋 조정)

4. 짧은 텍스트 / 문장유사도

5. 배포 (구글 애즈, GA, AWS)

 


KoGPT2 학습방식 개요 - 저는 주로 ver.1을 다루고 다른 팀원이 ver.2를 다뤘다. '기업설명, 슬로건'으로 이루어진 문장이 여럿 들어가는 거와 기업설명, 슬로건을 나눠서 학습시키는 것과 차이가 커보이지는 않는데 ver.2의 경우 성능이 좋지 않았다. 아마 코드가 영어슬로건 생성에 맞춰진 거라서 그렇지 않을까 싶다.

 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from transformers import TextDataset, DataCollatorForLanguageModeling
from transformers import GPT2LMHeadModel
from transformers import Trainer, TrainingArguments
from transformers import PreTrainedTokenizerFast
 
 
def load_dataset(file_path, tokenizer, block_size = 128):
    dataset = TextDataset(
        tokenizer = tokenizer,
        file_path = file_path,
        block_size = block_size,
    )
    return dataset
 
 
def load_data_collator(tokenizer, mlm = False):
    data_collator = DataCollatorForLanguageModeling(
        tokenizer=tokenizer, 
        mlm=mlm,
    )
    return data_collator
 
def train(train_file_path,model_name,
          output_dir,
          overwrite_output_dir,
          per_device_train_batch_size,
          num_train_epochs,
          save_steps):
  tokenizer = PreTrainedTokenizerFast.from_pretrained(model_name,
                bos_token='</s>', eos_token='</s>', unk_token='<unk>',
                pad_token='<pad>', mask_token='<mask>')
  train_dataset = load_dataset(train_file_path, tokenizer)
  data_collator = load_data_collator(tokenizer)
 
  tokenizer.save_pretrained(output_dir, legacy_format=False)
   
  model = GPT2LMHeadModel.from_pretrained(model_name)
 
  model.save_pretrained(output_dir)
 
  training_args = TrainingArguments(
          output_dir=output_dir,
          overwrite_output_dir=overwrite_output_dir,
          per_device_train_batch_size=per_device_train_batch_size,
          num_train_epochs=num_train_epochs,
      )
 
  trainer = Trainer(
          model=model,
          args=training_args,
          data_collator=data_collator,
          train_dataset=train_dataset,
  )
      
  trainer.train()
  trainer.save_model()
 
train_file_path = './datasets/slogans.txt'
model_name = 'skt/kogpt2-base-v2'
output_dir = './models2'
overwrite_output_dir = False
per_device_train_batch_size = 8
num_train_epochs = 5.0
save_steps = 500
 
train(
    train_file_path=train_file_path,
    model_name=model_name,
    output_dir=output_dir,
    overwrite_output_dir=overwrite_output_dir,
    per_device_train_batch_size=per_device_train_batch_size,
    num_train_epochs=num_train_epochs,
    save_steps=save_steps
)
cs

gpt2 모델 중에서 pytorch로 학습을 시킨 경우가 많았는데, 생각보다 복잡하고 배우지를 않아서 사용하지 못 했다. skt/kopgt2 토크나이저를 사용하였고, skt/kogpt2-base-v2 모델을 사용하여 학습을 진행했다. 생각보다 학습 코드 자체에는 우리가 수정해서 성능을 개선시킬 것이 많지 않았다. 그래서 결과를 어떻게 개선시킬 수 있는지에 더욱 초점을 두고 프로젝트를 진행했다.

 

 

 

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
32
33
34
35
36
37
38
39
from transformers import PreTrainedTokenizerFast, GPT2LMHeadModel
 
def load_model(model_path):
    model = GPT2LMHeadModel.from_pretrained(model_path)
    return model
 
 
def load_tokenizer(tokenizer_path):
    tokenizer = PreTrainedTokenizerFast.from_pretrained(tokenizer_path)
    return tokenizer
 
 
def generate_text(sequence, max_length):
    model_path = "./models2"
    model = load_model(model_path)
    tokenizer = load_tokenizer(model_path)
    ids = tokenizer.encode(f'{sequence},', return_tensors='pt')
    final_outputs = model.generate(
        ids,
        do_sample=True,
        max_length=max_length,
        pad_token_id=model.config.pad_token_id,
        top_k=50,
        top_p=0.95,
    )
    print(tokenizer.decode(final_outputs[0], skip_special_tokens=True))
 
# sequence = input()
# max_len = int(input())
 
input = '기업 설명'
 
sequence = input
max_len = 50
 
print('input :' + sequence)
 
for i in range(10):
    print(generate_text(sequence, max_len))
print('=' * 30)
cs

GPT 언어 모델 자체가 주어진 단어 다음에 등장할 단어의 확률을 예측하는 방식으로 학습된다. 그래서 transformer로 문장을 생성할 때 성능을 높이기 위해 top_k 와 top_p 샘플링 방식을 이용했다.

 

 

 

Top-K 샘플링 : 현재 단어 다음으로 나올 수 있는 단어를 개수로 제한한다. 아주 작은 확률의 단어도 선택 가능.

Top-P 샘플링 : 현재 단어 다음으로 나올 수 있는 단어를 확률로 제한한다. 누적활률로 계산을 하기 때문에 확률이 낮은 단어는 제외.

 

 

 

 

결과에서 문제점들이 많이 발견됐다. 

1. input 값과 관련 없는 슬로건들이 등장한다.

2. 결과값의 문장 모양이(?) 통일성이 없다. => 슬로건, 광고문구만 뽑기 위해서 제약이 생긴다.

3. 완벽한 문장들이 등장해서 슬로건으로서의 가치가 떨어진다.

 

 

 

 

1, 2번을 해결하기 위해서 결국 노가다를 시작했다. 데이터셋을 조금 더 통일감 있게 구성을 하고('기업설명, 슬로건'으로 통일), 슬로건은 카테고리로 세분화가 되어있었는데, 더 세분화를 시켰다(화장품 -> 세럼, 스킨케어 등등). 그리고 1번을 더욱 정교하게 처리하기 위해서 텍스트 문장 유사도를 사용했다.  

 

 

 

3번 문제도 약간은 복잡했다. 에포크 수를 변경하면서 loss 값이 가장 적은 최적의 에포크 수를 찾아서 저장을 했다. 하지만 실제로 에포크에 따른 모델들을 다 돌려봤을 때, loss값이 가장 적었던 모델이 너무 완벽한 문장이 나와서 오히려 광고문구 같은 느낌이 나지 않는 경우도 발생했다. 영어 모델의 경우는 에포크와 어떤 gpt2 모델을 돌리느냐에 따라서 결과값의 차이가 컸다.

 

그리고 혹시나 데이터 양이 많지 않아서 생긴 문제가 아닐까 싶어서(1만 개 정도), 애플의 슬로건만(200개?) 가지고 학습을 진행했더니 정말 충격적인 결과가 나왔다.

 

 

 

 

데이터의 양이 적으면 애초에 슬로건 자체가 형성이 되지 않고, gpt2나 kogpt2에서 이미 사전에 학습한 내용을 가지고 문장을 생성하기 때문에 데이터 자체에 문제는 아니었다. 물론 데이터가 많으면 많을수록 우리가 노가다 해야할 부분도 많겠지만... 더 좋은 결과가 나올 것이라고 장담한다.

 

 

 

잠깐 스트레칭을 하면서

고개도 도리도리 돌려주세요

 

이어서 쓰려다가 너무 길어질 것 같아서

2편으로 나눕니다.

 

 

GPT3 관련 내용은 아래 링크로 ▼

 

 

GPT3 사용법, 설치부터 쉽게! 슬로건, 동화 만들기까지? KoGPT3 등장?

6-1 파이널 프로젝트 : 자연어처리, kogpt2를 이용한 슬로건 생성 목차 1. SKT-AI/KoGPT2와 자연처(NLP) 2. 데이터 전처리 (나무위키, 블로그) 3. KoGPT2와 기능구현 (인풋 아웃풋 조정) 4. 짧은 텍스트 / 문장

0goodmorning.tistory.com

 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

목차

1. SKT-AI/KoGPT2와 자연처(NLP)

2. 데이터 전처리 (나무위키, 블로그)

3. KoGPT2와 기능구현 (인풋 아웃풋 조정)

4. 짧은 텍스트 / 문장유사도

5. 배포 (구글 애즈, GA, AWS)

 


 

[네이버 어벤저스] 내가 보는 상품 홍보문구, 실은 AI가 썼다고?

국민 포털로 출발한 네이버가 다양한 플랫폼과 서비스들로 영역을 대폭 확장하고 있다. 이용자 경험을 위한 체질 개선뿐만 아니라, 중소상공인(SME) 및 창작자들과 이용자들을 연결해 디지털 비

n.news.naver.com

[네이버 어벤저스] 내가 보는 상품 홍보문구, 실은 AI가 썼다고?

뭔가 우리 팀에서 진행했던 파이널프로젝트 결과가 나오고 나서 부랴부랴 기사를 낸 것 같은 착각이 들어서 뿌듯했다. 기업에서도 이런 생각을 하고 있었고, 우리가 이걸 해냈구나? 하는 느낌.. 빨리 파이널 프로젝트 글을 쓰고 나서 다른 글도 올려야 하는데, 추가로 gpt3와 자연어 공부를 같이 하고 있어서 글 쓰는 시간도 부족한 것 같다. 그리고 정리를 해놨던 파일이 갑자기 증발이 되는 바람에 목차도 많이 줄였다.

 

우리가 필요한 데이터는 기업 설명(단순 기업명 가지고는 안 됐다)과 슬로건, 광고 문구였다. 하지만 온라인 상에는 그러한 데이터셋이 존재하지 않았다. 슬로건, 광고문구 데이터를 어떻게 모았는가 하면, 블로그에서 기업명과 함께 크롤링을 하고, 기업명을 네이버, 나무위키, 사람인 등에 다시 검색해서 기업의 정보를 모았다. 사람인에서 기업 설명이 깔끔하게 입력이 됐으면 이를 사용했을텐데 이상하게 분류된게 많아서 결국 손으로 데이터 전처리를 진행했다.

 

(* 잡담 : 도전하자. 프로젝트에 올라온 글들의 제목이 매력이 없어 보인다. 추후에 구글에서 검색이 되면서 사람들이 클릭하게끔 또 만들어야할 듯 싶다)

 

 

 

 

출처 : python awesome

어떻게 프로젝트를 진행했는지 다시 생각해보니, 다양한 시도를 하긴 했구나 하는 느낌? style gan을 사용해서 로고생성까지 시도하려고 했으나 생각보다 결과가 좋지 않고 비효율적이었다. 그래서 새로운 캐릭터를 생성하자는 느낌으로 해볼까 했는데, 캐릭터를 크롤링하고 찾는 것도 일일 것 같아서 우선 할 수 있는 부분에 더욱 중점을 뒀다.

 

 

 

 

출처 : 금강일보

네이버 블로그 크롤링의 문제점

1. 우선 java script로 구성이 돼서 동적 크롤링을 사용해야 한다. 2. iframe으로 둘러 쌓여서 크롤링이 쉽지 않았다그리고 스마트 에디터 one과 2.0 버전에 따라 크롤링 해야하는 방법이 다르다.

 

동적 크롤링인 셀레니움이 속도도 느리고 중간중간 빠지는 데이터들도 있어서 사용하는 것을 별로 안 좋아해서 어떻게 하면 beautiful soup으로 할까 하다가.. 네이버 블로그 검색창에 제목을 검색해서 하니까 잘 진행이 됐다. link가 포함된 부분을 크롤링하고 get('href')로 링크만 크롤링을 했다.

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
# 네이버 블로그 iframe 제거 함수
def delete_iframe(url):
    headers = {
        "User-Agent""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"}
   req = requests.get(url, headers=headers)
   req.raise_for_status()  # 문제시 프로그램 종료
    soup = BeautifulSoup(res.text, "lxml")
 
    src_url = "https://blog.naver.com/" + soup.iframe["src"]  # iframe 안에 있는 src 부분을 가져옴
 
    return src_url
 
cs

출처 : https://github.com/tiger-beom/naverblog_scraping

 

iframe 제거 함수를 미리 정의해놓으면 나중에 네이버 블로그 크롤링하는데 편리할 것이다. 2.0 -> 3.0 -> one 다 써봤었는데 2.0보다는 one이 더 깔끔하긴 하지만.. 정말 초반에는 오류 투성이었다. 글을 써야 하는데 평상시보다 몇 배가 더 걸렸던 기억이 있다. 투데이 2만이 넘었던 블로그였는데 ..

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 네이버 블로그 글 크롤링 함수
def text_scraping(url):
    headers = {
        "User-Agent""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"}
    req = requests.get(url, headers=headers)
    req.raise_for_status()  # 문제시 프로그램 종료
    soup = BeautifulSoup(res.text, "lxml")
 
    if soup.select_one('div.se-main-container'):
        text = soup.select_one('div.se-main-container').text
        text = text.replace('\n''')
        # print("블로그")
        return text
    elif soup.select_one('div#postViewArea'):
        text = soup.select_one('div#postViewArea').text
        text = text.replace('\n''')
        # print('블로그 2.0')
        return text
    else:
        return "오류"
cs

div.se-main-container가 포함되면 스마트에디터-one, div#postViewArea가 포함이 되면 2.0 버전이라고 생각하면 된다. 네이버 포스트의 경우 또 다른 방식으로 글을 크롤링해야 한다. 궁금하면 위의 깃허브로 들어가시면 됩니다.

 

 

 

 

나무위키 크롤링 문제점

동적, 정적 크롤링이 모두 안 됐다! 왜 그런가 찾아보니 나무위키에서 크롤링 하는 것을 원천 차단한 모양이다. 트래픽 과부하를 막기 위해서 그런 것으로 보인다. 그래서 봇으로 인식을 하면 아예 창이 들어가지지 않았다. 

 

우선 코드를 짜봤는데 진행이 되지 않았고, 내 문제인가 싶어서 위키독스에 나와있던 코드를  따라했는데도 되지 않았다. 결국 구글링을 열심히 해서 봇이 아닌 사람으로 인식하는 코드를 추가로 넣어줘야 했다

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#봇이 아닌 사람으로 인식하는 코드 / 자신의 크롬 위치 입력
subprocess.Popen(r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\chrometemp"')
 
options = webdriver.ChromeOptions()
options.add_experimental_option("debuggerAddress""127.0.0.1:9222")
 
chrome_ver = chromedriver_autoinstaller.get_chrome_version().split('.')[0]
try:
    driver = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe', options=options)
except:
    chromedriver_autoinstaller.install(True)
    driver = webdriver.Chrome(f'./{chrome_ver}/chromedriver.exe', options=options)
 
driver.implicitly_wait(3)
start = time.time()
cs

첫번째 줄에 있는 코드는 컴퓨터마다 크롬 위치가 다를 수 있기 때문에 확인해야 한다. 그리고 나서 크롬드라이버를 아예 새로 설치하는 것 같았다. import chromedriver_autoinstaller 를 통해서 패키지를 추가하자.

 

이렇게 코드를 입력하면 이제 본격적으로 셀레니움을 통해서 검색을 하면 된다고 생각했지만... 또 문제가 있었다. 어떤 정보를 긁어와야 하는지? 동음이의어가 존재할 때 어떻게 처리를 할지? 그리고 기업명이 단순히 기업명만 있으면 좋겠지만, 슬로건이나 광고문구를 가져오다 보니 지역명이나, 캠페인도 포함이 돼서 이를 먼저 처리해야했다. 그리고 no_search 리스트를 만들어서 제외했다.

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
            same = driver.find_element_by_xpath('//*[@id="app"]/div/div[2]/article/div[3]/div[1]/ul/li/a').text
 
            #동음이의어가 존재할 경우 원하는 정보를 긁어오지 않음, 예외로 뺴기 (분류에 동음이의어/* 여부)
            if '동음이의어' in same:
                explane = 'same'
                explanes.append(explane)
 
            #아닐 경우 그대로 진행
            else :
               try:
                    explane = driver.find_element_by_css_selector('div.wiki-heading-content').text
                    explanes.append(explane)
                    #print(explane)
 
                except:
                    explane = 'NaN'
                    explanes.append(explane)
cs

간단하게 접근을 했다. 개요에서 회사에 대한 설명을 긁어오기 전에 우선 동음이의어가 검색이 되는지 파악을 하고, 검색이 되는 경우 크롤링을 진행하지 않았다. 그리고 사람인, 네이버 뉴스 검색에서 회사 설명을 찾았다. 예전에 기사를 써본적이 있는데, 처음에 회사나 제품, 서비스에 대한 설명을 간단하게 적어놓는다는 점을 착안했다.

 

이렇게 크롤링을 하면 되겠다 싶었는데... 결과를 비교하니 참담했다. 그래서 손크롤링을 진행했다고 한다. ㅠㅠㅠ

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

목차

1. SKT-AI/KoGPT2와 자연처(NLP)

2. 데이터 전처리 (나무위키, 블로그)

3. KoGPT2와 기능구현 (인풋 아웃풋 조정)

4. 짧은 텍스트 / 문장유사도

5. 배포 (구글 애즈, GA, AWS)

 

모바일로 보니 너무 불편해서 수정 좀 했습니다 ㅠㅠ


 

결과물부터 보자면, kogpt2를 사용해서 슬로건을 생성하였다. 웹으로 서비스를 배포(AWS)하고, 구글애즈로 노출을 시키면서, GA(구글애널리틱스)로 트래픽을 분석하여 더 개선시키는 방향으로 진행했다.

 

 

 

 

 

 

GPT3 사용법, 설치부터 쉽게! 슬로건, 동화 만들기까지? KoGPT3 등장?

6-1 파이널 프로젝트 : 자연어처리, kogpt2를 이용한 슬로건 생성 목차 1. SKT-AI/KoGPT2와 자연처(NLP) 2. 데이터 전처리 (나무위키, 블로그) 3. KoGPT2와 기능구현 (인풋 아웃풋 조정) 4. 짧은 텍스트 / 문장

0goodmorning.tistory.com

읽으면 유용한 글 : GPT3

 

 

 

 

 

패키지, 툴 등 사용 기술

기간 : 2021.07.12 ~ 2021.08.18 (1 달 조금 넘게)

사용 기술은 그림을 참고. 

 

파이널 프로젝트라서 거창한 것을 해보려고 다양한 아이디어를 냈으나 쉽게 주제를 결정할 수 없었다. 이것저것해보다가 시간은 4주도 남지 않아서 처음에 진행하려고 했던 슬로건 생성을 해보자고 했다. 과연 슬로건처럼 간단하면서 임팩트 있는 문구를 인공지능이 생성할 수 있을까? 하는 의문이 있었지만 인공지능은 해냈다. (우리가 해냈다)

 

이번 시간을 통해서 자연어처리에 대해서 많이 공부를 할 수 있었고, gpt2와 프로젝트가 끝난 이후 gpt3에 대해서도 추가적으로 공부를 하였다. 주로 인공지능을 통해서 분류를 하거나 예측을 하였는데, 새로운 문장을 생성한다는게 참 신기했다.

 

 

 

GPT(Generative Pre-trained Transformer)는 언어모델로 '자연어 디코더 모델'이라고 생각하면 쉽다. 자연어 처리 기반이 되는 조건부 확률 예측 도구이며, 단어가 주어졌을 때 다음에 등장한 단어의 확률을 예측하는 방식으로 학습이 진행 된다. 문장 시작부터 순차적으로 계산한다는 점에서 일방향을 보인다.

 

 

 

 

 

KoGPT2 skt-ai에서 만든 한글 디코더 모델. KoGPT2에서는 기존 GPT의 부족한 한국어 성능을 극복하기 위해 많은 데이터(40g)로 학습된 언어 모델로서 한글 문장 생성기에서 좋은 효과를 보인다고 한다. 시 생성, 가사 생성, 챗봇 등의 서비스 구현한 사례가 있다.

 

단순히 모델 사용보다 자연어를 어떻게 처리할지 많은 공부를 하게 됐다. 간단하게 정리한 부분을 추가적으로 공유하려고 한다.

 

자연어 처리로 할 수 있는 것들 

-텍스트 분류 (스팸 메일)

-감성 분석 (긍/부)

-내용 요약 (추출/ 생성)

-기계 번역 (번역)

-챗봇

 

 

 

 

출처 : dreamstime

자연어 처리 과정

-Preprocessing (전처리) : stopwords 불용어 제거, 형태소 분석, 표제어 추출 / 컴퓨터가 자연어를 처리할 수 있게

-Vectorization (벡터화)  : 원핫인코딩, count vectorization, tfdif, padding

-Embedding : word2vec, doc2vec, glove, fasttext

-Modeling : gru, lstm. attention

 

*Transfer learning (전이 학습) : pretrain한 임베딩을 다른 문제를 푸는데 재사용 

*Fine-tuning (파인 튜닝) : pretrain된 모델을 업데이트하는 개념. / 엔드투엔드에서 발전

 

 

 

임베딩

- 자연어를 숫자의 나열인 벡터로 바꾼 결과 혹은 과정 전체 (벡터 공간에 끼워넣는다)

- 말뭉치의 의미, 문법 정보가 응축되어 있음, 단어/문서 관련도 계산 가능

- 품질이 좋으면 성능이 높고 converge(수렴)도 빠르다

- NPLM(최초) / Word2Vec(단어수준) / ELMo(문장수준), BERT, GPT

 

단어 문장간 관련도 예상 / t-SNE 차원 축소 100차원->2차원으로 / Word2Vec 개선 모델 FastText / 행렬 분해 모델 / 에측 기반 방법 / 토픽 기간 방법 등으로 나뉨

 

잠재의미분석 : 말뭉치의 통계량을 직접적으로 활용

희소 행렬 - 행렬 대부분의 요소 값 0

단어-문서행렬, TF-IDF, 단어-문맥 행렬, 점별 상호정보량 행렬

 

 

단어수준 임베딩 단점 : 동음이의어 분간 어려움 

=> ELMo, BERT, GPT 시퀀스 전체의 문맥적 의미 함축해서 전이학습 효과가 좋음

 

*다운스트림 태스크 : 풀고 싶은 자연어 처리의 구체적 문제들 

(품사 판별, 개체명 인식, 의미역 분석, 형태소 분석, 문장 성분 분석, 의존 관계 분석, 의미역 분석, 상호참조 해결)

*업스트팀 태스크 : 다운스트렘 태스크 이전에 해결해야할 괴제. 단어/문장 임베딩을 프리트레인하는 작업

 

토큰 : 단어, 형태소, 서브워드

토크나이즈 : 문장을 토큰 시퀀스로 분석

형태소 분석 : 문장을 형태소 시퀀스로 나누는 과정

 

 

 

 

출처 : 벡터가 어떻게 의미를 가질까?

TF-IDF : 백오브워즈 가정(어떤 단어가 많이 쓰였는가) / term frequency inverse document

순서 정보는 무시하는 특징이 있다. 주제가 비슷하면 단어 빈도 또는 단어 비슷할 것이다. (정보 검색 분야에서 많이 쓰인다.)

사용자 질의에 가장 적절한 문서 보여줄 때 코사인 유사도를 구해서 보여준다.

 

-TF : 특정 문서에 얼마나 많이 쓰이는지

-DF : 특정 단어가 나타난 문서의 수

-IDF : 전체 문서를 해당 단어의 DF로 나눈 뒤 로그를 취함. 값이 클수록 특이 단어

(단어의 주제 예측 능력과 직결 됨)

 

 

 

출처 : 브런치

ELMo, GPT : 단어가 어떤 순서로 쓰였는가? 주어진 단어 시퀀스 다음에 단어가 나올 확률이 어떤게 큰지? 

n-gram (말뭉치 내 단어들을 n개씩 묶어서 빈도를 학습), 다음 단어 나타날 확률 조건부확률의 정의를 활용해 최대우도추정법으로 유도 => 한 번도 나오지 않으면 확률이 0이 되므로 보완을 해줘야 한다

 

마코프 가정 (한 상태의 확률은 그 직전 상태에만 의존한다) => 그래도 등장하지 않았던 단어 나오면 0이 되기 때문에 백오프, 스무딩 방식 (높은 빈도를 가진 문자열 등장확률을 일부 깎고, 등장하지 않은 케이스에 확률 부여

 

뉴럴 네트워키 기반 언어 모델 : 다음 단어를 맞추는 과정 학습 (엘모,지피티) 

마스크 언어 모델 : 문장 전체를 보고 중간에 있는 맞추기 (BERT)

 

 

 

 

출처 : Towards Data Scince

Word2Vec : 어떤 단어가 같이 쓰였는가 (분포 가정) 단어의 의미는 곧 그 언어에서의 활용이다?

타깃단어와 그 주위에 등장하는 문맥단어 계산 / 분포 정보가 곧 의미? 의문점

형태소 분류 - 계열 관계 : 해당 형태소 자리에 다른 형태소가 대치 될 수 있는지

품사 분류 – 기능(주어, 서술어), 의미(같은 뜻), 형식(이름, 성질, 상태)

형태는 같지만 기능과 의미가 달라질 수 있다.(기능과 분포는 다르지만 밀접한 관련)

PMI 두 단어의 등장이 독립일 때 대비해 얼마나 자주 같이 등장하는지 (단어 가중치) 단어-문맥 행렬

 

+ Recent posts