[카테고리:] 생활코딩

  • keras로 키워드 분석(4/5)

    대박이다!! 1,000회를 돌렸는데 0.87 정확도를 보였는데, verb까지 검사하니 0.93에서 시작한다!! kkma가 동사로 끝나는 명사형 단어를 동사로 인식한다!!

    사용자 입력을 받아들여 단어를 분석하는 부분을 아래와 같이 했다.

    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    from keras.layers import Dense, Flatten, SimpleRNN, Dropout
    from keras.models import Sequential
    from keras.preprocessing.sequence import pad_sequences
    from keras.layers.embeddings import Embedding
    from keras.utils import to_categorical
    import numpy as np
    from sklearn.cluster import KMeans
    
    def main():
        model=Word2Vec.load('./TagWord2VecModel')
        print(model)
        MAX_VOCAB=len(model.wv.vocab)
        WV_SIZE=model.wv.vectors.shape[1]
        WORD_MAX=6
        CATEGORIY_SIZE=7
        print("로드한 모델 vocab 최대값은", MAX_VOCAB)
        print("로드한 모델 vectror 크기는", WV_SIZE)
        #단어 표시
        showWord2VecClusters(Model=model)
    
        #keras 모델 설정.
        model2= Sequential()
        model2.add(Embedding(input_dim=MAX_VOCAB, output_dim=WV_SIZE, input_length=WORD_MAX, weights=[model.wv.vectors], trainable=False))
        #model2.add(Flatten())
        model2.add(SimpleRNN(256, input_shape=(4,4)))
        model2.add(Dropout(0.2))
        model2.add(Dense(128))
        model2.add(Dropout(0.2))
        model2.add(Dense(64, activation='relu'))
        model2.add(Dropout(0.2))
        model2.add(Dense(CATEGORIY_SIZE, activation='softmax'))
    
        #load model 경로.
        weight_path = "./saved_network_weight.h5"
        model2.load_weights(weight_path)
        print("저장된 weights를 불름")
        model2.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
        model2.summary()
        checkSentenceWord(Model=model)
        userInput(Word2Vec=model, Networks=model2, Maxword=WORD_MAX)
    
    
    def showWord2VecClusters(Model):
        #현재 입력된 단어 표시
        #클러스터링 사용.
        word_vectors = Model.wv.syn0 # 어휘의 feature vector
        num_clusters = int(word_vectors.shape[0]/50) # 어휘 크기의 1/5나 평균 5단어
        print(num_clusters)
        num_clusters = int(num_clusters)
    
        kmeans_clustering = KMeans(n_clusters=num_clusters)
        idx = kmeans_clustering.fit_predict(word_vectors)
    
        idx = list(idx)
        names = Model.wv.index2word
        word_centroid_map = {names[i]: idx[i] for i in range(len(names))}
    
    
        for c in range(num_clusters):
            # 클러스터 번호를 출력
            print("\ncluster {}".format(c))
    
            words = []
            cluster_values = list(word_centroid_map.values())
            for i in range(len(cluster_values)):
                if (cluster_values[i] == c):
                    words.append(list(word_centroid_map.keys())[i])
            print(words)
    
    
    
    def userInput(Word2Vec, Networks, Maxword):
        EndFlag=False
        while True:
            #사용자 입력 확인
            ErrorFlag=False
            ZeroFlag=False
            wordToPredictSentence = []
            wordToPredictSentenceStr = []
            index = 0
            #총 MAX개수만큼 입력을 받아들이고, 
            #단어를 판단
            # 인덱스를 증가하지 말지 판단하기 위해 while루프 사용
            #print("WORD_MAX는",Maxword)
            while (index < Maxword):
            #for index in range(Maxword):
                print("%d/6 단어 입력"%(index+1))
                print("끝내려면 END!!를 입력")
                print("마지막까지 0을 채우려면 ZERO!!를 입력")
                if(not ZeroFlag):
                    userInput=input()
                #input_predict =model.wv.vocab.get(word[0]).index
                #print(repr(userInput))
    
                if(userInput == "END!!"):
                    EndFlag=True
                    break
                if(userInput == "ZERO!!"):
                    ZeroFlag=True
    
                try:
                    #Try에서 에러플래그를 다시 초기화
                    ErrorFlag=False
                    num = Word2Vec.wv.vocab.get(userInput).index
                    print(num)
                except AttributeError:
                    if(not ZeroFlag):
                        print("리스트에 없는 단어 입력함. 다시 입력하세요")
                        ErrorFlag=True
    
                #전에 정확하게 입력했는지 확인
                if(ErrorFlag == True):
                    continue
                else:
                    index=index+1
                    if(not ZeroFlag):
                        wordToPredictSentence.append(num)
                        wordToPredictSentenceStr.append(userInput)
                        print(wordToPredictSentence)
                    else:
                        wordToPredictSentence.append(0)
                        wordToPredictSentenceStr.append(userInput)
                        print(wordToPredictSentence)
    
                #input_predict = np.asarray([[num0, num1, num2, 0, 0, 0]])
                input_predict = np.asarray([wordToPredictSentence])
                #print("input_predict 는",input_predict.shape)
            if(EndFlag == False):
                print("입력한 단어는",wordToPredictSentenceStr)
                myPrediction = Networks.predict_classes(input_predict, batch_size=100, verbose=0)
                myPredictionAcc = Networks.predict(input_predict, batch_size=100, verbose=0)
                print("내 예상", myPrediction, "확률", myPredictionAcc)
            else:
                #while 루프 탈출.
                break
    
    
    def checkSentenceWord(Model):
        print(Model)
        sample_sentence="B220ST YD5 CLAMP 잠김"
        tokenlist = okt.pos(sample_sentence, stem=True, norm=True)
        for word in tokenlist:
            print(word)
    
    
    if __name__=="__main__":
        main()
    

    네트웍은 LSTM을 복잡한 형식으로 썼다. 네트웍 구조가 json으로, 웨이트가 h5로 저장된다. 나중에 네트웍 구조를 json으로 저장하고, json으로 부르는 부분으로 수정해야 겠다.

    위에 “B220ST YD5 CLAMP 잠김”을 분석하면 아래로 분석한다.

    ('B', 'Alpha')
    ('220', 'Number')
    ('ST', 'Alpha')
    ('YD', 'Alpha')
    ('5', 'Number')
    ('CLAMP', 'Alpha')
    ('잠기다', 'Verb')
    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    from keras.layers import Dense, Flatten, SimpleRNN, Dropout, LSTM
    from keras.models import Sequential
    from keras.preprocessing.sequence import pad_sequences
    from keras.layers.embeddings import Embedding
    from keras.utils import to_categorical
    from keras.optimizers import Adam
    import numpy as np
    #label encoder로 text를 int로 변경.
    from sklearn.preprocessing import LabelEncoder
    #model save
    from keras.callbacks import ModelCheckpoint
    
    
    targetFile = open("./tag정리.txt", "r", encoding='UTF-8')
    #lines=targetFile.readline()
    #model=Word2Vec.load('./myModelV1')
    model=Word2Vec.load('./TagWord2VecModel')
    
    MAX_VOCAB=len(model.wv.vocab)
    WV_SIZE=model.wv.vectors.shape[1]
    print("로드한 모델 vocab 최대값은", MAX_VOCAB)
    print("로드한 모델 vectror 크기는", WV_SIZE)
    
    i=0
    sentence_by_index=[]
    training_result=[]
    result=[]
    WORD_MAX=16
    
    
    while True:
    
        lines = targetFile.readline()
        firstColumn = lines.split(',')
        #print(lines)
        
        if not lines:break
        #if i == 1000:break
        i=i+1
        #word2vec를 만든 형태소 분석기를 사용..
        tokenlist = okt.pos(firstColumn[1], stem=True, norm=True)
        temp=[]
    
        for word in tokenlist:
            #word[0]은 단어.
            #word[1]은 품사.
            #print("word[0]은",word[0])
            #print("word[1]은",word[1])
    
            if word[1] in ["Noun","Alpha","Number","Verb"]:
                #temp.append(model.wv[word[0]])
                #word[0]를 index로 변경.
                #단어장에 없는 단어를 예외처리
                #입력과 출력을 같이 맞추기 위해, 입출력 동시에 append
                try:
                    #print("---------")
                    #print(i)
                    #print(word[0])
                    temp.append(model.wv.vocab.get(word[0]).index)
                    #print(model.wv.vocab.get(word[0]).index)
    
                except AttributeError:
                    #값을 못찾으면 0값 입력
                    temp.append(0)
                    #print(temp)
        #print("index is ", i)
        #print("temp is", temp)
    
        #가져단 쓴 코드는 temp에 값이 있을 경우에만 append.
        #출력과 맞추기 위해, list가 비어있어도 append로 변경.
        #if temp:
        #    sentence_by_index.append(temp)
        sentence_by_index.append(temp)
    
        #결과를 배열로 입력
        tempResult=firstColumn[2].strip('\n')
        training_result.append(tempResult)
    
    
    targetFile.close()
    #print(tokenlist)
    
    #출력을 categorical로 변경.
    
    label_encoder = LabelEncoder()
    training_result_asarray = np.asarray(training_result)
    integer_encoded = label_encoder.fit_transform(training_result_asarray)
    categorical_training_result = to_categorical(integer_encoded, dtype='int')
    
    #입력, 출력 확인
    fixed_sentence_by_index = pad_sequences(sentence_by_index, maxlen=WORD_MAX, padding='post', dtype='int')
    #print("입력은",fixed_sentence_by_index)
    #print("출력은",integer_encoded)
    #print("출력은",categorical_training_result)
    size_categorical_training_result = categorical_training_result.shape[1]
    print("출력 크기는",size_categorical_training_result)
    
    #keras 모델 설정.
    model2= Sequential()
    model2.add(Embedding(input_dim=MAX_VOCAB, output_dim=WV_SIZE, input_length=WORD_MAX, weights=[model.wv.vectors], trainable=False))
    #model2.add(Flatten())
    model2.add(LSTM(1024, input_shape=(4,4)))
    model2.add(Dropout(0.2))
    model2.add(Dense(512))
    model2.add(Dropout(0.2))
    model2.add(Dense(256, activation='relu'))
    model2.add(Dropout(0.2))
    model2.add(Dense(size_categorical_training_result, activation='softmax'))
    model2.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.001, epsilon=1e-08, decay=0.0), metrics=['accuracy'])
    
    #save model 경로.
    weight_path = "./saved_network_weight.h5"
    checkpoint = ModelCheckpoint(weight_path, monitor='acc', verbose=2, save_best_only=True, mode='auto') 
    callbacks_list = [checkpoint]
    
    model2.fit(x=fixed_sentence_by_index, y=categorical_training_result, epochs=1000, verbose=2, validation_split=0.2, callbacks=callbacks_list, batch_size=200)
    model2.summary()

    로 분석하면, 대충 아래와 같다.

    로드한 모델 vocab 최대값은 694
    로드한 모델 vectror 크기는 10
    출력 크기는 7
    Train on 7602 samples, validate on 1901 samples
    Epoch 1/1000
     - 7s - loss: 1.0435 - acc: 0.5389 - val_loss: 1.7584 - val_acc: 0.7564
    
    Epoch 00001: acc improved from -inf to 0.53894, saving model to ./saved_network_weight.h5
    Epoch 2/1000
     - 3s - loss: 0.4565 - acc: 0.8172 - val_loss: 2.1145 - val_acc: 0.7480
    
    Epoch 00002: acc improved from 0.53894 to 0.81715, saving model to ./saved_network_weight.h5
    Epoch 3/1000
     - 3s - loss: 0.4405 - acc: 0.8508 - val_loss: 2.5999 - val_acc: 0.7575
    
    Epoch 00003: acc improved from 0.81715 to 0.85083, saving model to ./saved_network_weight.h5
    Epoch 4/1000
     - 3s - loss: 0.2354 - acc: 0.9100 - val_loss: 2.1261 - val_acc: 0.7475
    
    Epoch 00004: acc improved from 0.85083 to 0.91002, saving model to ./saved_network_weight.h5
    Epoch 5/1000
     - 3s - loss: 0.1733 - acc: 0.9323 - val_loss: 2.2204 - val_acc: 0.7522
    
    Epoch 00005: acc improved from 0.91002 to 0.93225, saving model to ./saved_network_weight.h5
    Epoch 6/1000
     - 3s - loss: 0.2758 - acc: 0.9025 - val_loss: 3.7245 - val_acc: 0.7543
  • keras로 키워드 분석(3/5)

    과거 acc를 못 올리는 이유를 알아보았다. 둘 중 하나를 선택하는 문제는 activation softmax대신 sigmoid를 사용해야 한다. 아래로 고치고 1,000번 학습시켰다. 최고값을 찾은 weight를 파일로 저장했다. 147번 학습해보니 0.99?? 정확도를 보이나, vlaidation 체크용은 0.87대 정확도를 보인다.

    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    from keras.layers import Dense, Flatten, SimpleRNN
    from keras.models import Sequential
    from keras.preprocessing.sequence import pad_sequences
    from keras.layers.embeddings import Embedding
    import numpy as np
    
    #model save
    from keras.callbacks import ModelCheckpoint
    
    model=Word2Vec.load('./myModel')
    MAX_VOCAB=len(model.wv.vocab)
    WV_SIZE=model.wv.vectors.shape[1]
    print("로드한 모델 vocab 최대값은", MAX_VOCAB)
    print("로드한 모델 vectror 크기는", WV_SIZE)
    
    #b=model.wv.most_similar(positive=["클램프", "잠김"])
    print(model)
    
    #print(model.wv["후드힌지시프트"])
    
    #tokenizer 설정.
    #Okt()사용.
    
    targetFile = open("./tagv4태그붙인파일.csv", "r", encoding='UTF-8')
    
    i=0
    sentence_by_index=[]
    traing_result=[]
    WORD_MAX=6
    #WV_SIZE=10
    #model을 load후 최대값 확인
    #MAX_VOCAB=3532
    
    #못찾은 단어를 입력하기 위한 부분.
    #삭제.
    #VACANT_ARRAY = np.zeros((4,1))
    
    
    while True:
    
        lines = targetFile.readline()
        firstColumn = lines.split(',')
        #print(lines)
    
        if not lines:break
        #if i == 1000:break
        i=i+1
        #word2vec를 만든 형태소 분석기를 사용..
        tokenlist = okt.pos(firstColumn[1], stem=True, norm=True)
        temp=[]
    
        for word in tokenlist:
            #word[0]은 단어.
            #word[1]은 품사.
            #print("word[0]은",word[0])
            #print("word[1]은",word[1])
    
            if word[1] in ["Noun","Alpha","Number"]:
                #temp.append(model.wv[word[0]])
                #word[0]를 index로 변경.
                #단어장에 없는 단어를 예외처리
                #입력과 출력을 같이 맞추기 위해, 입출력 동시에 append
                try:
                    #print("---------")
                    #print(i)
                    #print(word[0])
                    temp.append(model.wv.vocab.get(word[0]).index)
                    #print(model.wv.vocab.get(word[0]).index)
    
                except AttributeError:
                    #값을 못찾으면 0값 입력
                    temp.append(0)
                    #print(temp)
        #print("index is ", i)
        #print("temp is", temp)
    
        #가져단 쓴 코드는 temp에 값이 있을 경우에만 append.
        #출력과 맞추기 위해, list가 비어있어도 append로 변경.
        #if temp:
        #    sentence_by_index.append(temp)
        sentence_by_index.append(temp)
    
        #결과를 배열로 입력
        tempResult=firstColumn[4].strip('\n')
        traing_result.append(tempResult)
    
    targetFile.close()
    training_result_asarray = np.asarray(traing_result)
    
    #최대 단어를 6으로 설정.
    #행 수보다 6까지 뒤쪽으로 0을 채움.
    #word2Vec가 실수이므로 float32로 설정
    #result가 embedding_matrix
    fixed_sentence_by_index = pad_sequences(sentence_by_index, maxlen=WORD_MAX, padding='post', dtype='int')
    print("입력 시퀀스는", fixed_sentence_by_index.shape)
    print("출력 시퀀스는", training_result_asarray.shape)
    #print("index로 변경한 값은",fixed_sentence_by_index)
    #print("embedding vector는", model.wv.vectors)
    
    #keras 모델 설정.
    model2= Sequential()
    model2.add(Embedding(input_dim=MAX_VOCAB, output_dim=WV_SIZE, input_length=WORD_MAX, weights=[model.wv.vectors], trainable=False))
    #model2.add(Flatten())
    model2.add(SimpleRNN(128, input_shape=(4,4)))
    model2.add(Dense(1, activation='sigmoid'))
    model2.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    
    #save model 경로.
    weight_path = "./saved_network_weight.h5"
    checkpoint = ModelCheckpoint(weight_path, monitor='acc', verbose=2, save_best_only=True, mode='auto')
    callbacks_list = [checkpoint]
    
    model2.fit(x=fixed_sentence_by_index, y=training_result_asarray, epochs=10, verbose=1, validation_split=0.2, callbacks=callbacks_list)
    model2.summary()
    
    
    #input_predict =model.wv.vocab.get(word[0]).index
    num0 = model.wv.vocab.get("B").index
    num1 = model.wv.vocab.get("180").index
    num2 = model.wv.vocab.get("셔틀").index
    num3 = model.wv.vocab.get("불간섭").index
    
    input_predict = np.asarray([[num0, num1, num2, num3, 0, 0]])
    #print("input_predict 는",input_predict.shape)
    myPrediction = model2.predict_classes(input_predict, batch_size=10, verbose=1)
    myPredictionAcc = model2.predict(input_predict, batch_size=10, verbose=1)
    print("내 예상", myPrediction,  "with ", myPredictionAcc)
    

    1,000회 하는데 4~5시간정도 걸린 듯 하다. 그러나 불행하게도 weight는 초기에 한번 업데이트하고 말아버렸다. 그래도 이렇게 간단한 구조인데도 87%를 유지하니 좀 파보면 나아질 듯 하다.

    이제 입력을 받아들여 이를 판정하는 부분을 만들어 보자.

  • keras로 키워드 분석(2/5)

    keras로 키워드 분석(2/5)

    keras가 지원하는 embedding을 어떻게 사용하는지 몰랐다. keras가 제공하는 문서가 embedding 기능을 정확히 설명한다.

    https://keras.io/layers/embeddings/#embedding

    weight로 embedding_matrix를 입력하고, input으로 index를 입력하면 index를 vector로 변경한다. 따라서 아래와 같은 순서로 작업해야 한다.

    1. 미리 만든 word2vec 파일을 불러온다.
    2. 전체 vocab 총 양을 embedding_matrix로 설정한다.
    3. konlpy로 각 태그를 분리한다.
    4. 불러온 word2vec 파일에서 해당하는 단어 index를 구하고, 이를 문장으로 만든다.
    5. 적절한 길이로 padding한다.
    6. 이를 입력으로 먹인다.

    대충 어떻게 할 지 감 잡았으니, 이제 다시 삽질을 시작하자.

    다시 아래와 같이 작성했다. 일단 네트웍을 fit으로 훈련시킬 수 있는지 없는지 확인했다. 일단 된다. 모든 입력과 출력을 정확하게 읽었고, 2진 분류기로 만들었다. embedding도 제대로 되는 듯 하다.

    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    from keras.layers import Dense, Flatten
    from keras.models import Sequential
    from keras.preprocessing.sequence import pad_sequences
    from keras.layers.embeddings import Embedding
    import numpy as np
    
    model=Word2Vec.load('./myModel')
    #b=model.wv.most_similar(positive=["클램프", "잠김"])
    print(model)
    
    #print(model.wv["후드힌지시프트"])
    
    #tokenizer 설정.
    #Okt()사용.
    
    targetFile = open("./tagv4태그붙인파일.csv", "r", encoding='UTF-8')
    
    i=0
    sentence_by_index=[]
    traing_result=[]
    WORD_MAX=6
    WV_SIZE=4
    MAX_VOCAB=3532
    
    #못찾은 단어를 입력하기 위한 부분.
    VACANT_ARRAY = np.zeros((4,1))
    
    
    while True:
    
        lines = targetFile.readline()
        firstColumn = lines.split(',')
        #print(lines)
        
        if not lines:break
        #if i == 1000:break
        i=i+1
        #word2vec를 만든 형태소 분석기를 사용..
        tokenlist = okt.pos(firstColumn[1], stem=True, norm=True)
        temp=[]
    
        for word in tokenlist:
            #word[0]은 단어.
            #word[1]은 품사.
            #print("word[0]은",word[0])
            #print("word[1]은",word[1])
    
            if word[1] in ["Noun","Alpha","Number"]:
                #temp.append(model.wv[word[0]])
                #word[0]를 index로 변경.
                #단어장에 없는 단어를 예외처리
                #입력과 출력을 같이 맞추기 위해, 입출력 동시에 append
                try:
                    #print("---------")
                    #print(i)
                    #print(word[0])
                    temp.append(model.wv.vocab.get(word[0]).index)
                    #print(model.wv.vocab.get(word[0]).index)
    
                except AttributeError:
                    #값을 못찾으면 0값 입력
                    temp.append(0)
                    #print(temp)
        #print("index is ", i)
        #print("temp is", temp)
    
        #가져단 쓴 코드는 temp에 값이 있을 경우에만 append.
        #출력과 맞추기 위해, list가 비어있어도 append로 변경.
        #if temp:
        #    sentence_by_index.append(temp)
        sentence_by_index.append(temp)
    
        #결과를 배열로 입력
        tempResult=firstColumn[4].strip('\n')
        traing_result.append(tempResult)
    
    targetFile.close()
    training_result_asarray = np.asarray(traing_result)
    
    #최대 단어를 6으로 설정.
    #행 수보다 6까지 뒤쪽으로 0을 채움.
    #word2Vec가 실수이므로 float32로 설정
    #result가 embedding_matrix
    fixed_sentence_by_index = pad_sequences(sentence_by_index, maxlen=WORD_MAX, padding='post', dtype='int')
    print("입력 시퀀스는", fixed_sentence_by_index.shape)
    print("출력 시퀀스는", training_result_asarray.shape)
    #print("index로 변경한 값은",fixed_sentence_by_index)
    #print("embedding vector는", model.wv.vectors)
    
    #keras 모델 설정.
    model2= Sequential()
    model2.add(Embedding(input_dim=MAX_VOCAB, output_dim=4, input_length=WORD_MAX, weights=[model.wv.vectors], trainable=False))
    model2.add(Flatten())
    model2.add(Dense(1, activation='softmax'))
    model2.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    model2.fit(x=fixed_sentence_by_index, y=training_result_asarray, epochs=1000, verbose=1, validation_split=0.2)
    
    model2.summary()

    네트웍을 조금 복잡하게 하고, gtx1060 gpu로 1000번 훈련 시켰다.

    root@AMD-1804:/home/mnt/konlpy_190910_moved# python tagCheckerv3.py 
    /usr/local/lib/python3.5/dist-packages/jpype/_core.py:210: UserWarning: 
    -------------------------------------------------------------------------------
    Deprecated: convertStrings was not specified when starting the JVM. The default
    behavior in JPype will be False starting in JPype 0.8. The recommended setting
    for new code is convertStrings=False.  The legacy value of True was assumed for
    this session. If you are a user of an application that reported this warning,
    please file a ticket with the developer.
    -------------------------------------------------------------------------------
    
      """)
    Using TensorFlow backend.
    Word2Vec(vocab=3532, size=4, alpha=0.025)
    2019-09-11 11:02:33.941682: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties: 
    name: GeForce GTX 1060 6GB major: 6 minor: 1 memoryClockRate(GHz): 1.7085
    pciBusID: 0000:01:00.0
    totalMemory: 5.93GiB freeMemory: 5.38GiB
    2019-09-11 11:02:33.941740: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0
    2019-09-11 11:02:34.356140: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix:
    2019-09-11 11:02:34.356206: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988]      0 
    2019-09-11 11:02:34.356217: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0:   N 
    2019-09-11 11:02:34.356473: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 5138 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1060 6GB, pci bus id: 0000:01:00.0, compute capability: 6.1)
    Train on 77696 samples, validate on 19424 samples
    Epoch 1/1000
    77696/77696 [==============================] - 19s 248us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 2/1000
    77696/77696 [==============================] - 18s 238us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 3/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 4/1000
    77696/77696 [==============================] - 19s 239us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 5/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 6/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 7/1000
    77696/77696 [==============================] - 18s 238us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 8/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 9/1000
    77696/77696 [==============================] - 19s 243us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 10/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 11/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 12/1000
    77696/77696 [==============================] - 18s 238us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 13/1000
    77696/77696 [==============================] - 18s 238us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 14/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 15/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 16/1000
    77696/77696 [==============================] - 19s 242us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 17/1000
    77696/77696 [==============================] - 19s 242us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 18/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 19/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 20/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 21/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 22/1000
    77696/77696 [==============================] - 19s 242us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 23/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 24/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 25/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 26/1000
    77696/77696 [==============================] - 19s 239us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 27/1000
    77696/77696 [==============================] - 19s 242us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 28/1000
    77696/77696 [==============================] - 19s 243us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 29/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 30/1000
    77696/77696 [==============================] - 19s 240us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 31/1000
    77696/77696 [==============================] - 18s 237us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325
    Epoch 32/1000
    77696/77696 [==============================] - 19s 241us/step - loss: 11.2624 - acc: 0.2936 - val_loss: 12.2350 - val_acc: 0.2325

    acc와 loss가 변할 조짐이 없다. 다음에는 네트웍을 조금 복잡하게 해보고 다시 훈련시켜야겠다.

  • keras로 키워드 분석(1/5)

    keras로 키워드 분석(1/5)

    인공지능으로 자연어 분석을 많이한다. 나도 남 따라 해보기로 했다. 조금씩 배워하므로 코드는 별거 없지만 많은 시간을 쓰고있다. 생각은 이렇다.

    1. 나는 설비 태그를 가지고 있다. 사람마다 태그 작성을 다르게 한다. 이렇게 되면 일관성없어 분석하기 어렵다. 이를 표준화? – 적어도 형식에 벗어난 태그를 찾기위해 – 하는 무엇인가 있으면 좋겠다.
    2. 태그를 준비한다. 한글+영어로 구성된다.
    3. 간단한 분류기를 구성한다. 처음과 끝 단어를 기준으로 OK, NG를 임의로 넣는다.
    4. 한글을 사용하여 형태소를 기준으로 자른다. konlpy로 태그를 자른다.
    5. 핫한 word2vec를 활용한다.
    6. 내 맘대로 네트웍을 구성하여 학습하고 결과를 본다.

    일단 word2vec를 만들었다. 인터넷에 이 유명한 word2vec 대한 설명을 쉽게 찾는다. 이론은 그렇다치고, 응용을 어떻게할지 확인했다. https://wikidocs.net/book/2155 를 그대로 참조했다.

    태그를 word2vec에서 사용한 vector로 나타내야 한다. 인터넷에 위키피디아 등 방대한 문서로 학습한 word2vec를 구할 수 있고, 쉽게 적용할 수 있다. 그러나 내가 가진 태그는 이쪽 업계 자의적, 단축 단어로 이뤄졌다. 예를 들어 차종, 절환 등 일본어 비슷한 단어를 주로 사용한다. 이 단어는 표준어도 아니고, 심지어 위키피디아에서 사용하지 않는다. 이를 구분하려면 사용자 정의 사전에 입력해야 한다. 인터넷 능력자의 도움으로 명사로 추가했다. 위 링크 핵심은 1. 사용할 형태소 분석기 압축을 푼다. 2. 사전 파일에 단어를 추가한다. 3. 다시 jar로 압축한다. 이다.

    다시 konlpy로 단어, 숫자,영어로 분리한다. 아래 코드의 word[0]은 단어이고, word[1]은 품사 정도 된다.

    이제 분리한 단어를 word2vec 함수로 vector를 만들어 파일로 저장한다. 아래 코드는 인터넷에서 구했고 나는 정말 조금만 수정했다.

    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    
    targetFile = open("./tagv4태그붙인파일.csv", "r", encoding='UTF-8')
    #lines=targetFile.readline()
    
    i=0
    result=[]
    while True:
    
        lines = targetFile.readline()
        firstColumn = lines.split(',')
        #print(lines)
        #print(lines[0])
        #print(firstColumn[1])
        #print(firstColumn[4])
        #firstColumn[4]가 마지막 OK, NG 플래그
    
        #if not lines:break
        #1000라인에서 쉽게 끊기 위해 넣어줌.
        if i == 1000:
            break
        #print(lines)
        i=i+1
        if i%1000 == 0:
            print("%d번째 while문"%i)
        tokenlist = okt.pos(firstColumn[1], stem=True, norm=True)
        temp=[]
    
        for word in tokenlist:
            if word[1] in ["Noun","Alpha","Number"]:
                temp.append((word[0]))
        if temp:
            result.append(temp)
    
    #    print(result)
    targetFile.close()
    #print(result[100:])
    print(result)
    #print(tokenlist)
    
    model=Word2Vec(sentences=result, size=200, window=4, min_count=2, workers=6, sg=0, iter=100)
    
    model.save('myModel')
    a=model.wv.most_similar("센서")
    print(a)
    """
    sent_text = sent_tokenize(lines)
    
    normalized_text = []
    for string in sent_text:
        tokens = re.sub(r"[^a-z0-9]+", " ", string.lower())
        normalized_text.append(tokens)
    
    result=[]
    result=[word_tokenize(sentence) for sentence in normalized_text]
    
    #print(result)
    
    #print(lines)
    model=Word2Vec(sentences=result, size=100, window=5, min_count=3, workers=6, sg=0, iter=10000)
    print(model)
    
    a=model.wv.most_similar("you")
    #print(model['man'])
    print(a)
    #print(normalized_text)
    
    #print(result[:10])
    """

    이제 vector를 불러와 keras로 학습을 시켜야 한다. rnn이나 lstm 이런 모듈을 사용할 예정이다. 학습할 입력을 vector 형식으로 네트웍에 집어 넣어야하는데, embedding으로 쉽게 사용할 수 있는 듯 하다. 입력으로 넣기 위해 크기를 일정하게 맞춰야한다. pad_sequences로 쉽게 가능하다. 다만 dtype=’float32’로 소수점 버림을 막아준다.

    pad_sequences를 적용하기 전에는 스트링으로 인식하는데, 이 후에 바로 vector로 바꿔준다. 어디까지 해줄 지 모르겠으나, 이 부분을 직접 입력으로 넣어도 될 듯 하다. vector 크기를 100으로 했는데 너무 크게 잡은 듯 하다. 나중에 줄여야겠다.

    중간에 실재 6개(내가 정한 최대값)로 일치되는지와 각 단어를 vector로 print로 뽑았다. 역시 word2vec를 만든 형태소 분석기를 그대로 사용했다.

    from konlpy.tag import Okt
    okt=Okt()
    from gensim.models import Word2Vec
    from keras.layers import Dense, LSTM, Dropout
    from keras.models import Sequential
    from keras.preprocessing.text import Tokenizer
    from keras.preprocessing.sequence import pad_sequences
    import numpy as np
    
    model=Word2Vec.load('./myModel')
    #b=model.wv.most_similar(positive=["클램프", "잠김"])
    print(model)
    
    #tokenizer 설정.
    #Okt()사용.
    
    targetFile = open("./tagv4태그붙인파일.csv", "r", encoding='UTF-8')
    
    i=0
    result=[]
    WORD_MAX=10
    WV_SIZE=200
    blankArray = np.zeros(WV_SIZE)
    while True:
    
        lines = targetFile.readline()
        firstColumn = lines.split(',')
        if i == 100:
            break
        i=i+1
        #word2vec를 만든 형태소 분석기를 사용..
        tokenlist = okt.pos(firstColumn[1], stem=True, norm=True)
        temp=[]
    
        for word in tokenlist:
            #word[0]은 단어.
            #word[1]은 품사.
            #print("word[0]은",word[0])
            #print("word[1]은",word[1])
    
            if word[1] in ["Noun","Alpha","Number"]:
                temp.append(model.wv[word[0]])
    
        if temp:
            result.append(temp)
    targetFile.close()
    
    #최대 단어를 6으로 설정.
    #행 수보다 6까지 뒤쪽으로 0을 채움.
    #word2Vec가 실수이므로 float32로 설정
    fixed_result = pad_sequences(result, maxlen=6, padding='post', dtype='float32')
    
    
    #정확하게 입력되어 있는지 테스트하는 부분.
    print(len(fixed_result))
    j=0
    while True:
        print("여기가 시작")
        print(len(fixed_result[j]))
        #print(fixed_result[j][0].shape)
        print(result[j])
        #print(fixed_result[j])
        print(fixed_result[j][0])
        print(fixed_result[j][1])
        print(fixed_result[j][2])
        print(fixed_result[j][3])
        print(fixed_result[j][4])
        print(fixed_result[j][5])
    
        j=j+1
    
        if j == 100:
            break;
    #print(result[0][0])
    #print(result[0][1])
    
    #b1=model.wv[result[0][0]]
    #b2=model.wv[result[0][1]]
    #print(b1)
    #print(b2)
    #keras 모델 설정.
    model = Sequential()
    Dense(100, input_dim=200, kernel_initializer='uniform', activation='relu')
    Dense(2, input_dim=100, activation='softmax')
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    

    이 후는 나중에 계속 해야된다.

  • cmus+sshfd로 유선 스피커 무선 개조

    cmus+sshfd로 유선 스피커 무선 개조

    쓸모없이 자리만 차지하고 있던 PC 부품 모아 쓸만한 스트리밍 박스를 만들었다. 어쩌다보니 잘 쓰고있던 PC 스피커를 여기에 붙였다. 이 유선 스피커는 가격은 싼데 성능은 괜찮다. 몇년전 블루투스 보세 스피커를 20만원에 구입했지만 비싸단 생각을 계속했고, 값싼 스피커와 차이나지 않는다. 보세 스피커는 크기도 작고 한 개인데, 싸구려 스피커는 두 개에다 크다. 게다가 배터리 걱정도 없다. 보세 스피커는 캠핑용인데, 한번도 가본적 없다. 요 놀고있는 가성비 높은 스피커를 네트웍에 붙이기로 했다.

    난 서버에 음악을 몽땅 넣어놓고 사용한다. Plex를 서버에서 굴리는데 정말 괜찮다. 스마트폰에서는 Plex App으로 서버 파일을 스트리밍으로 듣는다. 일반 PC에서는 웹 브라우저로 접속하여 음악을 들을 수 있다. 처음에는 스마트폰 앱을 만들어 구형 스피커에 접속된 PC 웹 브라우저를 직접 제어하려 했다. 그런데 Plex 개발사는 이런 API를 제공하지 않았다. 많이 찾았지만 결국 못찾았다. 누군가 CLI 앱을 만들었지만 사용할 수 없었다. 결국 Plex로 어떻게 하는 방법을 포기했다.

    콘솔에서 실행할 수 있는 음악 재생기를 찾았다. PC에 ssh로 접속하여 음악 재생기를 실행하면 PC 스피커로 출력되기 때문이다. xhost도 찾았는데 요놈은 내가 접속한 PC쪽에 출력을 내보낸다. 역시 인터넷에 능력자가 많다. 이 사람이 만든 CLI 플레이어 cmus를 활용하기로 했다. 예상대로 ssh로 접속하면 PC쪽 스피커로 출력된다.

    구매 비용을 아끼다보니 PC에 SSD를 붙였지만 용량이 작다. 내 기억으론 10GB도 안되는 중고 하드디스크를 구했었다. 음악 파일이 꽤 용량이 나가는데 PC로 매번 내다 들을 음악을 받기 귀찮다. 이 문제를 해결하려다 보니 ssh로 네트웍 스토리지를 접속하여 마치 내 하드디스크인양 사용 가능한 sshfs를 찾았다. 리눅스 만세다.

    매 부팅 때 mount하게 fstab을 수정한다. 아래는 기본 문법인데 사용하려면 좀 수정해야 한다.

    userNameHere@FQDN_OR_IP_HERE:/path/to/source/  /local/mountdir/  fuse.sshfs  defaults,_netdev  0  0

    ssh로 연결할 때 login 패스워드를 않넣기 위해서는 key chain 로그인으로 변경해야 한다. 이 방법을 사용하면 보안도 강화된다. fstab에 설정하려면 private key 위치를 지정해야 한다. allow_other를 넣어줘야 uid, gid를 제대로 잡나보다. 서버쪽에 cmus쪽 id를 새로 만들었는데, sshfs로 연결하면 mount한 디렉토리를 쓸 수 있다.ㅠㅠ. ro 옵션을 넣어준다. 대략 아래와 같이 /etc/fatab을 정했다.

    "유저"@"도메인 이름":/"서버 디렉토리" "/클라이언트 디렉토리" fuse.sshfs defaults,_netdev,IdentityFile="개인키 위치",uid=1000,gid=1000,allow_other,delay_connect,ro 0 0

    의지만 좀 있다면 유선 스피커 5만원, 라스베리 파이 4만원, 케이스 2만원. 약 10만원이면 하드웨어를 만들 수 있겠다.

    KT가 설치한 공유기를 사용하는데, 여기에 PC를 물리다보니 외부에서 접속되지 않는다. IP도 접속 때마다 변경되는 듯 하다. 관리자로 접속하여 설정할 수 있을 듯한데 ID, 비밀번호를 몰라 들어가지 못한다. 나중에 시간되면 고객센터에 물어 좀 건드려봐야겠다.

    와이파이로 접속, 실행 후 터미널을 깨도 다음 실행된다. 그러나 외부 주소로 접속하여 터미널을 깨면 pulseaudio를 재생할 수 없는 문제가 있다. 외부 주소로 하려면 screen으로 세션을 유지해야 한다.