반응형

나무위키 워드벡터(word2vec) 만들기


1. 나무위키 데이터베이스 다운로드

https://mu-star.net/wikidb

미러링 사이트에서 찾았다. 다운로드 안되는 곳이 많음. 

7z압축되어 있는 최신 파일 다운로드하니 1.2기가 정도 됨.


+ 압축해제 

우분투에 7z 압축해제 프로그램이 없어서 p7zip을 설치하고 다운받은 압축 파일을 풀었더니  무려 8.3기가였다.

설치

#apt-get install p7zip

파일압축해제

#7zr x [파일명].7z


+파일이 너무 커서, 조금만 읽어보고 형태를 보자.

압축을 풀면 확장자가 JSON 포맷임.

# wc -l  namuwiki_20180326.json

0

줄 구분없이 한 줄로 구성된 텍스트 파일이다. more로 한 페이지만 보자.


# head namuwiki_20180326.json | more

다음과 같이 나온다.

[{"namespace":"0","title":"!","text":"#redirect \ub290\ub08c\ud45c\n","contributors":["namubot","R:hoon12560"]},{"nam

espace":"0","title":"!!\uc544\uc557!!","text":"[[\ud30c\uc77c:3444050440.jpg]]\n([[\uc2e0 \uc138\uacc4\uc218\uc758 \u

bbf8\uad81 2]]\uc5d0\uc11c \ub72c !!\uc544\uc557!!)\n{{{+1 \uff01\uff01\u3042\u3042\u3063\u3068\uff01\uff01 }}}\n\n[[

\uc138\uacc4\uc218\uc758 \ubbf8\uad81 \uc2dc\ub9ac\uc988]]\uc5d0 \uc804\ud1b5\uc73c\ub85c \ub4f1\uc7a5\ud558\ub294 \u

b300\uc0ac. [[\uc138\uacc4\uc218\uc758 \ubbf8\uad81 2 \uc81c\uc655\uc758 \uc131\ubc30|2\ud3b8 \uc81c\uc655\uc758 \uc1

31\ubc30]]\ubd80\ud130 \ub4f1\uc7a5\ud588\uc73c\uba70, \ud6cc\ub96d\ud55c [[\uc0ac\ub9dd \ud50c\ub798\uadf8]]\uc758 \

uc608\uc2dc\uc774\ub2e4.\n\n\uc138\uacc4\uc218\uc758 \ubaa8\ud5d8\uac00\ub4e4\uc774 \ud0d0\ud5d8\ud558\ub294 \ub358\u

c804\uc778 \uc218\ud574\uc758 \uad6c\uc11d\uad6c\uc11d\uc5d0\ub294 \ucc44\ucde8\/\ubc8c\ucc44\/\ucc44\uad74 \ud3ec\uc

778\ud2b8\uac00 \uc788\uc73c\uba70, \uc774\ub97c \uc704\ud55c \ucc44\uc9d1 \uc2a4\ud0ac\uc5d0 \ud22c\uc790\ud558\uba7

4 \uc81c\ud55c\ub41c \ucc44\uc9d1 \uae30\ud68c\uc5d0 \ubcf4\ub2e4 \ud070 \uc774\ub4dd\uc744 \ucc59\uae38 \uc218 \uc78

8\ub2e4. \uadf8\ub7ec\ub098 \ubd84\ubc30\ud560 \uc218 \uc788\ub294 \uc2a4\ud0ac \ud3ec\uc778\ud2b8\ub294 \ud55c\uc815

\ub41c \ub9cc\ud07c \ucc44\uc9d1 \uc2a4\ud0ac\uc5d0 \ud22c\uc790\ud558\ub294 \ub9cc\ud07c \uc804\ud22c \uc2a4\ud0ac \

ub808\ubca8\uc740 \ub0ae\uc544\uc9c0\uac8c \ub41c\ub2e4.\n\n 1. \ucc44\uc9d1\uc6a9 \uce90\ub9ad\ud130\ub4e4\ub85c \uc

774\ub8e8\uc5b4\uc9c4 \uc57d\ud55c \ud30c\ud2f0(ex: [[\ub808\uc778\uc800(\uc138\uacc4\uc218\uc758 \ubbf8\uad81 2)|\ub

808\uc778\uc800]] 5\uba85)\uac00 \uc218\ud574\uc5d0 \uc785\uc7a5\ud55c\ub2e4.\n 1. \ud544\ub4dc \uc804\ud22c\ub97c \u

d68c\ud53c\ud558\uba74\uc11c \ucc44\uc9d1 \ud3ec\uc778\ud2b8\uc5d0 \ub3c4\ucc29\ud574 \uc5f4\uc2ec\ud788 \uc544\uc774

\ud15c\uc744 \uce90\ub294 \uc911\uc5d0...\n ..............................

유니코드 인코딩인 것으로 보인다. title, text 필드가 제목과 내용인 것 같다.

JSON 파일이 너무 커서 한 번에 읽을 수도 없다. python은 ijson 패키지에서 처리한다고 하니 살펴본다.

https://pypi.org/project/ijson/


+시험삼아 데이터 몇개만 꺼내 확인해 본다.

import ijson


def load_json(filename):
count=0
with open(filename, 'r') as fd:
parser = ijson.parse(fd)
for prefix, event, value in parser:
if prefix.endswith('.title'):
print('index=', count+1)
print("\nTITLE: %s" % value)
elif prefix.endswith('.text'):
print("\nCONTENT: %s" % value)
count += 1
# debug
if count==10 :
break
if __name__ == "__main__":
print('load_json start')
load_json('/home/psychic/download/namuwiki_20180326.json')
print('load_json end')

글 제목과 내용이 번갈아가면서 출력된다. 알아서 디코딩되어 한글이 바로 잘 출력되었다.

데이터가 너무 많기 때문에 10개만 출력되게 디버깅코드를 추가하였다. 

얼마나 많은 데이터가 있는지 카운트를 해 보았다. (출력문이 있으면 상당히 느려지기 때문에 카운트만 계산한다. ) 카운트만 해도 오래 걸린다. 565985 개가 있다. (약 56만건)


+용이한 개발 및 디버깅 테스트를 위해 일부만 자르자. 원본 갖고 바로 작업하는 것은 상당히 비효율적이다. 개발시에는 디버깅용으로 라이트한 데이터만 다루고, 이후 개발이 다 되고 난 후에 전체데이터로 학습을 시키면 된다. 물론, DB가 크다는 가정하에 개발해야 될 것이다. (메모리 관리)


+디버깅용 DB 만들기 / 미니나무위키DB

일부만 자른다. 10메가로 하자.

# head -c 10000000 > mini_namu.json

파일을 열고 마지막 부분을 편집하여 JSON 형식을 맞춘다.

vi로 편집하려했더니 느려서 안되겠다. 그냥 커맨드로 append해야 겠다.

tail -c 800 mini_namu.json  | grep -E "title|text"

:"#redirect \uc81c18\ub300 \uad6d\ud68c\uc758\uc6d0 \uc120\uac70\n","contributors":["namubot","R:ttgrgt24","211.187.44.56"]},{"namespace":"0","title":"18\ub85c \uc81c\ud6c4","text":"[include(\ud2c0:18\ub85c \uc81c\ud6c4)]\n\n\u5341\u516b\u8def\u8af8\u4faf\n\n[\ubaa9\ucc28]\n== \uc124\uba85 ==\n[[\ud6c4\ud55c]]\ub9d0 [[190\ub144]], [[\uc5ed\uc801]] [[\ub3d9\ud0c1#s-1|\ub3d9\ud0c1]]\uc744 \ud1a0\ubc8c\ud558\uace0 [[\ud55c\ub098\ub77c#s-1.2|\ud55c\ub098\ub77c]] \ud669\uc2e4\uc744 \uad73\uac74\ud788 \ubc1b\ub4e0\ub2e4\ub294 \uac83\uc744 \ub300\uc758 \uba85\ubd84\uc73c\ub85c \ud558\uc5ec \uc77c\uc5b4\uc120 [[\uc81c\ud6c4]]\ub4e4\uc758 [[\uc5f0\ud569]]. \uc774\ub978\ubc14 '[[\ubc18\ub3d9\ud0c1 \uc5f0\ud569]]'\uc774\ub77c\uace0 \ubd80\ub974\uba70, \ud568\uace1\uad00\uc758 \ub3d9\ucabd \uc9c0\ubc2

#echo -n "0\"}]" >> mini_namu.json

#tail -c 100 mini_namu.json 

ud569]]'\uc774\ub77c\uace0 \ubd80\ub974\uba70, \ud568\uace1\uad00\uc758 \ub3d9\ucabd \uc9c0\ubc20"}] 



+미니 DB를 사용하여 워드 벡터 생성.

import ijson
import codecs
import sys, os
import time

import nltk

from gensim.models import word2vec
from konlpy.tag import Okt

import pickle


'''
JSON 나무위키 파싱

'''


def load_json(filename):
count=0
with open(filename, 'r') as fd:
# parser = ijson.parse(fd)
# for prefix, event, value in parser:
# print ( 'prefix=', prefix, 'event=', event )

# if prefix.endswith('.title'):
# # print('index=', count+1)
# # print("\nTITLE: %s" % value)
# elif prefix.endswith('.text'):
# # print("\nCONTENT: %s" % value)
# count += 1
# print ('total cnt=', count)
for item in ijson.items(fd, 'item'):
print(item['title'])
# print(item['text'])

def load_and_write_content(filename, filename2):
count=0
file = codecs.open(filename2, 'w', encoding='utf-8')
with open(filename, 'r') as fd:
for item in ijson.items(fd, 'item'):
count+=1
file.write('[[제목]]: ')
file.write(item['title'])
file.write('\n')
file.write('[[내용]]: \n')
file.write(item['text'])
file.write("\n")
file.close()
print('contents count=', count)


def make_wakati(f1, f2, f3):
file = codecs.open(f1, 'r', encoding='utf-8')
text = file.read()

twitter = Okt()
lines = text.split('\r\n')
results = []
for line in lines:
r = []
malist = twitter.pos(line) # part of speech (POS)
# pumsa : Noun, Josa, Verb, Eomi, Punctuation, Number, KoreanParticle,
for word, pumsa in malist:
if not pumsa in ['Josa', 'Eomi', 'Punctuation']:
r.append(word)
results.append((" ".join(r)).strip())
output = (" ".join(results)).strip()

with open(f2, "w", encoding="utf-8") as fp:
fp.write(output)

print('make word2vec')
data = word2vec.LineSentence(f2)
model = word2vec.Word2Vec(data, size=200, window=10, hs=1, min_count=5, sg=1, workers=3)
model.save(f3)
print('end word2vec')


if __name__ == "__main__":
print('load_json start')
print('curdir=', os.getcwd())
filedir = os.path.dirname( os.path.realpath(__file__))
os.chdir(filedir)
print('filedir=', filedir)

filename ='mini_namu.json'
filename2='mini_namu.txt'
filename3='mini_namu.wakati'
filename4='mini_namu.model'
filename5='mini_namu.pkl'

# load_json(filename)
# 나무위키 JSON DB에서 제목과 컨텐트를 스트링으로 기록한 파일 생성. (txt)
if True:
print('Create WordTxT')
t1=time.time()
load_and_write_content(filename, filename2)
t2=time.time()
print('End WordTxt ', 'time=',t2-t1)

if True:
print('Create Wakati')
t1=time.time()
make_wakati(filename2, filename3, filename4)
t2=time.time()
print('End Wakati', 'time=',t2-t1)

if True:
print('Model test')
t1=time.time()
model = word2vec.Word2Vec.load(filename4)
t2=time.time()
print(model.most_similar(positive=["조선", "일본"]))
print(model.most_similar(positive=["고려"]))
print(model.most_similar(positive=["고려"], negative=["왕"]))
print(model.most_similar(positive=["고려", "경제"]))
print(model.most_similar(positive=["RPG", "게임"]))
print(model.most_similar(positive=["임진왜란"]))
print(model.most_similar(positive=["왕", "여자"], negative=["남자"]))

print(model.similarity('고려','공민왕'))
print(model.doesnt_match("아침 점심 저녁 조선 밥".split() ) )
print(model.doesnt_match("총 무기 칼 게임 하늘".split() ) )

print('time=',t2-t1)

gensim.model.word2vec을 사용하여 간단하게 만들어서 테스트해서 아래의 결과가 나왔다.

[('1536년', 0.7473468780517578), ('음력', 0.7256854772567749), ('이이', 0.7070702910423279), ('도요토미', 0.7009462118148804), ('1552년', 0.6966617703437805), ('정조', 0.6919983625411987), ('문인', 0.6826009750366211), ('메이지', 0.6784789562225342), ('덴노', 0.6729492545127869), ('1337년', 0.6693580150604248)]

[('폐위', 0.7308624982833862), ('공민왕', 0.7183995246887207), ('정종', 0.7026641368865967), ('충숙왕', 0.7024295926094055), ('인종', 0.6962566375732422), ('즉위', 0.6933885216712952), ('충혜왕', 0.6890701651573181), ('명종', 0.6795019507408142), ('무신정권', 0.6763734817504883), ('원나라', 0.6668024659156799)]

[('마진', 0.2932665944099426), ('국호', 0.28764602541923523), ('발전', 0.27793973684310913), ('인종', 0.26443612575531006), ('말기', 0.2635525166988373), ('부족하다는', 0.2609822154045105), ('경향', 0.2581954002380371), ('1.6', 0.2573755383491516), ('줄어든', 0.2572077512741089), ('시기', 0.25421619415283203)]

[('천도', 0.6886128783226013), ('무신정권', 0.6836416721343994), ('인종', 0.6704342365264893), ('요나라', 0.6599131226539612), ('공민왕', 0.6575653553009033), ('권력자', 0.6571816205978394), ('도모', 0.6510674357414246), ('신변', 0.6495651006698608), ('폐위', 0.646056056022644), ('몽골', 0.6421409845352173)]

[('동봉', 0.6660709381103516), ('FPS', 0.6493582129478455), ('플래시', 0.6356097459793091), ('슈팅', 0.6346113681793213), ('로더', 0.629481852054596), ('플레이스테이션', 0.6227577924728394), ('TECHNIKA', 0.6164207458496094), ('DJMAX', 0.6132534742355347), ('온라인게임', 0.6100178360939026), ('오어', 0.606633186340332)]

[('1598년', 0.9288400411605835), ('이순신', 0.9017009735107422), ('1618년', 0.7677931189537048), ('1821년', 0.7676668167114258), ('도요토미', 0.7628185749053955), ('1865년', 0.7540280222892761), ('1839년', 0.7511029243469238), ('1868년', 0.7489482760429382), ('문인', 0.7481677532196045), ('1863년', 0.7473239898681641)]

[('속특', 0.4879986345767975), ('왕비', 0.48508623242378235), ('성종', 0.4771915674209595), ('선조', 0.4723415970802307), ('샤', 0.46159034967422485), ('세조', 0.4432491660118103), ('충혜왕', 0.43805891275405884), ('후궁', 0.4356191158294678), ('철종', 0.4354616701602936), ('문종', 0.43034279346466064)]

0.7184

조선

게임

데이터가 적기 때문에 오차가 좀 있지만 그런대로 결과는 나온다.




+실제 나무위키DB 텍스트 변환 (대용량 변환)

파일명들을 실제 나무위키 원본으로 바꾸고 실행해보자.


1단계. create wordtxt에서 encoding 에러 발생함.

open에 옵션으로 errors='ignore'로 무시하고 진행하도록 설정.

참고로 작업 서버 사양은... 

CPU : intel i7-7800X CPU 3.5GHz 12core

메모리 : 64기가

GPU: GeForce GTX 1080


시간이 오래걸릴 것으로 예상.  원본json이 8기가가 넘어서, 생성되는 것도 그 쯤 될 것이다.

7분정도 되니까 1기가까지 만들어짐. 

25분 걸려서 txt 파일 5기가 정도로 생성 완료하였다.


2단계.wakati 생성. 텍스트 파일을 읽어서 필요한 단어만 모아놓음.  (명사, 동사, 형용사, 부사..)  word2vec 클래스에서 에러가 발생할 것으로 생각됨. 메모리 부족??

VM 에러 발생. Memory.

# ulimit -c unlimited     ; 파일 사이즈 제한 해제도 미리 해 둠.

품사 정보 생성을 위해 Okt (구 Twitter)를 쓰는데, 거기서 발생한 것으로 보임. 라인 길이가 너무 크다. 2424660146 이정도된다.

메모리가 되는 선에서 적당한 크기로 잘라서 부분씩 처리하기로 함. 여기서는 20메가씩 스트링을 처리. 좀 더 크게 잡았더니 계속 실패해서 줄이고 줄임.  스트링을 자르는 방식도 여러가지인데, 그냥 구현하기로... 메모리를 상당히 내부적으로 많이 쓰는 듯 함. 

make_wakati 수정


# make wakati file
twitter = Okt(max_heap_size=1024*8) # heap size.. 8G
lines = text.split('\r\n')
t1=time.time()

print('making wakati start')
print('lines count=', len(lines))
fp = open(f2, "w", encoding="utf-8")
for line in lines:
linelen = len(line)
print("line length=", linelen)

# split.
# lineparts = map(''.join, zip(*[iter(line)] * 1000*1000*20)) # 20MB / 1line
blocksize = 1000*1000*20
if linelen % blocksize == 0:
blockcnt = int(linelen/blocksize)
else:
blockcnt = int(linelen / blocksize) + 1

for li in range(blockcnt):
if li==blockcnt-1:
linepart = line[li*blocksize:]
else:
linepart = line[li*blocksize:(li+1)*blocksize]
print('progress=', li, '/', blockcnt, len(linepart) )
malist = twitter.pos(linepart) # part of speech (POS)
# pumsa : Noun, Josa, Verb, Eomi, Punctuation, Number, KoreanParticle,
for word, pumsa in malist:
if not pumsa in ['Josa', 'Eomi', 'Punctuation']:
fp.write(word.strip())
fp.write(" ")
fp.close()
t2=time.time()
print('making wakati end time=', t1-t1)

다음 날 보니 wakati 파일 생성완료. 4G 크기.


3단계로 word vector 생성  진행. 얼마나 진행되었는지 알 수 없다. 언제 끝나지?

메모리 상황을 보면 가상 메모리로 파이썬이 66기가를 쓰고있다. cpu는 3개 쓰기로 설정해서 300% 풀로 나온다. 

기나긴 기다림 끝에 드디어 끝났다. 워드 벡터 생성에 걸린 시간은 41564 초. 시간으로 바꾸니 11시간 걸렸다.

전체 과정(와카티 생성, 워드 벡터 생성) 시간은 96503초. 시간으로는 26시간 걸렸다. 반드시 학습한 모델을 저장하는 코드를 넣어라. 저장을 깜빡했다면 이제까지 했던게 허사. 처음 부터 다시 ^^;;

모델 저장이 됐으니 이제, 필요할때 마다 로딩하여 질의를 하면 된다.

워드벡터 모델 파일 사이즈는 236메가. 그리고 넘파일파일이 3개 더 생긴다. 모델파일만 있으니 안돌아가는 걸로 봐서 넘파이 파일도 쓰는것 같다. 다 합쳐서 2기가 정도 된다.

모델 로딩에만 8초 정도 걸린다.


+ 나무위키 모델 테스트

질의 내용
print(model.most_similar(positive=["조선", "일본"]))
print(model.most_similar(positive=["고려"]))
print(model.most_similar(positive=["고려"], negative=["왕"]))
print(model.most_similar(positive=["고려", "경제"]))
print(model.most_similar(positive=["RPG", "게임"]))
print(model.most_similar(positive=["임진왜란"]))
print(model.most_similar(positive=["왕", "여자"], negative=["남자"]))

print(model.similarity('고려','공민왕'))
print(model.doesnt_match("아침 점심 저녁 조선 밥".split() ) )
print(model.doesnt_match("총 무기 칼 게임 하늘".split() ) )


Model test

[('대한제국', 0.6866917610168457), ('중국', 0.6801478862762451), ('우리나라', 0.6566961407661438), ('청나라', 0.6511589288711548), ('일제강점기', 0.6480269432067871), ('한국', 0.6324470043182373), ('조선국', 0.6295247077941895), ('경술국치', 0.6277073621749878), ('임진왜란', 0.623056173324585), ('역사', 0.6140305995941162)]

[('조선', 0.6692752838134766), ('고려왕조', 0.6515953540802002), ('공민왕', 0.6487005949020386), ('문종', 0.6360877752304077), ('현종', 0.6323516368865967), ('무신정권', 0.6292731761932373), ('태조', 0.6256691217422485), ('감안', 0.6252619624137878), ('冊封', 0.6246188879013062), ('충렬왕', 0.6229778528213501)]

[('감안', 0.4361225962638855), ('염두', 0.3996908664703369), ('제승방략', 0.39954277873039246), ('유념', 0.3989650011062622), ('바람직하지', 0.39659619331359863), ('해보아야', 0.39381834864616394), ('갖추자는', 0.39022499322891235), ('추세였음', 0.38095635175704956), ('타당', 0.3788178563117981), ('받아들여지기에', 0.37214767932891846)]

[('정책', 0.7264151573181152), ('동북아', 0.702474057674408), ('사회', 0.7002162933349609), ('정치', 0.6759592294692993), ('불평등', 0.6736841797828674), ('노동시장', 0.6685125827789307), ('경제정책', 0.668291449546814), ('한반도', 0.6653428673744202), ('민생', 0.6610323190689087), ('발전', 0.6543104648590088)]

[('TPS', 0.757465124130249), ('롤플레잉', 0.7494930028915405), ('로그라이크', 0.7455687522888184), ('FPS', 0.7437580823898315), ('플랫포머', 0.7379695177078247), ('RTS', 0.7236455082893372), ('모바일', 0.7205138206481934), ('MOBA', 0.718673586845398), ('SRPG', 0.7134039402008057), ('MMORPG', 0.7068561911582947)]

[('정유재란', 0.8903812170028687), ('병자호란', 0.8541854619979858), ('임란', 0.8498165607452393), ('왜란', 0.8400564193725586), ('정묘호란', 0.7854044437408447), ('1592년', 0.7841730117797852), ('의병장', 0.781627893447876), ('류성룡', 0.7787343263626099), ('왜군', 0.7751662731170654), ('광해군', 0.7695599794387817)]

[('왕인', 0.6398370265960693), ('준왕', 0.6377674341201782), ('왕중', 0.5966447591781616), ('극', 0.5917797088623047), ('최후', 0.5905873775482178), ('선왕', 0.5905437469482422), ('왕전', 0.588803231716156), ('中山王', 0.5885385274887085), ('楚穆王', 0.5835995674133301), ('南平王', 0.5762388706207275)]

0.648701

조선

게임

model.wv.get_vector('노트북') 을 해보니 200개의 수가 나온다. 200차원. 모델 생성시에 사이즈를 200으로 줘서 그렇다. 값이 클 수록 표현하는 정보가 큰데, 학습 시간이 더 오래 걸린다.

그런대로 재미가 있다.

다음엔 이걸로 무엇을 할 수 있을지 생각해 봐야겠다.
















반응형

+SVM (support vector machine)을 사용하여 간단하게 바이너리 분류하기


간단하게 말하면 가장 마진이 크도록 최적의 구분 라인 긋기. 약간의 판단 오류가 있더라면 데이터의 밀집 분포 정도에 따라 최적의 라인은 다를 수 있다. 판단오류가 하나도 없도록(과적합) 구분 라인을 만들면 오히려 임의의 값 예측시 정확도가 더 떨어질 수 있다. 


X 데이터 : 피쳐2개. 

Y데이터 : 라벨 (0, 1) binary 분류값.

SVM으로 최적 구분 라인 계산.

임의의 값에 대해 Y데이터 예측하기.


from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np

# line split SVM

X = np.array([[1,2],
[5,8],
[1.5,1.8],
[8,8],
[1,0.6],
[9,11]])
y = [0,1,0,1,0,1]
clf = SVC(kernel='linear'1.0# C is error penalty. if C is bigger then more strictly but margin will be narrow...
clf.fit(X,y)
print(clf.predict([[0.58,0.76]]))
print(clf.predict([[10.58,10.76]]))

w = clf.coef_[0]
print(w)
a = -w[0] / w[1]

xx = np.linspace(0,12)
yy = a * xx - clf.intercept_[0] / w[1]

h0 = plt.plot(xx, yy, 'k-'label="non weighted div")

plt.scatter(X[:, 0], X[:, 1], = y)
plt.legend()
plt.show()

[해설]
x데이터의 벡터는 2차원이고 구분 레이블은 y로 0, 1로 두 그룹으로 나눈다.
SVC의 리턴값으노 clf로 피팅을 하게 되면
clf.predict()로 입력값 x에 대한 구분 레이블 y를 예측할 수 있다.

x데이터의 벡터요소(피쳐)를 x0, x1라 하면
새로운 좌표계의 1차원 좌표축을 z라하면
z = f (x0, x1) 
z>=0 이면 레이블1, z<0이면 레이블 0가 될 것이다. (z=0이면 1일까? 맞다.)

clf의 coef_로 w0, w1를 얻고, intercept로 b를 얻는다.
w0, w1는 입력값의 가중치. b 는 bias

z = w0*x0+w1*x1 + b 가 된다.
따라서 위 라인 (z=0으로 놓는다.)을 기준으로 분류한다.

위 라인을 x1(Y축)에 대해 정리하면
기울기는 -w0/w1
y절편은 -b/w1가 된다.
이 라인이 구분선이 된다.





반응형



++ Linear Regression with multi-variables
X의 feature들이 여러 개 x1, x2, ...

import tensorflow as tf
# y = x1*2+x2+x3 training
# W => 2,1,1, b=0
x_train = [[1,2,3],[2,3,4],[3,4,5],[4,5,6], [1,3,5]]
y_train = [[7],[11],[15],[19], [10]]

#placeholder
x = tf.placeholder(tf.float32, shape=[None,3])
y = tf.placeholder(tf.float32, shape=[None,1])
# variables
W = tf.Variable(tf.random_normal(shape=[3,1]), name='W')
b = tf.Variable(tf.random_normal(shape=[1]), name='b')

# model
hypothesis = tf.matmul(x, W) + b
cost = tf.reduce_mean( tf.square(hypothesis-y) )
# train
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train = optimizer.minimize(cost)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
# test
# hres= sess.run(hypothesis, feed_dict={x:x_train, y:y_train})
for i in range(3001):
    _, pcost, _W, _b= sess.run([train, cost, W, b], feed_dict={x:x_train, y:y_train})
    if i%500==0:
        print (i, pcost, _W, _b)

# test
print( sess.run(hypothesis, feed_dict={x: [[4, 2, 3]]}))





반응형



1. Linear Regression 

++ single attribute . 

H(x) = x*W + b
cost(W,b) = 1/m * 오차제곱의 합  =   오차제곱의 평균. (편차제곱의 평균은 분산이다.)
   = 1/m * Sigma(  (H(x)-y)^2  )                    # cost함수를 여기에다가 1/2을 곱하여 사용하기도 한다. 그 때의 미분결과는 아래에 2*가 없어진다.
dJ/dW = 2* (1/m) * Sigma(  (H(x)-y) x )
#train
W := W - alpha* dJ/dW

x_train=[1,2,3]
y_train=[1,2,3]

W=tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name="bias')
hypothesis = x_train * W + b

cost = tf.reduce_mean(  tf.square(hypothesis - y_train) )

optimizer = tf.train.GradientDescentOptimizer( learning_rate=0.1 )
train = optimizer.minimize(cost)

sess = tf.Session()
sess.run( tf.global_variables_initializer())
for step in range(2001):
     sess.run(train)
     if step%100==0:
          print(step, sess.run(cost), sess.run(W), sess.run(b) )

+ 예측 
print ( sess.run( hypothesis , {X:[100]} ) )



반응형




-학습데이터 저장 및 복구

: 저장
변수들 선언. (tf.Variables....) 주의! 이름을 지정.
W1 = tf.Variable( tf.truncated_normal(shape=[INPUTSIZE, HIEEDNSIZE]), dtype=tf.float32, name='W1')
저장할 변수들 지정

param_list={ 'W1':W1, 'b1':b1, 'W2':W2, 'b2':b2}
saver = tf.train.Saver( param_list )
...
saver.save(sess, './savedata.ckpt', write_meta_graph=False)     #디렉터리 명시

: 로딩
변수들 선언. (tf.Variables....) 주의! 이름을 지정. (저장시 사용했던 variables 그대로 복사)
saver 초기화도 동일
param_list={ 'W1':W1, 'b1':b1, 'W2':W2, 'b2':b2}
saver = tf.train.Saver( param_list )
...
sess=tf.Session()
saver.restore(sess, './savedata.ckpt')
로딩 완료. W1, b1, ... 변수들 사용 가능.



반응형


+ 자료 처리 및 많이 사용하는 함수들...

-Shape, Rank, Axis
t=tf.constant(  [1,2,3,4])
tf.shape(t).eval()
     tensor의 shape과 타입을 알수 있다.   Rank는 처음에 [의 개수로 볼 수 있음.
     array ( [4],  dtype=int32 )

t=tf.constant(  [[1,2],  [3,4] ])
tf.shape(t).eval()
     array ( [2,2],  dtype=int32 )

     축에도 번호를 매길수 있는데, 가장큰 범위부터 0으로 매김.
     2차원배열의 경우 0은 행방향, 1은 열 방향.

-Matrix 곱

tf.matmul( matrix1, matrix2)          ; Matrix 곱; 내적
matrix1*matrix2     ; 성분곱.
 ( *과 matmul은 다름. 주의!)

;Broadcasting  알아서 형을 변환하여 연산해 줌. (편하지만 주의할 필요가 있음)



-reduce_sum( input_tensor, axis=None)

axis가 없으면 총합. 축은 큰 범위에서부터 인덱스가 0임.

입력이 1차원이면 축은 의미없음. axis=0이 됨.
입력이 2차원이면
axis=0 세로방향으로 합.  (테이블 input이 있으면, 아래에 답을 쓴 것)
axis=1 가로방향으로 합. (테이블 input에서 오른쪽에 답을 단 것)
axis=-1 이면 가장 마지막 축. 2차원에서는 1이됨. 3차원에서는 2가 됨.
axis가 없으면 성분들 총합.


-reduce_mean( tensor, axis )
평균
tf.reduce_mean(x, axis=0)

-argmax  ; 최대값의 인덱스
tf.argmax(x, axis=1)

-reshape ; 텐서 재구성
t=np.array( [[[0,1,2], [3,4,5]],    [[6,7,8],[9,10,11]] ] )
tf.reshape(t, shape=[-1,3])  ; -1은 알아서 다른 성분크기에 맞게 자동조정.
[[0,1,2], [3,4,5], [6,7,8], [9,10,11]]

비슷한 함수. squeeze, expand

-onehot encoding
t=tf.one_hot(  [[0], [1], [2], [0]],  depth=3)
[ [[1, 0, 0]] , [[0,1,0]], [[0,0,1]], [[1,0,0]] ]          #주의 rank가 올라감!!!
원래의 차수로 내리려면
tf.reshape ( t, [-1, 3] )
[ [1,0,0], [0,1,0], [0,0,1], [1,0,0] ]


-타입 캐스팅
tf.cast( [1.8, 2.2], tf.int32)
tf.cast(  [True, False, 1==1, 1==0], tf.int32 )
     [1, 0, 1, 0]

-스택
x=[1,2], y=[3,4], z=[5,6]
np.stack( [x,y,z] )
          =>   [[1,2], [3,4], [5,6]]
np.stack( [x,y,z], axis=1)
          =>  [[1, 3, 5], [2,4,6]]

-ones and zeros like
tf.ones_like(x).eval()          # .eval()은 값과 타입을 출력해준다.
x의 shape과 같은데 값을 모두 1로 채움.
tf.zeros_like(x)

-Zip ; 묶어준다.
for x, y, z in zip( [1,2,3], [4,5,6], [7,8,9] ):
     print (x, y, z)   
1 4 7 
2 5 8
3 6 9
zip을 하지 않고 출력하면?
for x, y, z in ( [1,2,3], [4,5,6], [7,8,9] ):          # 또는 [[1,2,3],[4,5,6],[7,8,9]]
     print (x, y, z)   
1 2 3
4 5 6
7 8 9



반응형



+자료형

1. PlaceHolder
텐서를 저장. (핸들값). 바로 계산되지는 않는다.
input data 저장시. feed dictionary=맵핑시켜주는 역할. (입력값들로 그래프 실행시 입력할 수 있다.)

tf.placeholder(dtype, shape=None, name=None)
     데이터 타입(dtype);     tf.float32, tf....

     p1 = tf.placeholder(tf.float32, shape=(3,3))
     feeding을 해주어야 한다.

# place holder test
ph1 = tf.placeholder(tf.float32)
ph2 = tf.placeholder(tf.float32)
ph3 = tf.placeholder(tf.float32)

value1=3
value2=4
value3=5

feed_dict = {ph1:value1, ph2:value2, ph3:value3}

ph4 = ph1+ph2*ph3

result=s1.run(ph4, feed_dict)
#or  result = s1.run(ph4, {ph1:value1, ph2:value2, ph3:[2.3]})
print(result)



2. Variable (대문자V 주의!)
     weight를 저장시 사용. (그래프 계산시에 내부에서 변경되는 값들. 초기화가 필요.)
v1 = tf.Variable([1,2,3,4], dtype=tf.float32)
v2 = tf.Variable([1,2,3,4], dtype=tf.float32)
v3=v1*v2
print(v3) ; 역시 출력되지 않는다.
sess.run(v3) ; 에러 발생!
원인은 variable은 반드시 초기화가 필요하다. (weight 초기화 같이)
sess.run 전에 반드시 초기화를 돌려주어야한다. (예외, 저장된 vars restore의 경우는 안해도 됨.)
init = tf.global_variables_initializer()
sess.run(init)
또는
     sess.run( tf.global_variables_initializer())

이후부터 sess.run(v3)하면 계산이 된다.

초기화시킨 variables

weights = tf.Variable( tf.random_normal([784,200], stddev=0.35), name="weights")
또는
weights = tf.Variable( tf.truncated_normal( [None, 200] ) )

biases = tf.Variable(tf.zeros([200]), name="biases")

-변수의 값 변경assign()으로 한다.
gradient = tf.reduce_mean( (W*X-Y)*X)
descent = W-0.1*gradient
update = W.assign(descent)
sess.run(update)



3. constant
tf.zeros(shape, dtype=tf.float32, name=None)
tf.zeros_like(tensor, dtype=None, name=None, optimizer=True)
tf.ones(...)
tf.constant(value, dtype=None, shape=None, ..)

c1 = tf.zeros([3,4], tf.int32)


위 값들을 직접 print하면 객체 정보만 나오고 실제 값을 알 수 없음.
세션을 만들고 실행해 줘야 함.


4. Session   세션.
연산 그래프 묶음을 의미.
세션.run() . 세션단위로 실행. (그래프 실행)

import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
print( sess.run(hello))

세션에 입력되는 텐서는 그래프 말단 노드로 보면 된다. 앞에 있는 것을 따라서 다 실행됨.
run시에 텐서 맵핑 테이블 추가하여  placeholder와 값을 맵핑시킨다.
run의 결과로 받으면 데이터를 로딩 및 출력이 가능하다. Weight, bias 정보를 얻을 수 있다.

result = sess.run(hello)
w = sess.run(w)
b = sess.run(b)
print(result)


tensor_map={x:input_x, y_:output_y}
_,tmp_cost,acc = sess.run( [train, cost, accuracy], tensor_map)
출력이 필요없는 것은 _로 받으면 된다.


다른 출력 방법??? eval() 이용
print ("Accuracy:", accuracy.eval( session=sess, feed_dict={x:inputx, y:outputy}) )

단,  sess = InteractiveSession() 으로 디폴트 세션을 열어주어야 한다.


마지막에 세션 close를 위해서 with as 구문 사용
with tf.Session() as sess:
     sess.run(train)
자동으로 위 블록탈출시 sess.close() 됨.




반응형



+TensorFlow

machine learning 오픈소스 라이브러리. python 기반.
계산 그래프(computational graph) 를 생성하여 텐서가 흐르는 프로그램


+ 로딩
import tensorflow as tf

로딩이 안되면 tensorflow를 설치한다.



+버전 확인
tf.__version__
'1.1.0'


+텐서 (Tensor)
Rank ; 차원
여기서는 모든 자료형이 텐서다. 원래는 정적타입의 n차원 배열 or list ; 랭크값이 차원수. 1차원은 벡터, 2차원은 매트릭스, 3차원부터 텐서다.
rank 0 ; scalar 1
rank 1 ; vector [1,2,3]
rank 2 ; matrix [[1,2],[3,4]]
rank 3 ; 3-tensor [ [[1],[2]], [[3],[4]] ]
rank n ; n-tensor

Shape ; dimension number. 
rank 1 ;  shape [4]
rank 2 ;  shape [4,2]  ; 4x2 행렬
rank 3 ;  shape [3,4,5]    ; 3x4x5 행렬

DataTypes
tf.float32     ; 대부분 함수에서 디폴트 자료형임.
tf.float64
tf.int8, 16, 32, 64
tf.uint8, 16
tf.string
tf.bool
tf.complex64, 128



+ 기본 예제, 작동 확인:   hello world -> hello tensorflow

import tensorflow as tf
hello = tf.constant('Hello tensorflow!')
sess = tf.Session()
print ( sess.run(hello) )
-------------
b'Hello tensorflow!'
위와 같이 출력됨.
b는 bytes를 의미. 


------------------------------------------------------------------
+ 간단한 더하기 계산그래프 테스트

3+4를 계산하는 그래프.

import tensorflow as tf
# build graph(tensor)
node1=tf.constant(3.0, tf.float32)
node2=tf.constant(4.0)
node3 = tf.add(node1, node2)
# 위 값을 print("node1=",node1, "node2=",node2, "node3=",node3)로 출력해 봐야 주소와 타입만 찍힌다. 값을 모름.
# feed data and run graph, update vars and return.
sess = tf.Session()
print ( sess.run( [node1, node2] ) )          # node1, node2를 구하여 출력.
print ( sess.run( [node3] ) )     # node3인 계산 결과를 출력. (윗줄은 데이터 값을 확인하기 위한 디버깅용)
sess.close()



반응형

아래와 같은 함수를 x가 -500~500 까지인 샘플을 가지고, 학습하여 -1000에서 1000까지의 출력결과를 보자.

학습은 기존의 샘플에 맞는 최적화된 모델을 찾을 뿐 그것으로 미래를 예측하는 것은 이 방식으로는 한계가 있다. 주어진 범위 내에서만 가능하다. 학습된 범위 밖의 영역에서는 정확하지 않다. 물론 가까운 정도는 어느정도 맞지 않을까.

학습할 그래프.

위 그래프의 수식은 아무렇게나 만들어본 

y=sin(x/100)*500+ cos(x/27)*300 + x


# -*- coding: utf-8 -*-


'''

Created on Sat May 13 10:54:59 2017


@author: Junhee

'''


#

# complex algbra predict learning? is it possible???

# continous valued target bounded range (-1000,1000)

# not using polynomial modified input!. because I don't know

# what polynomial degree is correct. 

#



import numpy as np

import tensorflow as tf

import matplotlib.pyplot as plt

import time



bDrawFigure = True

# train yes or no

bTrain = 1

#learning_rate = 0.1


#learning_rate = 0.00001

learning_rate = 0.001

train_cnt = 4000




# unknown algbra function

def problem(x):

    y = np.sin(x/100)*500 + np.cos(x/27)*300 +x

    return y

# can u imagine? i dont know.

xrange = np.linspace(-500, 500, 1000)

y_correct = problem(xrange)



# draw graph?

if bDrawFigure:

    plt.figure()

    plt.plot(xrange, y_correct)


output_space = 2000     # tanh ; -1~1 X output_space ; output range! ; -2000~2000


                    # x domain ; -1000~1000

trainx = np.random.rand(train_cnt)*2000-1000   # training set must be shuffle!!!

trainx = trainx.reshape([-1,1])

trainy_cor = problem(trainx)

trainy_cor = trainy_cor.reshape([-1,1])



X = tf.placeholder(tf.float32, shape=[None,1])

Y = tf.placeholder(tf.float32, shape=[None,1])


# make network NN

W1 = tf.Variable(tf.random_normal([1,512]))

b1 = tf.Variable(tf.zeros([512]))

L1 = tf.nn.sigmoid(tf.matmul(X, W1)+b1)

#L1 = tf.nn.tanh(tf.matmul(X, W1)+b1) 


W2 = tf.Variable(tf.random_normal([512,1024]))

b2 = tf.Variable(tf.zeros([1024]))

L2 = tf.nn.sigmoid( tf.matmul(L1, W2)+b2) 


W3 = tf.Variable(tf.random_normal([1024,1024]))

b3 = tf.Variable(tf.zeros([1024]))

L3 = tf.nn.sigmoid( tf.matmul(L2, W3)+b3) 


W4 = tf.Variable(tf.random_normal([1024,1024]))

b4 = tf.Variable(tf.zeros([1024]))

L4 = tf.nn.sigmoid( tf.matmul(L3, W4)+b4) 


W5 = tf.Variable(tf.random_normal([1024,1]))

b5 = tf.Variable(tf.zeros([1]))

#Llast = tf.nn.tanh( tf.matmul(L4, W5)+b5) *output_space

#Llast = (tf.matmul(L4, W5)+b5) *output_space

Llast = (tf.matmul(L4, W5)+b5)


cost = tf.reduce_mean( tf.square(Llast-Y) )


train = tf.train.AdamOptimizer(learning_rate).minimize(cost)


sess = tf.Session()

sess.run( tf.global_variables_initializer())


param_list = {'W1':W1,'b1':b1,

              'W2':W2,'b2':b2,

              'W3':W3,'b3':b3,

              'W4':W4,'b4':b4,

              'W5':W5,'b5':b5,

              }

saver = tf.train.Saver(param_list)

#saver.restore(sess, './unknown_predict.ptl')    # continue train


print( "bTrain=", bTrain, " train_cnt=", train_cnt)

# train

oldtime = time.time()

if bTrain:

    for i in range(train_cnt) :

        _, _cost = sess.run( [train, cost], feed_dict={X:trainx, Y:trainy_cor})

        if i%100==(100-1):

            newtime = time.time()

            term = newtime-oldtime

            print( "train=",i," cost=",_cost, " remaintime=", ((train_cnt-i)/100+1)*term)

            oldtime=newtime

    saver.save(sess, './unknown_predict.ptl')


##########################################################

# test

saver.restore(sess, './unknown_predict.ptl')


test_cnt = 500

testx = np.random.rand(test_cnt)*1000-500  # training set must be shuffle!!!

testx = testx.reshape([-1,1])

testy_cor = problem(testx)

testy_cor = testy_cor.reshape([-1,1])

_llast = sess.run( Llast, feed_dict = { X:testx } )

testcost = np.mean( np.square(_llast-testy_cor))

print ( "cost=", testcost )

#for i in range(test_cnt):

#    print("input=", testx[i], " predict=", _llast[i], " correct=", testy_cor[i])

    

#draw compare

if bDrawFigure:

#    xrange = np.linspace(-1000, 1000, 2000)

    xrange = np.linspace(-500, 500, 1000)

    xrange = xrange.reshape(-1, 1)

    _llast2 = sess.run( Llast, feed_dict = { X:xrange } )

    xrange = xrange.reshape(-1)

    testyrange = _llast2.reshape(-1)

    plt.plot(xrange, testyrange, c='r')    

    

plt.show()



GPU로 돌려야지 안 그럼 오래걸린다.

어쨋거나 결과는 아래와 같다.



0부근에서 오차가 심하다.

학습을 오래 할수록 좋아지기는 한다.




'AI(DeepLearning)' 카테고리의 다른 글

tensorflow 강좌2. 자료형  (0) 2018.07.16
[tf] tensorflow 강좌1 로딩테스트  (0) 2018.07.16
[tf] unknown math polynomial function modeling  (0) 2017.06.01
[tf] XOR tensorflow로 학습구현  (0) 2017.05.23
[tf] XOR manual solve  (0) 2017.05.23
반응형

알 수 없는 n차 다항 함수에 근사하는 샘플데이터를 학습시켜보자.

단순한 linear regression으로는 다차항 함수의 학습이 되지 않는다.

feature 값을 x^2, x^3, .. 이런식으로 변환하여 feture들을 늘려서 학습시킨다면 가능할수도 있지만, 몇 차로 해야될지도 알 수 없고 전처리를 해야되서 예측이 어렵다.

이것을 해결하기 위해서는 deep and wide한 네트웍을 구성하여 학습을 시킨다.

단, 주의해야될 점은 바로 activation function이다. 항등함수로만 하면 아무리 네트웍을 구성해도 학습이 되지 않는다.

네트웍을 affine  계층으로만 하게되면 weighted sum을 다시 weighted sum을 하게 되므로 다중 레이어를 둔 의미가 상실되게 된다. 즉, xw+b를 다시 (xw+b)w+b가 되서 아무리 반복해도 x*w+b꼴로 표현이 가능하다. 즉, 단층레이어와 동일할 뿐이다.

activation function은 다양한 정보 표현이 가능하도록 비선형 함수들을 사용해야 한다. sigmoid, tanh, relu 등.

그리고 마지막 계층 또한 중요하다. 1/0을 판단하는 binary classification이라면 sigmoid로 하고, multinomial classfication이라면 softmax를 사용하며, 실수범위의 예측이라면???  출력값의 범위가 표현될 수 있는 function을 만든다.  학습이 잘 되냐 실패하냐거 거의 여기에 달린 것 같다.

ex) sigmoid or tanh or identity 의 값에 * 도메인크기 + bias , 

(identity는 항등함수를 말함. 즉, weighted sum 인풋이 그대로 출력되는 함수) 

몇 번 테스트해보니 sigmoid나 tanh가 적당하다. 


단, 이렇게 학습하여 예측하는 것에는 한계가 있다.

학습한 데이터의 도메인에 해당되는 범위내에서는 예측가능하나, 학습되지 않은 구간에서는 맞지 않게 된다.


# -*- coding: utf-8 -*-


'''

Created on Sat May 13 10:54:59 2017


@author: Junhee

'''


#

# complex algbra predict learning? is it possible???

# continous valued target bounded range (-1000,1000)

# not using polynomial modified input!. because I don't know

# what polynomial degree is correct. 

#



import numpy as np

import tensorflow as tf

import matplotlib.pyplot as plt

import time



bDrawFigure = True

# train yes or no

bTrain = 1

#learning_rate = 0.1

#learning_rate = 0.0001

learning_rate = 0.00001

#learning_rate = 0.1

trainset_cnt = 200

epoch_cnt = 4000

#epoch_cnt = 40000





# unknown algbra function

def problem(x):

#    y = x**2

    y = x**2-30*x

    return y

# can u imagine? i dont know.

xrange = np.linspace(0, 100, 200)

y_correct = problem(xrange)


# draw graph?

if bDrawFigure:

    plt.figure()

    plt.plot(xrange, y_correct)


output_space = 40000     # tanh ; -1~1 X output_space ; output range! ; -2000~2000


                    # x domain ; -1000~1000

trainx = np.random.rand(trainset_cnt)*100-0   # training set must be shuffle!!!

trainx = trainx.reshape([-1,1])

trainy_cor = problem(trainx)

trainy_cor = trainy_cor.reshape([-1,1])



X = tf.placeholder(tf.float32, shape=[None,1])

Y = tf.placeholder(tf.float32, shape=[None,1])


# make network NN

W1 = tf.Variable(tf.random_normal([1,512]))

b1 = tf.Variable(tf.zeros([512]))

L1 = tf.nn.sigmoid(tf.matmul(X, W1)+b1)

#L1 = tf.nn.tanh(tf.matmul(X, W1)+b1) 


W2 = tf.Variable(tf.random_normal([512,1024]))

b2 = tf.Variable(tf.zeros([1024]))

L2 = tf.nn.sigmoid( tf.matmul(L1, W2)+b2) 


W3 = tf.Variable(tf.random_normal([1024,1024]))

b3 = tf.Variable(tf.zeros([1024]))

L3 = tf.nn.sigmoid( tf.matmul(L2, W3)+b3) 


W4 = tf.Variable(tf.random_normal([1024,1024]))

b4 = tf.Variable(tf.zeros([1024]))

L4 = tf.nn.sigmoid( tf.matmul(L3, W4)+b4) 


W5 = tf.Variable(tf.random_normal([1024,1]))

b5 = tf.Variable(tf.zeros([1]))

#Llast = tf.nn.tanh( tf.matmul(L4, W5)+b5) *output_space


#good

Llast = (tf.nn.sigmoid( tf.matmul(L4, W5)+b5)) *output_space - 500


#Llast = (tf.matmul(L4, W5)+b5) *output_space


# bad... 

#Llast = (tf.matmul(L4, W5)+b5)


cost = tf.reduce_mean( tf.square(Llast-Y) )


train = tf.train.AdamOptimizer(learning_rate).minimize(cost)


sess = tf.Session()

sess.run( tf.global_variables_initializer())


param_list = {'W1':W1,'b1':b1,

              'W2':W2,'b2':b2,

              'W3':W3,'b3':b3,

              'W4':W4,'b4':b4,              

              'W5':W5,'b5':b5,

              }

saver = tf.train.Saver(param_list)

#saver.restore(sess, './unknown_predict_poly.ptl')    # continue train


print( "bTrain=", bTrain, " trainset_cnt=", trainset_cnt, " epoch=cnt", epoch_cnt)

# train

oldtime = time.time()

if bTrain:

    for i in range(epoch_cnt) :

        _, _cost = sess.run( [train, cost], feed_dict={X:trainx, Y:trainy_cor})

        if i%100==(100-1):

            newtime = time.time()

            term = newtime-oldtime

            print( "train=",i," cost=",_cost, " remaintime=", ((epoch_cnt-i)/100+1)*term)

            oldtime=newtime

    saver.save(sess, './unknown_predict_poly.ptl')


##########################################################

# test

saver.restore(sess, './unknown_predict_poly.ptl')

    

#draw compare

if bDrawFigure:

#    xrange = np.linspace(-1000, 1000, 2000)

    xrange = np.linspace(1, 200, 200)

    xrange = xrange.reshape(-1, 1)

    _llast2 = sess.run( Llast, feed_dict = { X:xrange } )

    xrange = xrange.reshape(-1)

    testyrange = _llast2.reshape(-1)

    plt.plot(xrange, testyrange, c='r')    

    

plt.show()



출력결과

bTrain= 1  trainset_cnt= 200  epoch=cnt 4000

train= 99  cost= 4.10605e+07  remaintime= 408.33133206844326

train= 199  cost= 6.47534e+06  remaintime= 374.9750850892067

train= 299  cost= 3.22122e+06  remaintime= 390.8726796555519

...

train= 3399  cost= 12447.5  remaintime= 73.77905233621597

train= 3499  cost= 12130.0  remaintime= 62.91447646141052

train= 3599  cost= 11828.8  remaintime= 51.30402812004089

train= 3699  cost= 11539.5  remaintime= 43.085111978054044

train= 3799  cost= 11257.4  remaintime= 33.96168860197067

train= 3899  cost= 10978.7  remaintime= 21.201974751949308

train= 3999  cost= 10699.7  remaintime= 11.279016330242158

INFO:tensorflow:Restoring parameters from ./unknown_predict_poly.ptl

초반에 cost가 어마어마하다. 학습이 잘 된다면 위와 같이 점점 줄어들 것이다.


임의의 다차항 함수의 샘플을 생성하여 학습한다.

y=x^2-30x 라는 함수를 배워본다. 단, 전체 실수범위에 대해서 학습은 불가능하다.

샘플의 범위는 유한하기 때문. x의 범위를 0~100까지를 학습해 본다.

학습데이터의 모습은 아래와 같다.

이를 학습하여 200까지 예측해 보면, 100~200 범위는 배우지 않았기 때문에 오차가 커진다.

그러나 학습한 범위인 0~100까지는 거의 정확하다!

최종 학습 결과.

위 그림에서 0~100 구간은 파란선과 빨간선의 거의 일치한다.


추신)

샘플에 noise를 가해주고 학습하는게 좋을 것 같다.

학습시에는 batch로 샘플데이터를 random select하게 해야 학습이 더 잘 될 것 같다. 

다른 복잡한 곡선도 테스트해 보자.


+ Recent posts