ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • chapter6. 챗봇 엔진에 필요한 딥러닝 모델
    공부/처음 배우는 딥러닝 챗봇 2023. 5. 8. 12:26
    728x90

    6.1 빠르게 케라스 정리하기

    이 장에서는 챗봇 엔진 개발에 필요한 딥러닝 모델의 간단한 이론과 구현방법을 알아볼 것

     

    케라스 : 직관적이고 사용하기 쉬움, 빠른 연구 개발에 목적, 모듈 구성이 간단->쉽게 사용가능

    신경망 모델을 구축할 수 있는 고수준 API 라이브러리

    텐서플로우의 기본 API로 채택되어 구글의 전격적인 지원받는중

    이 책에서는 텐서플로우 2.1버전의 케라스 API를 이용해 챗봇 개발에 필요한 모델을 구현할 것

     

    6.1.1 인공 신경망

    인공 신경망 : 두뇌의 신경 세포인 뉴런을 수학적으로 모방한 모델

    각 뉴런은 다른 뉴런에서 입력 신호를 받아 일정 크기 이상의 신호인지 확인

    이 때 임계치를 넘어서면 다른 뉴런으로 신호를 보내는 형태로 구성

    이렇게 연결되어 있는 뉴런에 의미있는 신호가 들어오면 그 신호에 반응하는 출력 신호를 내보내도록 구성되어 있음

     

    인공 신경망 역시 이와 동일한 방법으로 모델링

    인공신경망 뉴런에 들어온 입력값이 임계치를 넘어 활성화되면 다음 뉴런으로 출력값을 내보냄

    뉴런의 출력 수는 항상 1이며 입력 수는 해결하려는 문제에 따라 임의로 정할 수 있음

    뉴런에는 입력 개수만큼의 가중치와 1개의 편향값을 가지고 있음

    이는 뉴런의 동작 특성을 나타내는 중요한 파라미터로서 이 값들을 조정해 원하는 출력값을 만들어냄

    이런 반복적인 과정->학습

    실제 뉴런은 입력된 신호가 특정 강도 이상일 때만 다음 뉴런으로 신호를 전달

    인공 신경망의 뉴런에서도동일한 역할을 하는 영역이 있음

    f로 표시된 영역!->활성화 함수라고 부르며, 가중치 계산 결괏값 y가 최종적으로 어떤 형태의 출력값으로 내보낼비 결정

    활성화 함수에는 여러 종류가 있으며, 출력 형태에 따라 선택하면 됨

    가장 유명한 3가지 활성화 함수를 소개

    1. 스텝 함수
      • 이 함수는 그래프 모양이 계단과 같아 스텝 함수라고 부름
      • 스텝 함수는 입력값이 0보다 클때는 1로, 0이하 일때는 0으로 만듦
      • 즉, 입력값이 양수일때만 활성화
      • 결과값이 0또는 1=>입력값에 대해 판별해야하는 결과가 합/불합, True/False 등 이진 분류일 때 사용
    2. 시그모이드 함수
      • 스텝함수는 결과를 너무 극단적으로 나누기 때문에 실제로 사용하기엔 문제가 조금 있음
      • ex)0.1의 경우 0에 가깝지만 0보다 크기 때문에 무조건 1로 출력
      • 확률을 이용해서 결과를 소수점으로 표현하는 것이 훨씬 자연스럽
      • 스텝 함수에서 판단 기준이 되는 임계치 부근의 데이터를 고려하지 않는 문제를 해결하기 위해 계단 모양을 완만한 형태로 표현
      • 0에서 1까지의 출력값이 확률로 표현
      • 시그모이드 함수 특성상 신경망이 깊어질수록 최종 미분값이 0으로 수렴할수밖에 없어 학습이 잘 안됨
      • 심층 신경망으로 구현하는 경우 잘 사용하지 않음
    3. ReLU(Rectified Linear Unit)
      • 입력값이 0이상인 경우에는 기울기아 1인 직선이고, 0보다 작을 땐 결괏값이 0
      • 시그모이드 함수에 비해 연산 비용이 크지 않아 학습 속도가 빠름
      • 시그모이드 함수의 문제를 완화시키는데 효과적이라 뉴런의 활성화 함수로 많이 사용
      • 문제를 신경망 모델로 해결할 때는 1개의 뉴런만 사용하진 않음, 문제가 복잡할수록 뉴런수가 늘어나야하며 신경망의 계층도 깊어져야 함
      • 입력층+출력층=>단층 신경망/입력층+1개이상의 은닉층+출력층=>심층 신경망
      • 복잡한 문제일수록 뉴런과 은닉층 수를 늘리면 성능이 좋아진다고 알려져 있지만 계산해야하는 파라미터가 많아지면 학습비용이 올라가는 단점, 문제 난이도에 비해 은닉층이 너무 깊어지거나 뉴런수가 많은 경우에 학습이 잘 안 되는 문제도 있으니 많은 실험을 통해 최적의 결과를 내는 쪽으로 결정해야함

    해당 신경망 모델에서 입력층으로부터 출력층까지 데이터가 순방향으로 전파되는 과정을 순전파라고 함

    데이터가 순방향으로 전파될 때 현 단계 뉴런의 가중치와 전 단계 뉴런의 출력값의 곱을 입력값으로 받음

    이 값은 다시 활성화 함수를 통해 다음 뉴런으로 전파

    최종적으로 출력층에서 나온 결과값이 모델에서 예상한 결과

    최종적으로 나온 순전파 결과값과 우리가 목표하는 실제값의 차이를 오차라고 함

    성능 좋은 모델이란 결과값과 실제값의 차이가 크지 않은 모델

    즉, 오차가 작은 모델일수록 정확도가 높음

    오차가 발생했을 때 뉴런의 가중치를 어떻게 조정??

    =>가중치 조정은 순전파의 역방향으로 진행됨

    각 단계별로 만나는 뉴런의 가중치가 얼마만큼 조정되어야 오차를 줄일 수 있는지 계산해 가중치 갱신

    (편미분을 통해 오차가 줄어들 수 있는 가중치 변화 방향의 크기를 계산)

    =>역전파(back propagation)이라고 부름, 역전파를 이용해 오차를 최대한 줄일 수 있도록 가중치를 조정하는 과정

    더보기

    시그모이드 함수의 경우 학습 시 층이 깊어질수록 미분값이 0으로 수렴

    역전파 진행 시 편미분을 통해 오차가 줄어들 수 있는 가중치 변화 방향의 크기를 계산

    이 때 미분값이 0이면 가중치 변화가 생기지 않음

    즉, 가중치가 갱신되지 않아 학습이 안 되는 문제가 발생

    심층 신경망의 원활한 학습을 위해 내부 은닉층의 활성화 함수에는 ReLU를 많이 사용하며, 0~1까지 확률적인 표현을 위해 출력층에만 시그모이드 함수를 사용해 정확도를 올림

    6.1.2 딥러닝 분류 모델 만들기

    MNIST 분류 예제(사람이 손글씨로 0~9까지 숫자를 이미지화한 데이터셋)

    MNIST의 숫자 이미지는 28*28 픽셀 크기의 흑백 이미지

    총 60,000개의 학습 이미지와 10,000개의 테스트 이미지를 포함

    총 70,000개의 숫자 이미지가 실제 숫자값으로 라벨링되어 있어 분류 문제를 해결하기 위한 딥러닝 예제로 많이 사용

    import tensorflow as tf
    import matplotlib.pyplot as plt
    from tensorflow.keras.datasets import mnist
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Flatten, Dense
    
    #MNIST 데이터셋 가져오기
    (x_train, y_train), (x_text, y_text_=mnist.load_data()
    x_train, x_text = x_train/255.0, x_text/255 #데이터 정규화
    
    #tf.data를 사용하여 데이터셋을 섞고 배치 만들기
    ds= tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(10000)
    train_size=int(len(x_train)*0.7)	#학습셋:검증셋 = 7:3
    train_ds=ds.take(train)size).batch(20)
    val_ds=ds.skip(train_size).batch(20)
    
    #MNIST 분류 모델 구성
    model = Sequential()
    model.add(Flatten(input_shape=(28,28)))
    model.add(Dense(20, activation='relu'))
    model.add(Dense(20, activation='relu'))
    model.add(Dense(10, activation='softmax'))
    
    #모델 생성
    model.compile(loss='sparse_categorical_crossentropy',optimizer='sgd', metrics=['accuracy'])
    
    #모델 학습
    hist=model.fit(train_ds, validation_data=val_ds, epochs=10)
    
    #모델 평가
    print('모델 평가')
    model.evaluate(x_test, y_text)
    
    #모델 정보 출력
    model.summary()
    
    #모델 저장
    model.save('mnist_miodel.h5')
    
    #학습 결과 그래프 그리기
    fig, loss_as=plt.subplots()
    acc_ax=loss_ax.twinx()
    
    loss_ax.plot(hist.history['loss'],'y',lable='train loss')
    loss_ax.plot(hist.history['val_loss'],'r',lable='val loss')
    
    acc_ax.plot(hist.history['accuracy'],'b',label='train acc')
    acc_ax.plot(hist.history['val_accuracy'],'g',label='val acc')
    
    loss_ax.set_xlabel('epoch')
    loss_ax.set_ylabel('loss')
    acc_ax.set_ylabel('accuracy')
    
    loss_ax.legend(loc='upper left')
    acc_ax.legend(loc='lower left')
    plt.show()

    6.1.3 학습된 딥러닝 모델 사용하기

    from tensorflow.keras.datasets import mnist
    from tensorflow.keras.models import load_model
    import matplotlib.pyplot as plt
    
    #MNIST데이터 셋 가져오기
    _, (x_text, y_text) = mnist.load_data()
    x_test = x_test /255.0 #데이터 정규화
    
    #모델 불러오기
    model = load_model('mnist_model.h5')
    miodel.summary()
    model.evaluate(x_test, y_test, verbose=2)
    
    #테스트셋에서 20번째 이미지 출력
    plt.imshow(x_test[20], cmap="gray")
    plt.show()
    
    #테스트셋의 20번째 이미지 클래스 분류
    picks=20
    predict=model.predict_classes(x_text[picks])
    print("손글씨 이미지 예측값 : ", predict)

    6.2 문장 분류를 위한 CNN 모델

    CNN은 합성곱 신경망, 컴퓨터 비전 분야에서 대표적으로 사용되는 딥러닝 모델

    이미지를 분류해내는 데 좋은 성능

    자율주행 자동차 및 얼굴 인식 등 이미지를 판별해야하는 분야에서 많이 사용

    6.2.1 CNN 모델 개념

    CNN을 이해하려면 합성곱과 풀링 연산이 무엇인지 알아야 함

    1. 합성곱 연산이란 합성곱 필터로 불리는 특정 크기의 행렬을 이미지 데이터(혹은 문장 데이터) 행렬에 슬라이딩하면서 곱하고 더하는 연산을 의미(합성곱 필터=마스크, 윈도우, 커널)

    2. 필터 위치를 오른쪽으로 칸 이동해 합성곱 연산을 함

    필터 위치를 몇 칸 이동할지 결정하는 값을 스트라이드라고 함

    필터가 이미지 데이터 행렬 위를 상하좌우로 이동하는 동작을 슬라이딩이라고 함

    3. 4. 반복

    =>최종적으로 나온 결과를 특징맵이라고 부름

    합성곱 연산을 거칠때마다 필터 크기와 스트라이드값에 따라 특징맵의 크기가 작아지게 되는데, 이를 방지하기 위해 패딩을 사용

    패딩은 주로 출력 크기를 조정할 목적으로 사용, 처리된 영역은 0으로 처리

    패딩을 적용한 채 합성곱 연산을 수행하면 입력데이터와 동일한 크기로 다음 계층으로 전달 가능

     

    풀링 연산이란 합성곱 연산결과로 나온 특징맵의 크기를 줄이거나 주요한 특징을 추출하기 위해 사용하느 ㄴ연산

    최대 풀링, 평균 풀링이 있는데 주로 최대 풀링을 사용

    6.2.2 챗봇 문답 데이터 감정분류 모델 구현

    #필요한 모듈 임포트
    import pandas as pd
    import tensorflow as tf
    from tensorflow.keras import preprocessing
    from tensorflow.keras.models import Model
    from tensorflow.keras.layers import Input, Embedding, Dense, Dropout, Conv1D, GlobalMaxPool1D, concatenate
    
    #데이터 읽어오기
    train_file="./chatbot_data.csv"
    data=pd.read_csv(train_file, delimiter=',')
    features=data['Q'].tolist()
    labels=data['label'].tolist()
    
    #단어 인덱스 시퀀스 벡터
    corpus=[preprocessing.text, text_to_word_sequence(text) for text in features]
    tokenizer=preprocessing.text.Tokenizer()
    tokenizer.fit_on_texts(corpus)
    sequences=tokenizer.textx_to_sequence(corpus)
    word_index=tokenizer.word_index
    
    MAX_SEQ_LEN=15 #단어 시퀀스 벡터 크기
    padded_seqs=preprocessing.sequence.pad_sequences(sequences, maxlen=MAX_SEQ_LEN, padding='post')
    
    #학습용, 검증용, 테스트용 데이터셋 생성
    #학습셋:검증셋:테스트셋: =7:2:1
    ds= tf.dataDataset.from_tensor_slices((padded_seqs, labels))
    ds=ds.shuffle(len(features))
    
    train_size=int(len(padded_seqs)*0.7)
    val_size=int(len(padded_seqs)*0.2)
    test_size=int(len(padded_seqs)*0.1)
    
    train_ds=ds.take(train_size).batch(20)
    val_ds=ds.skip(train_size).take(val_size).batch(20)
    test_ds=ds.skip(train_size+val_size).take(test_size).batch(20)
    
    #하이퍼파라미터 설정
    dropout_prob=0.5
    EMB_SIZE=128
    EPOCH=5
    VOCAB_SIZE=len(word_index)+1	#전체 단어 수
    
    #CNN모델 정의
    input_layer=Input(shape=(MAX_SEQ_LEN,))
    embedding_layer=Embedding(VOCAB_SIZE, EMB_SIZE, input_length=MAX_SEQ_LEN)(input_layer)
    dropout_emb=Dropout(rate=dropout_prob)(embedding_layer)
    
    conv1=Conv1D(
    	filters=128,
        kernel_size=3,
        padding='valid',
        activation=tf.nn.relu)(dropout_emb)
    pool1=GlobalMaxPool1D()(conv1)
        
    conv2=Conv1D(
    	filters=128,
        kernel_size=4,
        padding='valid',
        activation=tf.nn.relu)(dropout_emb)
    pool2=GlobalMaxPool1D()(conv2)
    
    conv3=Conv1D(
    	filters=128,
        kernel_size=5,
        padding='valid',
        activation=tf.nn.relu)(dropout_emb)
    pool3=GlobalMaxPool1D()(conv3)
    
    #3,4,5-gram 이후 합치기
    concat=concatenate([pool1, pool2, pool3])
    
    hidden=Dense(128, activation=tf.nn.relu)(concat)
    dropout_hidden=Dropout(rate=dropout_prob)(hidden)
    logits=Dense(3, name='logits')(dropout_hidden)
    predictions=Dense(3, activation=tf.nn.softmax)(logtis)
    
    #모델 생성
    model=Model(inputs=input_layer, output=predictions)
    model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
    
    #모델 학습
    model.fit(train_ds, validation_data=val_ds, epochs=EPOCH, verbose=1)
    
    #모델 평가(테스트 데이터셋 이용)
    loss, accuracy = model.evaluate(test_ds, verbose=1)
    print('Accuracy : %f' %(accuracy*100))
    print('loss:%f' %(loss))
    
    #모델 저장
    model.save('cnn_model.h5')

    6.2.3 챗봇 문답 데이터 감정 분류 모델 사용

    import tensorflow as tf
    import pandas as pd
    from tensorflow.keras.models import Model, load_model
    from tensorflow.keras import import preprocessing
    
    #데이터 읽어오기
    train_file="./chatbot_data.csv"
    data=pd.read_csv(train_file, delimiter=',')
    features=data['Q'].tolist()
    labels=data['label'].tolist
    
    #단어 인덱스 시퀀스 벡터
    corpus=[preprocessing.text.text_to_word_sequence(text) for text in features]
    tokenizer=preprocessing.text.Tokenizer()
    tokenizer.fit_on_texts(corpus)
    sequences=tokenizer.texts_to_sequences(corpus)
    
    MAX_SEQ_LEN=15 #단어 시퀀스 벡터 크기
    padded_seqs=preprocessing.sequence.pad_sequences(sequences, maxlen=MAX_SEQ_LEN, padding='post')
    
    #테스트용 데이터셋 생성
    ds=tf.data.Dataset.from_tensor_slices((padded_seqs, labels))
    ds=ds.shuffle(len(features))
    test_ds=ds.take(2000).batch(20) #테스트 데이터셋
    
    #감정 분류 CNN모델 불러오기
    model=load_miodel('cnn_model.h5')
    model.summary()
    model.evaluate(test_ds, verbose=2)
    
    #테스트용 데이터셋의 10212번째 데이터 출력
    print("단어 시퀀스 : ",corpus[10212])
    print("단어 인덱스 시퀀스 : ",padded_seqs[10212])
    print("문장 분류(정답) : ", labels[10212])
    
    #테스트용 데이터셋의 10212번째 데이터 감정 예측
    picks=10212
    predict=model.predict(padded_seqs[ppicks])
    predict_class=tf.math.argmax(predict, axis=1)
    print("감정 예측 점수 : ", predict)
    print("감정 예측 클래스 : ", predict_class.numpyt())

    6.3 개체명 인식을 위한 양방향 LSTM 모델

    챗봇 엔진에 개체명 인식을 위해 사용하는 양방향 LSTM에 대해 알아봄

    LSTM은 순환 신경망 모델의 일종으로 시퀀스 또는 시계열 데이터의 패턴을 인식하는 분야에서 많이 사용

    연속적인 데이터의 패턴을 이용해 결과를 예측하므로 주로 주가 예측이나 신호 분석 및 번역 분야에서 좋은 성능을 보여줌

    6.3.1 RNN

    LSTM은 RNN모델에서 파생

    RNN은 순환 신경망으로 불리며, 앞서 배운 신경망 모델과 다르게 은닉층 노드의 출력값을 출력층과 그 다음 시점의 은닉층 노드의 입력으로 전달해 순환하는 특징을 가지고 있음

    #sin 곡선 예측 RNN 모델 사용
    
    import numpy as np
    import matplotlib.pyplot as plt
    
    from tensorflow.keras.models import Sequential
    from ensorflow.keras.layers import Flatten, Dense, LSTM, SimpleRNN
    
    #time step만큼 시퀀스 데이터 분리
    def split_sequence(sequence, step):
    	x,y=list(), list()
        
        for i in range(len(sequence)):
        	end_idx=i+step
            if end_idx>len(sequence)-1;
            	break
            
            seq_x, seq_y = sequence[i:end_idx],sequence[end_idx]
            x.append(seq_x)
            y.append(seq_y)
            
        return np.array(x), np.array(y)
    
    #sin함수 학습데이터
    x=[i for i in np.arange(start=10, wtop=10, step=0.1)]
    train_y=[np.sin(i) for i in x]
    
    #하이퍼파라미터
    n_timesteps=15
    n_fetures=1
    
    #시퀀스 나누기
    #train_x.shape=>(samples, timesteps)
    #train_y.shape=>(samples)
    train_x, train_y = split_sequence(train_y, step=n_timesteps)
    print("shape x:{} / y:{}".format(train_x.shape, train_y.shape)
    
    #RNN입력 벡터 크기를 맞추기 위해 벡터 차원 크기 변경
    #reshape from [sample,timesteps] into [samples, timesteps, features]
    train_x=train_x.reshape(train_x.shape[0],train_x.shape[1],n_fetures)
    print("train_x.shape={}".format(train_x.shape)
    print("train_y.shape={}".format(train_y.shape)
    
    #RNN모델 정의
    model=Sequential()
    model.add(SimpleRNN(units=10, return_sequences=False, input_shape=(n_timesteps, n_features)))
    model.add(Dense(1))
    model.compile(optimizer='adam',loss='mse')
    
    #모델 학습
    np.random.seed(0)
    from tensorflow.keras.callbacks import EarlyStopping
    early_stopping=EarlyStopping(monitor='loss',patience=5, mode='auto')
    history=model.fit(train_x, train_y, epochs=1000, callbacks=[early_stopping]
    
    #loss 그래프 생성
    plt.plot(history.history['loss'], lable='loss')
    plt.legend(loc="upper right")
    plot.show()
    
    #테스트 데이터셋 생성
    test_x=np.arrange(10,20,0.1)
    calc_y=np.cos(test_x) 	#테스트 정답 데이터
    
    #RNN모델 예측 및 로그 저장
    test_y=calc_y[:n_timesteps]
    for i in range(len(test_x)-n_timesteps):
    	net_input=test_y[i:i+n_timesteps]
        net_input=net_input.reshape((1,n_timesteps, n_features))
        train_y=model.predict(net_input, verbose=0)
        print(test_y.shape, train_y.shape, i, i+n_timesteps)
        test_y=np.append(test_y, train_y)
        
    #예측 결과 그래프 그리기
    plt.plot(test_x, calc_y, label="ground truth", color="orange")
    plt.plot(test_x, test_y, label="predictions", color="blue")
    
    #plt.legend(loc='upper left')
    plt.ylin(-2,2)
    plt.show()

    6.3.2 LSTM

    RNN모델은 입력 시퀀스의 시점(time step)이길어질수록 앞쪽의 데이터가 뒤쪽으로 잘 전달되지 않아 학습 능력이 떨어짐

    RNN을 다층구조로 쌓으면 입력과 출력 데이터 사이의 연관관계가 줄어들어 장기 의존성 문제가 생김

    =>LSTM(Long Short Term Memory)을 개발

    #sin 곡선 예측 LSTM 모델 사용
    
    import numpy as np
    import matplotlib.pyplot as plt
    
    from tensorflow.keras.models import Sequential
    from ensorflow.keras.layers import Flatten, Dense, LSTM
    
    #time step만큼 시퀀스 데이터 분리
    def split_sequence(sequence, step):
    	x,y=list(), list()
        
        for i in range(len(sequence)):
        	end_idx=i+step
            if end_idx>len(sequence)-1;
            	break
            
            seq_x, seq_y = sequence[i:end_idx],sequence[end_idx]
            x.append(seq_x)
            y.append(seq_y)
            
        return np.array(x), np.array(y)
    
    #sin함수 학습데이터
    x=[i for i in np.arange(start=10, wtop=10, step=0.1)]
    train_y=[np.sin(i) for i in x]
    
    #하이퍼파라미터
    n_timesteps=15
    n_fetures=1
    
    #시퀀스 나누기
    #train_x.shape=>(samples, timesteps)
    #train_y.shape=>(samples)
    train_x, train_y = split_sequence(train_y, step=n_timesteps)
    print("shape x:{} / y:{}".format(train_x.shape, train_y.shape)
    
    #LSTM입력 벡터 크기를 맞추기 위해 벡터 차원 크기 변경
    #reshape from [sample,timesteps] into [samples, timesteps, features]
    train_x=train_x.reshape(train_x.shape[0],train_x.shape[1],n_fetures)
    print("train_x.shape={}".format(train_x.shape)
    print("train_y.shape={}".format(train_y.shape)
    
    #LSTM모델 정의
    model=Sequential()
    model.add(LSTM(units=10, return_sequences=False, input_shape=(n_timesteps, n_features)))
    model.add(Dense(1))
    model.compile(optimizer='adam',loss='mse')
    
    #모델 학습
    np.random.seed(0)
    from tensorflow.keras.callbacks import EarlyStopping
    early_stopping=EarlyStopping(monitor='loss',patience=5, mode='auto')
    history=model.fit(train_x, train_y, epochs=1000, callbacks=[early_stopping]
    
    #loss 그래프 생성
    plt.plot(history.history['loss'], lable='loss')
    plt.legend(loc="upper right")
    plot.show()
    
    #테스트 데이터셋 생성
    test_x=np.arrange(10,20,0.1)
    calc_y=np.cos(test_x) 	#테스트 정답 데이터
    
    #LSTM모델 예측 및 로그 저장
    test_y=calc_y[:n_timesteps]
    for i in range(len(test_x)-n_timesteps):
    	net_input=test_y[i:i+n_timesteps]
        net_input=net_input.reshape((1,n_timesteps, n_features))
        train_y=model.predict(net_input, verbose=0)
        print(test_y.shape, train_y.shape, i, i+n_timesteps)
        test_y=np.append(test_y, train_y)
        
    #예측 결과 그래프 그리기
    plt.plot(test_x, calc_y, label="ground truth", color="orange")
    plt.plot(test_x, test_y, label="predictions", color="blue")
    
    #plt.legend(loc='upper left')
    plt.ylin(-2,2)
    plt.show()

    6.3.3 양방향 LSTM

    RNN, LSTM은 일반 신경망과 다르게 시퀀스 또는 시계열 데이터 처리에 특화되어 은닉층에서 과거의 정보를 기억할 수 있음

    순환 신경망의 구조적 특성상 데이터가 입력 순으로 처리되기 때문에 이전 시점의 정보만 활용할 수 밖에 없는 단점

    =>문장이 길어질수록 성능이 저하

    =>자연어 처리에 있어 입력 데이터의 정방향 처리만큼 역방향 처리도 중요

    양방향 LSTM(Bidirectional LSTM)은 기존 LSTM 계층에 역방향으로 처리하는 LSTM계층을 하나 더 추가해 양방향에서 문장의 패턴을 분석할 수 있도록 구성

    입력문장을 양방향에서 처리하므로 시퀀스 길이가 길어진다 하더라도 정보 손실없이 처리 가능

    #양방향 LSTM
    
    import numpy as np
    from random import random
    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import Bidirectional, LSTM, Dense, TimeDistributed
    
    #시퀀스 생성
    def get_sequence(n_timesteps):
    	#0~1 사이의 랜덤 시퀀스 생성
        X=np.array([random() for _ in range(n_timesteps)])
        
        #클래스 분류 기준
        limit=n_timesteps/4.0
        
        #누적합 시퀀스에서 클래스 결정
        #누적합 항목이 limit보다 작은 경우 0, 아닌 경우 1로 분류
        y=np.array([0 if x<limit else 1 for x in np.cumsum(X)])
        
        #LSTM입력을 윟 ㅐ3차원 텐서 형태로 변경
        X=X.reshape(1, n_timesteps,1)
        y=y.reshape(1, n_timesteps,1)
        return X, y
        
    #하이퍼파라미터 정의
    n_units=20
    n_timesteps=4
    
    #양방향 LSTM 모델 정의
    model=Sequential()
    model.add(Bidirectional(LSTM(n_units, return_sequences=True, input_shape=(n_timesteps,1))))
    model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
    
    #모델 학습
    #에포크마다 학습 데이터를 생성해서 학습
    for epoch in range(1000):
    	X, y=get)sequence(n_timesteps)
        model.fit(X,y,epochs=1, batch_size=1, verbose=2)
        
    #모델 평가
    X,y=get_sequence(n_timesteps)
    yhat=model.predict_classes(X, verbose=0)
    for i in range(n_timesteps):
    	print("실제값 :",y[0,i], "예측값 :', yhat[o,i])

    6.3.4 개체명 인식

    문장에서 각 개체의 유형을 인식하는 개체명 인식(Named Entity Recognition)에 대해 알아봄

    개체명 인식이란 문장 내에 포함된 어떤 단어가 인물, 장소, 날짜 등을 의미하는 단어인지 인식하는 것

    딥러닝 모델이나 확률 모델등을 이용해 문장에서 개체명을 인식하는 프로그램을 개체명 인식기라고 부름

    개체명 인식은 챗봇에서 문장을 정확하게 해석하기 위해 반드시 해야하는 전처리 과정

    단순한 질문 형태라면 개체명 사전을 구축해 해당 단어들과 매핑되는 개체명을 찾을 수 있음

    하지만 문장 구조가 복잡하거나 문맥에 따라 단어의 의미가 바뀐다면 딥러닝 모델을 활용해야함

    개체명 사전 구축 방식은 신조어나 사전에 포함되지 않은 단어는 처리 불가능하며 사람이 직접 사전 데이터를 관리해야하기 때문에 관리 비용이 많이 듦

    개체명 인식 모델을 만들기 위해서는 우선 BIO표기법을 알아야함

    BIO란 Beginning, Inside, Outside의 약자로 각 토큰마다 태그를 붙이기 위해 사용함

    B는 개체명이 시작되는 단어에 'B-개체명'으로 태그되며, I는 'B-개체명'과 연결되는 단어일 때 'I-개체명'으로 태그, 마지막으로 O는 개체명 이외의 모든 토큰에 태그

     

     

     

     

     

     

     

     

     

     

    '공부 > 처음 배우는 딥러닝 챗봇' 카테고리의 다른 글

    chapter5. 텍스트 유사도  (0) 2023.04.13
    chatper4. 임베딩  (0) 2023.04.13
    chapter3.토크나이징  (0) 2023.04.13

    댓글

Designed by Tistory.