Big Picture Machine Learning : 신경망 및 TensorFlow를 사용하여 텍스트 분류

개발자는 종종 머신 러닝을 시작하려면 먼저 알고리즘이 작동하는 방식을 알아야한다고 말합니다. 그러나 나의 경험은 그렇지 않다.

먼저 응용 프로그램의 작동 방식을 큰 그림으로 볼 수 있다고 말합니다. 일단 이것을 이해하면, 심층적으로 다이빙하고 알고리즘의 내부 작동을 탐색하는 것이 훨씬 쉬워집니다.

그렇다면 어떻게 직관을 개발하고 머신 러닝에 대한이 큰 그림 이해를 달성 할 수 있습니까? 이를 수행하는 좋은 방법은 머신 러닝 모델을 만드는 것입니다.

여전히 모든 알고리즘을 처음부터 작성하는 방법을 모른다고 가정하면 이러한 알고리즘이 모두 구현 된 라이브러리를 사용하는 것이 좋습니다. 그리고 그 라이브러리는 TensorFlow입니다.

이 기사에서는 텍스트를 카테고리로 분류하는 기계 학습 모델을 작성합니다. 다음 주제를 다룰 것입니다.

  1. TensorFlow 작동 방식
  2. 기계 학습 모델이란 무엇입니까
  3. 신경망이란?
  4. 신경망이 배우는 방법
  5. 데이터를 조작하여 신경망 입력에 전달하는 방법
  6. 모델을 실행하고 예측 결과를 얻는 방법

아마도 많은 새로운 것들을 배우게 될 것이므로 시작하겠습니다!

텐서 플로우

TensorFlow는 기계 학습을위한 오픈 소스 라이브러리로, Google이 처음 만든 것입니다. 라이브러리의 이름은 라이브러리 사용 방식을 이해하는 데 도움이됩니다. 텐서는 그래프의 노드를 통해 흐르는 다차원 배열입니다.

tf. 그래프

TensorFlow의 모든 계산은 데이터 흐름 그래프로 표시됩니다. 이 그래프에는 두 가지 요소가 있습니다.

  • 계산 단위를 나타내는 tf.Operation 세트
  • 데이터 단위를 나타내는 tf.Tensor 세트

이 모든 것이 어떻게 작동하는지 보려면이 데이터 흐름 그래프를 작성하십시오.

x + y를 계산하는 그래프

x = [1,3,6] 및 y = [1,1,1]을 정의합니다. 그래프가 tf.Tensor와 함께 작동하여 데이터 단위를 나타내면 상수 텐서를 생성합니다.

tensorflow를 tf로 가져 오기
x = tf.constant ([1,3,6])
y = tf.constant ([1,1,1])

이제 작업 단위를 정의하겠습니다.

tensorflow를 tf로 가져 오기
x = tf.constant ([1,3,6])
y = tf.constant ([1,1,1])
op = tf.add (x, y)

모든 그래프 요소가 있습니다. 이제 그래프를 작성해야합니다.

tensorflow를 tf로 가져 오기
my_graph = tf.Graph ()
my_graph.as_default () 사용 :
    x = tf.constant ([1,3,6])
    y = tf.constant ([1,1,1])
    op = tf.add (x, y)

이것이 TensorFlow 워크 플로우의 작동 방식입니다. 먼저 그래프를 만든 다음에 만 계산을 수행 할 수 있습니다 (실제로 그래프 노드를 '실행'). 그래프를 실행하려면 tf.Session을 만들어야합니다.

tf. 세션

tf.Session 객체는 Operation 객체가 실행되는 환경을 캡슐화하고 (문서에서) Tensor 객체가 평가됩니다. 이를 위해 세션에서 사용될 그래프를 정의해야합니다.

tensorflow를 tf로 가져 오기
my_graph = tf.Graph ()
tf.Session (graph = my_graph)을 sess로 사용 :
    x = tf.constant ([1,3,6])
    y = tf.constant ([1,1,1])
    op = tf.add (x, y)

작업을 실행하려면 tf.Session.run () 메서드를 사용합니다. 이 메소드는 필요한 그래프 조각을 실행하여 모든 Operation 객체를 실행하고 인수 페치에 전달 된 모든 Tensor를 평가하여 TensorFlow 계산의 '단계'를 한 번 실행합니다. 귀하의 경우 합계 작업 단계를 실행합니다.

tensorflow를 tf로 가져 오기
my_graph = tf.Graph ()
tf.Session (graph = my_graph)을 sess로 사용 :
    x = tf.constant ([1,3,6])
    y = tf.constant ([1,1,1])
    op = tf.add (x, y)
    결과 = sess.run (fetches = op)
    인쇄 (결과)
>>> [2 4 7]

예측 모델

이제 TensorFlow의 작동 방식을 알았으므로 예측 모델을 작성하는 방법을 배워야합니다. 한마디로

머신 러닝 알고리즘 + 데이터 = 예측 모델

모델을 구성하는 프로세스는 다음과 같습니다.

예측 모델을 만드는 프로세스

보시다시피이 모델은 데이터를 이용한 '훈련 된'기계 학습 알고리즘으로 구성됩니다. 모델이 있으면 다음과 같은 결과를 얻을 수 있습니다.

예측 워크 플로우

만들 모델의 목표는 텍스트를 범주별로 분류하는 것입니다.

입력 : 텍스트, 결과 : 카테고리

모든 텍스트에 레이블이 지정된 교육 데이터 세트가 있습니다 (모든 텍스트에는 해당 범주에 속하는 레이블이 있습니다). 기계 학습에서 이러한 유형의 작업은 감독 학습으로 표시됩니다.

우리는 정답을 알고 있습니다. 알고리즘은 훈련 데이터를 반복적으로 예측하고 교사가 수정합니다.”— Jason Brownlee

데이터를 카테고리로 분류하므로 분류 작업이기도합니다.

모델을 만들기 위해 신경망을 사용할 것입니다.

신경망

신경망은 계산 모델 (수학적 언어와 수학적 개념을 사용하여 시스템을 설명하는 방법)입니다. 이러한 시스템은 명시 적으로 프로그래밍되지 않고 자체 학습 및 교육을받습니다.

신경망은 중추 신경계에서 영감을 얻었습니다. 그들은 우리의 뉴런과 비슷한 노드를 연결했습니다.

신경망

퍼셉트론은 최초의 신경망 알고리즘이었습니다. 이 기사는 퍼셉트론의 내부 작업에 대해 잘 설명합니다 (“인공 뉴런 내부”애니메이션은 환상적입니다).

신경망 작동 방식을 이해하기 위해 실제로 TensorFlow를 사용하여 신경망 아키텍처를 구축합니다. 이 예제에서는 Aymeric Damien이이 아키텍처를 사용했습니다.

신경망 아키텍처

신경망에는 숨겨진 레이어가 2 개 있습니다 (네트워크에 몇 개의 숨겨진 레이어가 있는지 선택해야 함). 숨겨진 각 레이어의 역할은 입력을 출력 레이어가 사용할 수있는 것으로 변환하는 것입니다.

숨겨진 레이어 1

입력 레이어 및 첫 번째 숨겨진 레이어

또한 첫 번째 숨겨진 레이어의 노드 수를 정의해야합니다. 이 노드는 특징 또는 뉴런이라고도하며 위 이미지에서 각 원으로 표시됩니다.

입력 계층에서 모든 노드는 데이터 세트의 단어에 해당합니다 (나중에 어떻게 작동하는지 볼 것입니다).

여기에 설명 된대로 각 노드 (뉴런)에 가중치를 곱합니다. 모든 노드에는 가중치 값이 있으며 훈련 단계에서 신경망은 올바른 출력을 생성하기 위해 이러한 값을 조정합니다 (잠깐, 우리는 이것에 대해 1 분 안에 자세히 배울 것입니다).

각 입력 노드에 가중치를 곱하는 것 외에도 네트워크는 바이어스 (신경 네트워크의 바이어스 역할)를 추가합니다.

아키텍처에서 입력에 가중치를 곱한 후 값을 바이어스에 합산하면 데이터도 활성화 함수를 통과합니다. 이 활성화 기능은 각 노드의 최종 출력을 정의합니다. 유추 : 각 노드가 램프라고 상상해보십시오. 활성화 기능은 램프가 켜지는지 여부를 알려줍니다.

활성화 기능에는 여러 가지 유형이 있습니다. 정류 된 선형 단위 (ReLu)를 사용합니다. 이 기능은 다음과 같이 정의됩니다.

f (x) = max (0, x) [출력이 x 또는 0 (영) 중 큰 값)

예 : ifx = -1, f (x) = 0 (영); x = 0.7이면 f (x) = 0.7입니다.

숨겨진 레이어 2

두 번째 숨겨진 레이어는 첫 번째 숨겨진 레이어의 기능을 수행하지만 이제 두 번째 숨겨진 레이어의 입력은 첫 번째 숨겨진 레이어의 출력입니다.

첫 번째 및 두 번째 숨겨진 레이어

출력 레이어

그리고 마지막 레이어 인 출력 레이어에 도달했습니다. one-hot 인코딩을 사용하여이 레이어의 결과를 얻습니다. 이 인코딩에서 한 비트 만 값 1을 가지며 다른 모든 비트는 0 값을 갖습니다. 예를 들어, 세 가지 범주 (스포츠, 우주 및 컴퓨터 그래픽)를 인코딩하려는 경우 :

+ ------------------- + ----------- +
| 카테고리 | 가치 |
+ ------------------- | ----------- +
| 스포츠 | 001 |
| 우주 | 010 |
| 컴퓨터 그래픽 | 100 |
| ------------------- | ----------- |

따라서 출력 노드 수는 입력 데이터 집합의 클래스 수입니다.

출력 레이어 값에도 가중치가 곱해지고 바이어스도 추가되지만 이제 활성화 기능이 다릅니다.

각 텍스트에 카테고리로 레이블을 지정하려고하며 이들 카테고리는 상호 배타적입니다 (텍스트는 동시에 두 카테고리에 속하지 않음). 이를 고려하여 ReLu 활성화 기능을 사용하는 대신 Softmax 기능을 사용하십시오. 이 함수는 각 단위의 출력을 0과 1 사이의 값으로 변환하고 모든 단위의 합이 1과 같은지 확인합니다. 이렇게하면 출력이 각 범주에 대한 각 텍스트의 확률을 알려줍니다.

| 1.2 0.46 |
| 0.9-> [소프트 맥스]-> 0.34 |
| 0.4 0.20 |

이제 신경망의 데이터 흐름 그래프가 있습니다. 지금까지 본 모든 것을 코드로 변환하면 결과는 다음과 같습니다.

# 네트워크 매개 변수
n_hidden_1 = 10 # 기능의 첫 번째 레이어 수
n_hidden_2 = 5 # 피처의 두 번째 레이어 수
n_input = total_words # 단어
n_classes = 3 # 카테고리 : 그래픽, 공간 및 야구
데프 multilayer_perceptron (입력 텐서, 가중치, 바이어스) :
    layer_1_multiplication = tf.matmul (입력 센서, 가중치 [ 'h1'])
    layer_1_addition = tf.add (layer_1_multiplication, biases [ 'b1'])
    layer_1_activation = tf.nn.relu (layer_1_addition)
RELU 활성화가있는 숨겨진 계층
    layer_2_multiplication = tf.matmul (layer_1_activation, weights [ 'h2'])
    layer_2_addition = tf.add (layer_2_multiplication, biases [ 'b2'])
    layer_2_activation = tf.nn.relu (layer_2_addition)
# 선형 활성화가있는 출력 레이어
    out_layer_multiplication = tf.matmul (layer_2_activation, 가중치 [ 'out'])
    out_layer_addition = out_layer_multiplication + 바이어스 [ 'out']
out_layer_addition을 반환

(나중에 출력 레이어 활성화 기능의 코드에 대해 이야기하겠습니다.)

신경망이 배우는 방법

앞에서 보았 듯이 무게 값은 네트워크가 훈련되는 동안 업데이트됩니다. 이제 TensorFlow 환경에서 어떻게 이런 일이 발생하는지 살펴 보겠습니다.

tf. 가변

가중치와 바이어스는 변수 (tf.Variable)에 저장됩니다. 이러한 변수는 run () 호출 동안 그래프에서 상태를 유지합니다. 기계 학습에서는 보통 정규 분포를 통해 가중치 및 바이어스 값을 시작합니다.

가중치 = {
    'h1': tf.Variable (tf.random_normal ([n_input, n_hidden_1])),
    'h2': tf.Variable (tf.random_normal ([n_hidden_1, n_hidden_2])),
    'out': tf.Variable (tf.random_normal ([n_hidden_2, n_classes]))
}
치우침 = {
    'b1': tf.Variable (tf.random_normal ([n_hidden_1])),
    'b2': tf.Variable (tf.random_normal ([n_hidden_2])),
    'out': tf.Variable (tf.random_normal ([n_classes]))
}

네트워크를 처음 실행할 때 (즉, 가중치는 정규 분포에 의해 정의 된 가중치입니다) :

입력 값 : x
무게 : w
편견 : b
출력값 : z
예상 값 : 예상

네트워크가 학습 중인지 여부를 확인하려면 출력 값 (z)을 예상 값 (예상)과 비교해야합니다. 이 차이를 어떻게 계산합니까 (손실)? 이를 수행하는 방법에는 여러 가지가 있습니다. 분류 작업을 수행하고 있기 때문에 손실을 측정하는 가장 좋은 방법은 교차 엔트로피 오류입니다.

James D. McCaffrey는 이것이 왜 이런 종류의 작업에 가장 좋은 방법인지에 대한 훌륭한 설명을 썼습니다.

TensorFlow를 사용하면 tf.nn.softmax_cross_entropy_with_logits () 메소드 (여기서는 softmax 활성화 함수)를 사용하여 교차 엔트로피 오류를 계산하고 평균 오류 (tf.reduce_mean ())를 계산합니다.

# 구축 모델
예측 = multilayer_perceptron (입력 텐서, 가중치, 바이어스)
# 손실 정의
entropy_loss = tf.nn.softmax_cross_entropy_with_logits (logits = 예측, labels = output_tensor)
손실 = tf.reduce_mean (엔트로피 _ 손실)

출력 오류 (우리가 얻은 값과 올바른 값의 차이)를 최소화하기 위해 가중치와 바이어스에 가장 적합한 값을 찾고 싶습니다. 이를 위해 기울기 하강 방법을 사용합니다. 더 구체적으로, 확률 적 경사 하강을 사용합니다.

그라데이션 하강. 출처 : https://sebastianraschka.com/faq/docs/closed-form-vs-gd.html

그라디언트 디센트를 계산하는 알고리즘도 많이 있으므로 Adaptive Moment Estimation (Adam)을 사용합니다. TensorFlow에서이 알고리즘을 사용하려면 learning_rate 값을 전달해야합니다.이 값은 최상의 가중치 값을 찾기 위해 값의 증분 단계를 결정합니다.

tf.train.AdamOptimizer (learning_rate) .minimize (loss) 메소드는 다음 두 가지 작업을 수행하는 구문 설탕입니다.

  1. compute_gradients (손실, <변수 목록>)
  2. apply_gradients (<변수 목록>)

이 메소드는 모든 tf.Variable을 새로운 값으로 업데이트하므로 변수 목록을 전달할 필요가 없습니다. 이제 네트워크를 훈련시키는 코드가 있습니다 :

learning_rate = 0.001
# 구축 모델
예측 = multilayer_perceptron (입력 텐서, 가중치, 바이어스)
# 손실 정의
entropy_loss = tf.nn.softmax_cross_entropy_with_logits (logits = 예측, labels = output_tensor)
손실 = tf.reduce_mean (엔트로피 _ 손실)
옵티 마이저 = tf.train.AdamOptimizer (learning_rate = learning_rate). 최소화 (손실)

데이터 조작

사용할 데이터 세트에는 영어로 된 많은 텍스트가 있으며이 데이터를 조작하여 신경망으로 전달해야합니다. 그렇게하려면 다음 두 가지를 수행하십시오.

  1. 각 단어에 대한 색인 작성
  2. 각 텍스트에 대한 행렬을 만듭니다. 여기서 단어가 텍스트에 있으면 값은 1이고 그렇지 않으면 0입니다.

이 과정을 이해하는 코드를 보자.

numpy를 np로 가져 오기 #numpy는 과학 컴퓨팅 용 패키지입니다
컬렉션 수입 카운터에서
vocab = 카운터 ()
text = "브라질 안녕하세요"
# 모든 단어를 얻으십시오
text.split ( '')의 단어 :
    vocab [word] + = 1
        
# 단어를 색인으로 변환
데프 get_word_2_index (vocab) :
    word2index = {}
    i, enumerate (vocab)의 단어 :
        word2index [word] = 나는
        
    return word2index
# 이제 색인이 있습니다
word2index = get_word_2_index (vocab)
total_words = len (vocab)
# 이것은 우리가 numpy 배열 (행렬)을 만드는 방법입니다
행렬 = np.zeros ((total_words), dtype = float)
# 이제 값을 채 웁니다
text.split ()의 단어 :
    행렬 [word2index [word]] + = 1
인쇄 (매트릭스)
>>> [1. 1. 1.]

위의 예에서 텍스트는 '브라질 출신'이고 매트릭스는 [1. 1. 1.]입니다. 텍스트가 '안녕'이라면?

행렬 = np.zeros ((total_words), dtype = float)
텍스트 = "안녕하세요"
text.split ()의 단어 :
    행렬 [word2index [word.lower ()]] + = 1
인쇄 (매트릭스)
>>> [1. 0. 0.]

레이블 (텍스트 범주)과 동일하지만 이제 원-핫 인코딩을 사용합니다.

y = np.zeros ((3), dtype = float)
category == 0 인 경우 :
    y [0] = 1. # [1. 0. 0.]
elif 카테고리 == 1 :
    y [1] = 1. # [0. 1. 0.]
그밖에:
     y [2] = 1. # [0. 0. 1.]

그래프를 실행하고 결과 얻기

이제 가장 좋은 부분은 모델에서 결과를 얻는 것입니다. 먼저 입력 데이터 세트를 자세히 살펴 보겠습니다.

데이터 세트

20 개의 주제에 대해 18.000 개의 게시물이있는 데이터 세트 인 20 개의 뉴스 그룹을 사용합니다. 이 데이터 세트를로드하려면 scikit-learn 라이브러리를 사용합니다. comp.graphics, sci.space 및 rec.sport.baseball의 3 가지 범주 만 사용합니다. scikit-learn에는 교육용과 테스트 용의 두 가지 하위 세트가 있습니다. 권장 사항은 테스트 데이터를 보지 말아야한다는 것입니다. 모델을 만드는 동안 선택에 방해가 될 수 있습니다. 이 특정 테스트 데이터를 예측하기 위해 모델을 작성하지 않고 일반화가 잘 된 모델을 작성하려고합니다.

데이터 세트를로드하는 방법은 다음과 같습니다.

sklearn.datasets에서 가져 오기 fetch_20newsgroups
categories = [ "comp.graphics", "sci.space", "rec.sport.baseball"]
newsgroups_train = fetch_20newsgroups (subset = 'train', 카테고리 = 카테고리)
newsgroups_test = fetch_20newsgroups (subset = 'test', categories = 카테고리)

모델 훈련

신경망 용어에서, 모든 훈련 예의 하나의 에포크 (epoch) = 하나의 순방향 패스 (출력 값 얻기) 및 하나의 역방향 패스 (가중치 업데이트).

tf.Session.run () 메소드를 기억하십니까? 자세히 살펴 보겠습니다.

tf.Session.run (가져 오기, feed_dict = 없음, 옵션 = 없음, run_metadata = 없음)

이 기사의 시작 부분의 데이터 흐름 그래프에서 합계 작업을 사용했지만 실행할 항목 목록을 전달할 수도 있습니다. 이 신경망 실행에서는 손실 계산과 최적화 단계의 두 가지를 전달합니다.

feed_dict 매개 변수는 각 실행 단계에 대한 데이터를 전달하는 위치입니다. 이 데이터를 전달하려면 feed_dict를 제공하기 위해 tf.placeholders를 정의해야합니다.

TensorFlow 설명서에 따르면

“자리 표시자는 피드의 대상으로 만 존재합니다. 초기화되지 않았으며 데이터가 없습니다.”— 소스

따라서 다음과 같이 자리 표시자를 정의합니다.

n_input = total_words # 단어
n_classes = 3 # 카테고리 : 그래픽, 공상 과학 및 야구
input_tensor = tf.placeholder (tf.float32, [없음, n_input], name = "input")
output_tensor = tf.placeholder (tf.float32, [없음, n_classes], name = "출력")

훈련 데이터를 배치별로 분리합니다.

“입력 공급에 자리 표시자를 사용하는 경우 tf.placeholder (…, shape = [None,…])로 자리 표시자를 만들어 가변 배치 차원을 지정할 수 있습니다. 모양의 없음 요소는 가변 크기 치수에 해당합니다.”— 소스

모델을 테스트하는 동안 큰 배치를 사용하여 dict에 피드를 제공하므로 가변 배치 차원을 정의해야합니다.

get_batches () 함수는 배치 크기를 가진 텍스트 수를 제공합니다. 이제 모델을 실행할 수 있습니다.

training_epochs = 10
# 그래프를 시작
tf.Session ()을 sess로 사용 :
    sess.run (init) # 변수를 초기화합니다 (정규 분포, 기억합니까?)
    # 훈련주기
    범위 내 에포크 (training_epochs)의 경우 :
        평균 비용 = 0
        total_batch = int (len (newsgroups_train.data) / batch_size)
        # 모든 배치에 루프
        범위 (total_batch)의 i의 경우 :
            batch_x, batch_y = get_batch (newsgroups_train, i, batch_size)
            # 최적화 운영 (백프로 프) 및 비용 운영 (손실 가치를 얻기 위해)
            c, _ = sess.run ([loss, optimizer], feed_dict = {입력 _tensor : batch_x, output_tensor : batch_y})

이제 모델이 훈련되었습니다. 테스트하려면 그래프 요소도 만들어야합니다. 모델의 정확도를 측정하므로 예측 값의 인덱스와 올바른 값의 인덱스를 가져와야합니다 (원핫 인코딩을 사용하기 때문에). 모든 테스트 데이터 세트 :

    # 테스트 모델
    index_prediction = tf.argmax (예측, 1)
    index_correct = tf.argmax (출력 _tensor, 1)
    correct_prediction = tf.equal (인덱스 예측, index_correct)
    # 정확도 계산
    정확도 = tf.reduce_mean (tf.cast (correct_prediction, "float"))
    total_test_data = len (newsgroups_test.target)
    batch_x_test, batch_y_test = get_batch (newsgroups_test, 0, total_test_data)
    print ( "정확도 :", 정확도 .eval ({input_tensor : batch_x_test, output_tensor : batch_y_test}))
>>> Epoch : 0001 손실 = 1133.908114347
    획기 : 0002 손실 = 329.093700409
    획기 : 0003 손실 = 111.876660109
    획기 : 0004 손실 = 72.552971845
    획기 : 0005 손실 = 16.673050320
    획기 : 0006 손실 = 16.481995190
    획기 : 0007 손실 = 4.848220565
    획기 : 0008 손실 = 0.759822878
    획기 : 0009 손실 = 0.000000000
    획기 : 0010 손실 = 0.079848485
    최적화 완료!
    정확도 : 0.75

그리고 그게 다야! 신경망을 사용하여 텍스트를 범주로 분류하는 모델을 만들었습니다. 축하합니다!

최종 코드가있는 노트북을 여기에서 볼 수 있습니다.

팁 : 변경 사항이 훈련 시간 및 모델 정확도에 미치는 영향을 확인하기 위해 정의한 값을 수정하십시오.

질문이나 제안? 의견에 남겨 두십시오. 아, 읽어 주셔서 감사합니다!

이 기사가 도움이 되었습니까? 매월 심도있는 다이브 기사를 작성하기 위해 최선을 다하고 있습니다. 새로운 기사를 게시 할 때 이메일을받을 수 있습니다.

을 클릭하고 친구들과 공유하면 큰 의미가 있습니다. 데이터 과학 및 기계 학습에 대한 추가 기사를 보려면 저를 따르십시오.