Keras에서 기계 학습에 첫 도전한 기록

백엔드, 프런트 엔드를 여러가지 카지 왔지만, 기계 학습은 미도전이었습니다. 이번에는 첫 도전했으므로 기념으로 기록해 둡니다. 파이썬, numpy, tf.keras를 사용하고 있습니다.

내 사양
  • 이 Qiita 참조.
  • c나 go에 의한 통신계~백엔드 개발, flutter/dart에 의한 프런트 엔드 개발이 가능.
  • 파이썬도 상당히 접하고 있습니다.
  • 기계 학습은 GUI의 도구로 조금 만져본 적이 있다.
  • 파이썬에서의 기계 학습은 첫 도전. numpy도 사용한 적이 없었던 레벨.

  • 기계 학습 이론을 함께 공부하기 위해 "처음부터 만든 Deep Learning - 파이썬에서 배우는 딥 러닝의 이론과 구현"을 읽었습니다. 아주 좋은 책이었습니다.

    개발 환경은 PyCharm Community 2019.3입니다. Anaconda라든가는 사용하지 않고 PyCharm에 필요한 라이브러리를 읽어들여 사용하고 있습니다.

    1. 기계 학습의 과제 설정



    다음 정답 로직을 기계 학습하는 것을 목표로 합니다.
  • 교사가 있는 2치 분류 문제로 합니다.
  • 입력하는 특징량을 2개의 난수치(0 이상 1 미만)로 하고, 2개의 대소 비교에 의해 0 또는 1을 정답 라벨로 합니다.
  • 정답 라벨에 드물게 노이즈를 혼입시킵니다. (처음에는 노이즈 없음)

  • 2. 코드



    2치 분류 문제의 전형적인 코드를, 몇개의 Web 기사를 보면서 만들어 보았습니다. 상당히, 컴팩트하게 직관적으로 기술할 수 있는 것이라고 생각했습니다. Keras 대단해.
    #!/usr/bin/env python3
    
    import tensorflow as tf
    import numpy as np
    from tensorflow.keras.metrics import binary_accuracy
    import matplotlib.pyplot as plt
    
    # データセット準備
    ds_features = np.random.rand(10000, 2)  # 特徴データ
    NOISE_RATE = 0
    ds_noise = (np.random.rand(10000) > NOISE_RATE).astype(np.int) * 2 - 1  # noiseなし: 1, あり: -1
    ds_labels = (np.sign(ds_features[:, 0] - ds_features[:, 1]) * ds_noise + 1) / 2  # 正解ラベル
    
    # データセットを訓練用と検証用に分割
    SPLIT_RATE = 0.8   # 分割比率
    training_features, validation_features = np.split(ds_features, [int(len(ds_features) * SPLIT_RATE)])
    training_labels, validation_labels = np.split(ds_labels, [int(len(ds_labels) * SPLIT_RATE)])
    
    # モデル準備
    INPUT_FEATURES = ds_features.shape[1]   # 特徴量の次元
    LAYER1_NEURONS = int(INPUT_FEATURES * 1.2 + 1)   # 入力次元より少し広げる
    LAYER2_NEURONS = LAYER1_NEURONS
    LAYER3_NEURONS = LAYER1_NEURONS  # 隠れ層は3層
    OUTPUT_RESULTS = 1  # 出力は一次元
    ACTIVATION = 'tanh'
    model = tf.keras.models.Sequential([
        tf.keras.layers.Dense(input_shape=(INPUT_FEATURES,), units=LAYER1_NEURONS, activation=ACTIVATION),
        tf.keras.layers.Dense(units=LAYER2_NEURONS, activation=ACTIVATION),
        tf.keras.layers.Dense(units=LAYER3_NEURONS, activation=ACTIVATION),
        tf.keras.layers.Dense(units=OUTPUT_RESULTS, activation='sigmoid'),
    ])
    LOSS = 'binary_crossentropy'
    OPTIMIZER = tf.keras.optimizers.Adam   # 典型的な最適化手法
    LEARNING_RATE = 0.03   # 学習係数のよくある初期値
    model.compile(optimizer=OPTIMIZER(lr=LEARNING_RATE), loss=LOSS, metrics=[binary_accuracy])
    
    # 学習
    BATCH_SIZE = 30
    EPOCHS = 100
    result = model.fit(x=training_features, y=training_labels,
                       validation_data=(validation_features, validation_labels),
                       batch_size=BATCH_SIZE, epochs=EPOCHS, verbose=1)
    
    # 表示
    plt.plot(range(1, EPOCHS+1), result.history['binary_accuracy'], label="training")
    plt.plot(range(1, EPOCHS+1), result.history['val_binary_accuracy'], label="validation")
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy')
    plt.ylim(0.5, 1)
    plt.legend()
    plt.show()
    
    

    3. 결과



    여기가 학습 결과입니다. 대략 99% 정도의 정밀도에 곧바로 도달해, 과학도 하고 있지 않은 것 같습니다.



    4. 고찰



    4.1. 노이즈를 가했을 때의 거동



    NOISE_RATE = 0.2로 보았습니다. 노이즈만큼 정확도가 낮아지지만 적절한 결과에 도달했습니다.



    4.2. 무관한 더미의 특징량을 더했을 때의 거동



    노이즈를 되돌려, 특징량을 5종으로 늘려 봅니다. 5종 중 2종만 사용하여 같은 로직으로 정답 라벨을 구합니다. 즉, 특징량의 나머지 3종은, 정답과는 전혀 관계없는 더미가 됩니다.

    결과는 여기에서 다소 흔들림 폭이 커지지만 더미에 속지 않고 학습할 수 있다고 할 수 있습니다.



    4.3. 특징량의 정규화를 무너뜨렸을 때의 거동



    특징량을 2종으로 되돌립니다만, 0 이상 1 미만의 난수치를 ×1000 해 보았습니다. 결과는 학습이 일률적으로 수렴하지 않는 것처럼 보이는 것 외에 최종 에포크 근처에서 정밀도가 악화되고 있습니다.



    에포크를 늘려 확인해 보았습니다. 역시 학습이 안정되지 않은 것 같습니다.



    한편, 특징량의 평균을 어긋나고, 0 이상 1 미만의 난수치를 +1000 해 보았습니다. 결과는 정확도가 거의 0.5, 즉 이진 분류로 전혀 학습되지 않는다는 것을 발견했다.



    전체적으로, 특징량의 정규화가 중요하다는 것을 알 수 있습니다.

    좋은 웹페이지 즐겨찾기