1. 소개

이 기사에서는 머신 러닝을위한 현대적이고 강력한 도구 인 deeplearning4j (dl4j) 라이브러리를 사용하여 간단한 신경망을 생성합니다 .

시작하기 전에이 가이드는 선형 대수, 통계, 기계 학습 이론 및 잘 기반을 갖춘 ML 엔지니어에게 필요한 기타 많은 주제에 대한 깊은 지식을 요구하지 않습니다.

2. 딥 러닝이란 무엇입니까?

신경망은 상호 연결된 노드 계층으로 구성된 계산 모델입니다.

노드는 숫자 데이터의 뉴런과 유사한 프로세서입니다. 입력에서 데이터를 가져 와서 이러한 데이터에 가중치와 함수를 적용하고 결과를 출력으로 보냅니다. 이러한 네트워크는 소스 데이터의 몇 가지 예를 사용하여 학습 할 수 있습니다.

훈련은 본질적으로 노드에서 나중에 계산에 영향을 미치는 일부 숫자 상태 (가중치)를 저장하는 것입니다. 학습 예에는 이러한 항목의 기능 및 알려진 특정 클래스가 포함 된 데이터 항목이 포함될 수 있습니다 (예 : "이 16x16 픽셀 세트에는 손으로 쓴 문자"a "가 포함되어 있음).

훈련이 완료된 후 신경망 은 이전에 이러한 특정 데이터 항목을 본 적이 없더라도 새로운 데이터에서 정보를 추출 할 수 있습니다 . 잘 모델링되고 잘 훈련 된 네트워크는 이미지, 손으로 쓴 편지, 음성을 인식하고 통계 데이터를 처리하여 비즈니스 인텔리전스에 대한 결과를 생성하는 등의 작업을 수행 할 수 있습니다.

최근 몇 년 동안 고성능 병렬 컴퓨팅의 발전으로 심층 신경망이 가능해졌습니다. 이러한 네트워크 는 여러 중간 (또는 숨겨진 ) 레이어 로 구성 된다는 점에서 단순한 신경망과 다릅니다 . 이 구조를 통해 네트워크는 훨씬 더 복잡한 방식 (재귀 적, 반복적, 컨볼 루션 방식 등)으로 데이터를 처리하고 더 많은 정보를 추출 할 수 있습니다.

3. 프로젝트 설정

라이브러리를 사용하려면 최소한 Java 7이 필요합니다. 또한 일부 기본 구성 요소로 인해 64 비트 JVM 버전에서만 작동합니다.

가이드를 시작하기 전에 요구 사항이 충족되는지 확인하겠습니다.

$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

먼저 Maven pom.xml 파일에 필요한 라이브러리를 추가하겠습니다 . 라이브러리 버전을 속성 항목으로 추출합니다 (최신 버전의 라이브러리는 Maven Central 저장소를 확인하세요 ).

<properties>
    <dl4j.version>0.9.1</dl4j.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.nd4j</groupId>
        <artifactId>nd4j-native-platform</artifactId>
        <version>${dl4j.version}</version>
    </dependency>

    <dependency>
        <groupId>org.deeplearning4j</groupId>
        <artifactId>deeplearning4j-core</artifactId>
        <version>${dl4j.version}</version>
    </dependency>
</dependencies>

참고 nd4j 네이티브 플랫폼 의존성이 가능한 여러 구현 중 하나입니다.

다양한 플랫폼 (macOS, Windows, Linux, Android 등)에서 사용할 수있는 기본 라이브러리에 의존합니다. CUDA 프로그래밍 모델을 지원하는 그래픽 카드에서 계산을 실행 하려면 백엔드를 nd4j-cuda-8.0-platform으로 전환 할 수도 있습니다.

4. 데이터 준비

4.1. 데이터 세트 파일 준비

우리는 기계 학습의“Hello World”( 붓꽃 데이터 세트의 분류)를 작성할 것 입니다 . 이것은 다른 종 ( Iris setosa , Iris versicolor , Iris virginica ) 의 꽃에서 수집 된 데이터 세트입니다 .

이 종은 꽃잎과 꽃받침의 길이와 너비가 다릅니다. 입력 데이터 항목을 분류하는 정확한 알고리즘을 작성하는 것은 어려울 것입니다 (즉, 특정 꽃이 어떤 종에 속하는지 결정). 하지만 잘 훈련 된 신경망은 실수없이 빠르게 분류 할 수 있습니다.

이 데이터의 CSV 버전을 사용할 것입니다. 여기서 열 0..3에는 종의 다양한 기능이 포함되고 열 4에는 레코드 클래스 또는 값 0, 1 또는 2로 코딩 된 종이 포함됩니다.

5.1,3.5,1.4,0.2,0
4.9,3.0,1.4,0.2,0
4.7,3.2,1.3,0.2,0
7.0,3.2,4.7,1.4,1
6.4,3.2,4.5,1.5,1
6.9,3.1,4.9,1.5,1

4.2. 데이터 벡터화 및 읽기

신경망은 숫자로 작동하기 때문에 클래스를 숫자로 인코딩합니다. 실제 데이터 항목을 일련의 숫자 (벡터)로 변환하는 것을 벡터화라고 합니다. deeplearning4j 는이를 위해 datavec 라이브러리를 사용합니다 .

먼저이 라이브러리를 사용하여 벡터화 된 데이터가있는 파일을 입력 해 보겠습니다. CSVRecordReader를 만들 때 건너 뛸 줄 수 (예 : 파일에 헤더 줄이있는 경우)와 구분 기호 (이 경우 쉼표)를 지정할 수 있습니다.

try (RecordReader recordReader = new CSVRecordReader(0, ',')) {
    recordReader.initialize(new FileSplit(
      new ClassPathResource("iris.txt").getFile()));

    // …
}

레코드를 반복하기 위해 DataSetIterator 인터페이스 의 여러 구현 중 하나를 사용할 수 있습니다 . 데이터 세트는 상당히 방대 할 수 있으며 값을 페이징하거나 캐시하는 기능이 유용 할 수 있습니다.

그러나 우리의 작은 데이터 세트에는 150 개의 레코드 만 포함되어 있으므로 iterator.next ()를 호출하여 한 번에 모든 데이터를 메모리로 읽어 보겠습니다 .

또한 우리의 경우 기능 개수 (4) 및 총 클래스 수 (3) 동일한 클래스 열의 인덱스를 지정합니다 .

또한 원본 파일에서 클래스 순서를 제거하려면 데이터 세트를 섞어 야합니다.

기본 System.currentTimeMillis () 호출 대신 상수 임의 시드 (42)를 지정 하여 셔플 링 결과가 항상 동일하도록합니다. 이를 통해 프로그램을 실행할 때마다 안정적인 결과를 얻을 수 있습니다.

DataSetIterator iterator = new RecordReaderDataSetIterator(
  recordReader, 150, FEATURES_COUNT, CLASSES_COUNT);
DataSet allData = iterator.next();
allData.shuffle(42);

4.3. 정규화 및 분할

훈련 전에 데이터로해야 할 또 다른 일은 데이터를 정규화하는 것입니다. 정규화는 2 단계 프로세스이다 :

  • 데이터에 대한 통계 수집 (적합)
  • 데이터를 균일하게 만들기 위해 어떤 방식 으로든 데이터를 변경 (변환)합니다.

정규화는 데이터 유형에 따라 다를 수 있습니다.

예를 들어 다양한 크기의 이미지를 처리하려면 먼저 크기 통계를 수집 한 다음 이미지를 균일 한 크기로 조정해야합니다.

그러나 숫자의 경우 정규화는 일반적으로이를 소위 정규 분포로 변환하는 것을 의미합니다. NormalizerStandardize의 클래스는 우리에게 도움이 될 수 있습니다 :

DataNormalization normalizer = new NormalizerStandardize();
normalizer.fit(allData);
normalizer.transform(allData);

이제 데이터가 준비되었으므로 세트를 두 부분으로 분할해야합니다.

첫 번째 부분은 교육 세션에서 사용됩니다. 훈련 된 네트워크를 테스트하기 위해 데이터의 두 번째 부분 (네트워크가 전혀 볼 수 없음)을 사용할 것입니다.

이를 통해 분류가 올바르게 작동하는지 확인할 수 있습니다. 데이터의 65 % (0.65)를 교육에 사용하고 나머지 35 %는 테스트에 사용합니다.

SplitTestAndTrain testAndTrain = allData.splitTestAndTrain(0.65);
DataSet trainingData = testAndTrain.getTrain();
DataSet testData = testAndTrain.getTest();

5. 네트워크 구성 준비

5.1. Fluent 구성 빌더

이제 멋진 유창한 빌더로 네트워크 구성을 구축 할 수 있습니다.

MultiLayerConfiguration configuration 
  = new NeuralNetConfiguration.Builder()
    .iterations(1000)
    .activation(Activation.TANH)
    .weightInit(WeightInit.XAVIER)
    .learningRate(0.1)
    .regularization(true).l2(0.0001)
    .list()
    .layer(0, new DenseLayer.Builder().nIn(FEATURES_COUNT).nOut(3).build())
    .layer(1, new DenseLayer.Builder().nIn(3).nOut(3).build())
    .layer(2, new OutputLayer.Builder(
      LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
        .activation(Activation.SOFTMAX)
        .nIn(3).nOut(CLASSES_COUNT).build())
    .backprop(true).pretrain(false)
    .build();

네트워크 모델을 구축하는이 단순화 된 유창한 방법에도 불구하고 소화해야 할 것이 많고 조정할 매개 변수가 많습니다. 이 모델을 분해 해 보겠습니다.

5.2. 네트워크 매개 변수 설정

반복 () 최적화 반복 방법 지정 작성기 번호.

반복 최적화는 네트워크가 좋은 결과를 얻을 때까지 훈련 세트에서 여러 번의 패스를 수행하는 것을 의미합니다.

일반적으로 실제 및 대규모 데이터 세트에서 훈련 할 때 여러 세대 (네트워크를 통한 완전한 데이터 전달)와 각 세대에 대해 한 번의 반복을 사용합니다. 그러나 초기 데이터 세트가 최소이므로 한 시대와 여러 반복을 사용합니다.

활성화 () 의 출력을 결정하기 위해 노드 내에서 실행하는 기능이다.

가장 간단한 활성화 함수는 선형 f (x) = x입니다. 그러나 비선형 함수 만 네트워크가 몇 개의 노드를 사용하여 복잡한 작업을 해결할 수 있도록합니다.

org.nd4j.linalg.activations.Activation 열거 형 에서 조회 할 수있는 다양한 활성화 기능이 있습니다 . 필요한 경우 활성화 함수를 작성할 수도 있습니다. 그러나 제공된 쌍곡 탄젠트 (tanh) 함수를 사용합니다.

weightInit () 여러 가지 방법 중 하나를 지정하여 네트워크에 대한 초기 가중치를 설정합니다. 올바른 초기 가중치는 훈련 결과에 큰 영향을 미칠 수 있습니다. 수학에 너무 많이 들어 가지 않고 가우스 분포 ( WeightInit.XAVIER ) 의 형태로 설정해 보겠습니다. 이는 일반적으로 시작하기에 좋은 선택입니다.

다른 모든 가중치 초기화 방법은 org.deeplearning4j.nn.weights.WeightInit 열거 형 에서 조회 할 수 있습니다 .

학습률 은 네트워크의 학습 능력에 중대한 영향을 미치는 중요한 매개 변수입니다.

더 복잡한 경우에이 매개 변수를 조정하는 데 많은 시간을 할애 할 수 있습니다. 그러나 우리의 간단한 작업에서는 0.1이라는 매우 중요한 값을 사용하고 learningRate () 빌더 메서드로 설정합니다.

훈련 신경망의 문제 중 하나는 네트워크가 훈련 데이터를 "기억"할 때 과적 합하는 경우입니다 .

이는 네트워크가 훈련 데이터에 지나치게 높은 가중치를 설정하고 다른 데이터에 대해 잘못된 결과를 생성 할 때 발생합니다.

이 문제를 해결하기 위해 .regularization (true) .l2 (0.0001)을 사용하여 l2 정규화를 설정합니다 . 정규화는 너무 큰 가중치에 대해 네트워크에 페널티를주고 과적 합을 방지합니다.

5.3. 네트워크 계층 구축

다음으로 고밀도 (완전 연결이라고도 함) 계층의 네트워크를 만듭니다.

첫 번째 계층에는 학습 데이터의 열과 동일한 양의 노드가 포함되어야합니다 (4).

두 번째 조밀 한 레이어에는 세 개의 노드가 포함됩니다. 이것은 우리가 변경할 수있는 값이지만 이전 레이어의 출력 수는 동일해야합니다.

최종 출력 레이어에는 클래스 수 (3)와 일치하는 노드 수가 포함되어야합니다. 네트워크의 구조는 그림에 나와 있습니다.

성공적인 훈련 후에는 입력을 통해 4 개의 값을 수신하고 3 개의 출력 중 하나로 신호를 보내는 네트워크를 갖게됩니다. 이것은 간단한 분류기입니다.

마지막으로 네트워크 구축을 완료하기 위해 역 전파 (가장 효과적인 훈련 방법 중 하나)를 설정하고 .backprop (true) .pretrain (false) 라인을 사용하여 사전 훈련을 비활성화 합니다.

6. 네트워크 생성 및 훈련

이제 구성에서 신경망을 만들고 초기화하고 실행 해 보겠습니다.

MultiLayerNetwork model = new MultiLayerNetwork(configuration);
model.init();
model.fit(trainingData);

이제 나머지 데이터 세트를 사용하여 훈련 된 모델을 테스트하고 세 가지 클래스에 대한 평가 지표로 결과를 확인할 수 있습니다.

INDArray output = model.output(testData.getFeatureMatrix());
Evaluation eval = new Evaluation(3);
eval.eval(testData.getLabels(), output);

이제 eval.stats ()를 출력하면 네트워크가 붓꽃을 분류하는 데 꽤 능숙하다는 것을 알 수 있습니다. 클래스 1을 클래스 2로 세 번 실수 했음에도 불구하고 말입니다.

Examples labeled as 0 classified by model as 0: 19 times
Examples labeled as 1 classified by model as 1: 16 times
Examples labeled as 1 classified by model as 2: 3 times
Examples labeled as 2 classified by model as 2: 15 times

==========================Scores========================================
# of classes: 3
Accuracy: 0.9434
Precision: 0.9444
Recall: 0.9474
F1 Score: 0.9411
Precision, recall & F1: macro-averaged (equally weighted avg. of 3 classes)
========================================================================

유창한 구성 빌더를 사용하면 네트워크의 레이어를 빠르게 추가 또는 수정하거나 다른 매개 변수를 조정하여 모델을 개선 할 수 있는지 확인할 수 있습니다. ㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ ㅇㅇㅇ

7. 결론

이 기사에서는 deeplearning4j 라이브러리를 사용하여 간단하면서도 강력한 신경망을 구축했습니다.

항상 그렇듯이 기사의 소스 코드는 GitHub에서 사용할 수 있습니다 .