[목차]
(0) 환경 설정 : DL4J 개발 환경 설정 및 예제 설명
(1) Data Iterator : 사용하고자 하는 데이터를 DL4J 에서 사용가능한 형태로 변환하는 작업 개발 필요
• Canova: The Rosetta Stone of Vectorization
(2) Net : 사용할 신경망의 형태가 어떤 것이 있는지 이해하고 선택, 활용 할 수 있어야 함
• Restricted Boltzmann machines
• Convolutional nets
• Recursive autoencoders
• Recurrent nets: Long Short-Term Memory (LSTM) (including bi-directional LSTMs)
• Deep-belief networks
• Denoising and Stacked Denoising autoencoders
• Deep autoencoders
(3) Activation : Weight + Bias 결과 다음 적용할 함수 결정 (예 : SigMoid : Chap1 에서 설명한 것)
• ReLU
• Leaky ReLU
• Tanh
• Sigmoid
• Hard Tanh
• Softmax
• Identity
• ELU: Exponential Linear Units
• Softsign
• Softplus
(4) Loss&Objective Functions : 일부 데이터를 누락함으로써 더 Robust 한 모델을 만들 수 있다.
• Reconstruction entropy
• Squared loss
• Mean squared error
• Multi-class cross entropy for classification
• Negative log likelihood
• RMSE_XENT
(5) Hyperparameters : 모든 Layer 에 공통적으로 적용되는 파라메터로 숙지 필요
• Dropout (random ommission of feature detectors to prevent overfitting)
• Sparsity (force activations of sparse/rare inputs)
• Adagrad (feature-specific learning-rate optimization)
• L1 and L2 regularization (weight decay)
• Weight transforms (useful for deep autoencoders)
• Probability distribution manipulation for initial weight generation
• Gradient normalization and clipping
(6) Event Listener & Result Anal : 분석 중간 발생하는 이벤트를 받아서 처리 및 결과에 대한 검증 및 비지니스 연동 등
DL4J 는 InteliJ 기반으로 개발됩니다. 홈페이지에 친절하게 환경 구성 과정이 설명되어 있습니다. (http://deeplearning4j.org/quickstart)
그럼에도 불구하고 간단하게 내용을 정리해 보도록 하겠습니다.
1. 환경 구성 사전 필수 조건
– Java 7 or later
– IntelliJ (Eclipse 도 가능은 하지만 InteliJ 추천)
– Maven (연관된 라이브러리 자동화 관리)
– Git (프로젝트 공유 관리)
위 내용은 DL4J 가 내부적으로 사용하는 과학적 데이터 처리 ND4J 홈페이지 설치 가이드 참조라고 되어 있음
※ Check 사항
. Java JDK 만 있으면 됩니다. JRE는 건들지 마세요. InteliJ 에서 SDK Setting 에 들어가서 경로만 걸어 주세요
. Maven 압축말 풀어서 Path 만 잡아주면 됩니다. MAVEN_HOME 설정해 주시면 InteliJ 는 자동으로 연동됩니다.
회사에서 개발시 Proxy 문제 발생 할 수 있습니다. InteliJ 에서 Proxy 만 잡아주세요
. Git : 윈도우 버전 설치시 계속만 열시히 눌러주면 됩니다.
2. Sample 실행해 보기
– git 사용 Sample 프로젝트 다운로드
. git 콘솔 실행
. 명령어 입력 : git clone https://github.com/deeplearning4j/dl4j-0.4-examples.git
. git 하위 폴더에 프로젝트 다운로드
. InteliJ 에서 기존소스 열기로 해당 프로젝트 오픈
– Maven 사용 필요 라이브러리 다운로드
. InteliJ 에서 프로젝트 import 시 라이브러리 없음으로 애러 발생
. Maven Reimport 수행
– 각 Sample 프로젝트 실행
. 다수의 Sample 을 포함하고 있는 프로젝트로 개별적으로 RUN 하여 테스트
※ Image 를 서버에서 다운받아 사용하는 예제의 경우 Proxy 문제로 소스 코드 수정 필요
3. 예제 소스 보기
– NeuralNetConfiguration 에 신경망 설계 내용이 들어간다.
(1) 데이터 Set
분석에서는 엄청 유명한 데이터 셋 Iris
EX) 5.1,3.5,1.4,0.2,i.setosa
1. sepal length in cm
2. sepal width in cm
3. petal length in cm
4. petal width in cm
5. class (Iris Setosa) , (Iris Versicolour) , (Iris Virginica)
(2) 데이터 로딩
신경망 분석이 가능한 형태로 데이터를 변환하는 과정
IrisDataSetIterator 는 CSV 파일을 신경망 분석이 가능한 데이터로 변환하는 클래스로
Canova(http://deeplearning4j.org/canova.html) 를 사용해서 만든 예제 클래스 중에 하나임
※ Canova 는 Text, CSV, Image, Audio 등 대표적인 데이터 타입을 신경망 분석 가능한 형태로
변환하는 라이브러리임( 해당 라이브러리 사용법에 대해서는 추후에 다루는 것으로)
– IrisDataSetIterator(batchSize, numSamples)
. batchSize : 한번에 읽는 데이터의 양
. numSamples : 전체 로딩하고자 하는 데이터의 양
– next.normalizeZeroMeanZeroUnitVariance()
. Nomalization 스케일링 작업 (너무 크거나 작은 값은 결과에 외곡을 줄수 있음)
[코드]
log.info("Load data...."); DataSetIterator iter = new IrisDataSetIterator(batchSize, numSamples); DataSet next = iter.next(); next.normalizeZeroMeanZeroUnitVariance();
(3) 학습 데이터 분리
R 분석에서도 항상 하는 것 처럼 데이터를 학습할 데이터와 검증할 데이터로 나누는 작업이다.
[코드]
log.info("Split data...."); SplitTestAndTrain testAndTrain = next.splitTestAndTrain(splitTrainNum, new Random(seed)); DataSet train = testAndTrain.getTrain(); DataSet test = testAndTrain.getTest();
(4) 신경망 구성 작업
가) HyperParameters
신경망에서는 각 Neuron 의 Weight 와 Bias 값 등을 Parameter 라고 부르며 아래와 같이 전체적인
망 구성의 옵션으로 적용되는 것들은 HyperParmeter 라고 부른다고 한다..
conf 값은 orvering 을 통해 각 Layer 별로 지정해 주지 않는한 모든 Layer 에 공통적으로 적용된다.
파라메터는 Builder() 뒤 쪽으로 연결해서 정의된다.
[코드]
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
나) Seed 값 지정
시드 값은 통상적인 프로그램에서와 마찬가지로 Random 값 생성시 사용하는 값으로
일정한 결과를 유지하기 위하여 지정한다.
[코드]
.seed(seed)
다) 학습 반복 횟수 지정
분류 및 저장을 반복할 횟수를 지정하는 것
(Epoch 와 Iteration 은 다른것이라고 하는데 확실히 이해는 안됨..??)
[코드]
.iterations(iterations)
라) 학습 반영도
학습이라 함은 간단하게 생각하면 Weight 값과 Bias 값의 조정이라고 보고 한번의
Iteration 으로 Weight 에 얼마나 변화를 줄 것 인지를 지정하는 것
[코드]
.learningRate(1e-6f)
마) 최적화 알고리즘 지정
신경막을 역방향으로 분석할 때 사용할 알고리즘을 지정하는 것
. LBFGS : Limited-memory BFGS
[코드]
.optimizationAlgo(OptimizationAlgorithm.LBFGS)
바) 기타 파라메터
[코드]
.regularization(true).momentum(0.9).constrainGradientToUnitNorm(true)
사) 데이터 누락
의도적으로 랜덤하게 데이터를 누락하는 것은 모델을 더 견고하게 만드는데 도움이 됨
[코드]
.useDropConnect(true)
아) Layer Depth
Layer 의 수를 지정한다. 2라고 함은 각 하나의 Input , Hidden, Output Layer 를 만들라는 말이다.
[코드]
.list(2)
사) 레이어 종류 지정
RBM 은 restricted Boltzmann machine 으로 같은 Level 끼리는 연결 관계를 갖지 않는 형태의
신경망을 이야기하며, 더 자세한 설명은 따로 정리하도록 하겠다.
파라메터를 보면 Hidden Layer 를 만드는데는 ReLU (Rectified linear units) 을 사용하여 더
견고하고 F1 점수가 높은(학습데이터와 테스트 데이터가 더 일치하는) Activation (Weight 와 Bias 로
구성된 Function) 을 만드는데 사용하고, Data Input 을 위한 Visible Layer 에는 가우시안 화이트 노이즈
(정규 분포를 어떻게 사용하는듯..??) 사용한다.
[코드]
.layer(0, new RBM.Builder(RBM.HiddenUnit.RECTIFIED, RBM.VisibleUnit.GAUSSIAN)
마) 인풋 데이터
인풋 노드의 수를 정의한다. (10 by 10 이미지를 Pixel 단위로 Input 데이터로 정의하면 100개)
본 예 에서는 아래와 같은 4가지의 인풋을 갖기 때문에 4이다.
원문서에서 Row 4 X Col 1 = 4라고 하는것은 Matrix 개념으로 설명했다고 보면 된다.
1. sepal length in cm
2. sepal width in cm
3. petal length in cm
4. petal width in cm
[코드]
.nIn(numRows * numColumns)
바) 아웃풋 데이터
아웃풋 노드의 수를 지정한다. 본 예에서는 아래와 같이 3가지로 outputNum 는 3이다,
class (Iris Setosa) , (Iris Versicolour) , (Iris Virginica)
[코드]
.nOut(outputNum)'
아) 초기 Weight 설정
초기 Weight 값 설정에 사용할 알고리즘을 정의한다. Xavier initialization 는 많은 Layer 를
거쳐 특정 값이 너무 커지거나 너무 작아지지 않도록 도와준다
[코드]
.weightInit(WeightInit.XAVIER)
차) Activation Function 지정
Rectified linear units 가 두번 정의되는데 인풋에서 한번 아웃풋에서 한번 정의되어
변화없이 값을 전달 할 수 있도록 한다.
[코드]
.activation("relu")
카) 오류치 계산 알고리즘
학습알고리즘은 Error 치가 적은 방향으로 점진적으로 조정해 가는데 이때 오류치를 구하는
방법을 지정한다. root-means-squared-error-cross entropy는 큰 오류치를 찾는데 효과적이라고 한다..
[코드]
.lossFunction(LossFunctions.LossFunction.RMSE_XENT)
(5) Net Build
Line1 : (4) configuration 값을 세팅
Line2 : Configuration 값으로 MultiLayerNetwork 을 생성
Line3 : 모델 초기화
Line4 : interation 에서 발생하는 Event Call Back
[코드]
.build(); MultiLayerNetwork model = new MultiLayerNetwork(conf); model.init(); model.setListeners(Collections.singletonList((IterationListener) new ScoreIterationListener(listenerFreq)));
(6) 모델 학습
위에서 생서한 Train Data Set 으로 모델을 훈련한다.
[코드]
log.info("Train model...."); model.fit(train);
(7) 모델 실행 평가
(6)의 테스트 데이터로 만든 모델에 Test Data 로 시뮬레이션을 실행하고
원래 원본에서 알고 있는 값과 비교를 통해 정확도를 평가한다.
가장 가단한 예제 하나를 실행하여 본 것이지만 R 에서 제공하는 RANN 과
차이와 장단점 비교를 하지 않을 수 없을 것 같다는 생각이 든다..
[코드]
log.info("Evaluate model...."); Evaluation eval = new Evaluation(); INDArray output = model.output(test.getFeatureMatrix()); for (int i = 0; i < output.rows(); i++) { String actual = train.getLabels().getRow(i).toString().trim(); String predicted = output.getRow(i).toString().trim(); log.info("actual " + actual + " vs predicted " + predicted); }
[결과 값]
Actual Class 0 was Predicted 0 with count 13 times Actual Class 1 was Predicted 0 with count 2 times Actual Class 1 was Predicted 2 with count 8 times Actual Class 2 was Predicted 2 with count 7 times =================Scores========================= Accuracy: 0.6667 Precision: 0.6667 Recall: 1 F1 Score: 0.8 ================================================
[전체 코드]
public class DBNIrisExample { private static Logger log = LoggerFactory.getLogger(DBNIrisExample.class); public static void main(String[] args) throws Exception { // Customizing params Nd4j.MAX_SLICES_TO_PRINT = -1; Nd4j.MAX_ELEMENTS_PER_SLICE = -1; final int numRows = 4; final int numColumns = 1; int outputNum = 3; int numSamples = 150; int batchSize = 150; int iterations = 5; int splitTrainNum = (int) (batchSize * .8); int seed = 123; int listenerFreq = 1; log.info("Load data...."); DataSetIterator iter = new IrisDataSetIterator(batchSize, numSamples); DataSet next = iter.next(); next.shuffle(); next.normalizeZeroMeanZeroUnitVariance(); log.info("Split data...."); SplitTestAndTrain testAndTrain = next.splitTestAndTrain(splitTrainNum, new Random(seed)); DataSet train = testAndTrain.getTrain(); DataSet test = testAndTrain.getTest(); Nd4j.ENFORCE_NUMERICAL_STABILITY = true; log.info("Build model...."); MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder() .seed(seed) // Locks in weight initialization for tuning .iterations(iterations) // # training iterations predict/classify & backprop .learningRate(1e-6f) // Optimization step size .optimizationAlgo(OptimizationAlgorithm.CONJUGATE_GRADIENT) // Backprop to calculate gradients .l1(1e-1).regularization(true).l2(2e-4) .useDropConnect(true) .list(2) // # NN layers (doesn't count input layer) .layer(0, new RBM.Builder(RBM.HiddenUnit.RECTIFIED, RBM.VisibleUnit.GAUSSIAN) .nIn(numRows * numColumns) // # input nodes .nOut(3) // # fully connected hidden layer nodes. Add list if multiple layers. .weightInit(WeightInit.XAVIER) // Weight initialization .k(1) // # contrastive divergence iterations .activation("relu") // Activation function type .lossFunction(LossFunctions.LossFunction.RMSE_XENT) // Loss function type .updater(Updater.ADAGRAD) .dropOut(0.5) .build() ) // NN layer type .layer(1, new OutputLayer.Builder(LossFunctions.LossFunction.MCXENT) .nIn(3) // # input nodes .nOut(outputNum) // # output nodes .activation("softmax") .build() ) // NN layer type .build(); MultiLayerNetwork model = new MultiLayerNetwork(conf); model.init(); model.setListeners(new ScoreIterationListener(listenerFreq)); log.info("Train model...."); model.fit(train); log.info("Evaluate weights...."); for(org.deeplearning4j.nn.api.Layer layer : model.getLayers()) { INDArray w = layer.getParam(DefaultParamInitializer.WEIGHT_KEY); log.info("Weights: " + w); } log.info("Evaluate model...."); Evaluation eval = new Evaluation(outputNum); eval.eval(test.getLabels(), model.output(test.getFeatureMatrix(), Layer.TrainingMode.TEST)); log.info(eval.stats()); log.info("****************Example finished********************"); OutputStream fos = Files.newOutputStream(Paths.get("coefficients.bin")); DataOutputStream dos = new DataOutputStream(fos); Nd4j.write(model.params(), dos); dos.flush(); dos.close(); FileUtils.writeStringToFile(new File("conf.json"), model.getLayerWiseConfigurations().toJson()); MultiLayerConfiguration confFromJson = MultiLayerConfiguration.fromJson(FileUtils.readFileToString(new File("conf.json"))); DataInputStream dis = new DataInputStream(new FileInputStream("coefficients.bin")); INDArray newParams = Nd4j.read(dis); dis.close(); MultiLayerNetwork savedNetwork = new MultiLayerNetwork(confFromJson); savedNetwork.init(); savedNetwork.setParams(newParams); System.out.println("Original network params " + model.params()); System.out.println(savedNetwork.params()); } }