JavaRush /Java Blog /Random-KO /Java 개발자를 위한 머신 러닝, 2부

Java 개발자를 위한 머신 러닝, 2부

Random-KO 그룹에 게시되었습니다
Java 개발자를 위한 머신 러닝, 1부
Java 개발자를 위한 기계 학습, 2부 - 1

목적 함수 추정

예측 함수라고도 알려진 목표 함수는 준비 또는 훈련 프로세스의 결과라는 점을 상기해 보겠습니다 . 수학적으로 문제는 변수를 입력으로 받아 х예측값을 반환하는 함수를 찾는 것입니다 у.
Java 개발자를 위한 기계 학습, 2부 - 2
기계 학습에서 비용 함수는 (J(θ))주어진 목적 함수의 오류 값 또는 "비용"을 계산하는 데 사용됩니다.
Java 개발자를 위한 기계 학습, 2부 - 3
비용 함수는 모델이 훈련 데이터에 얼마나 잘 맞는지 보여줍니다. 위에 표시된 목적 함수의 비용을 결정하려면 각 예시 주택의 제곱 오차를 계산해야 합니다 (i). 오차는 계산된 값과 예제의 집 у실제 값 사이의 거리입니다 . yi
Java 개발자를 위한 기계 학습, 2부 - 4
예를 들어, 면적이 1330인 주택의 실제 가격은 6,500,000€입니다 . 그리고 훈련된 목적 함수에 의해 예측된 주택 가격의 차이는 €7,032,478 입니다 . 차이(또는 오류)는 €532,478 입니다 . 위 그래프에서도 이 차이를 확인할 수 있습니다. 차이(또는 오류)는 각 가격-영역 훈련 쌍에 대해 빨간색 수직 점선으로 표시됩니다. 훈련된 목적 함수의 비용을 계산한 후에는 예제의 각 주택에 대한 제곱 오차를 합산하고 주요 값을 계산해야 합니다. 가격 값이 작을수록 (J(θ))목적 함수의 예측이 더 정확해집니다. 목록 3 은 목적 함수, 훈련 데이터 목록 및 이와 연관된 레이블을 입력으로 사용하는 비용 함수의 간단한 Java 구현을 보여줍니다. 예측 값은 루프에서 계산되며 오류는 실제 가격 값(라벨에서 가져옴)을 빼서 계산됩니다. 나중에 오류의 제곱이 합산되어 오류 값이 계산됩니다. 비용은 다음 유형의 값으로 반환됩니다 double.

목록-3

public static double cost(Function<ltDouble[], Double> targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels) {
 int m = dataset.size();
 double sumSquaredErrors = 0;

 // рассчет квадрата ошибки («разницы») для каждого тренировочного примера и //добавление его к сумме
 for (int i = 0; i < m; i++) {
 // получаем вектор признаков из текущего примера
 Double[] featureVector = dataset.get(i);
 // предсказываем meaning и вычисляем ошибку базируясь на реальном
 //значении (метка)
 double predicted = targetFunction.apply(featureVector);
 double label = labels.get(i);
 double gap = predicted - label;
 sumSquaredErrors += Math.pow(gap, 2);
 }

 // Вычисляем и возращаем meaning ошибки (чем меньше тем лучше)
 return (1.0 / (2 * m)) * sumSquaredErrors;
}
Java에 대해 읽고 싶으십니까? Java 개발자 그룹에 가입하세요 !

타겟 함수 학습

비용 함수는 목표 함수와 세타 매개변수의 품질을 평가하는 데 도움이 되지만 여전히 가장 적합한 세타 매개변수를 찾아야 합니다. 이를 위해 경사 하강 알고리즘을 사용할 수 있습니다.

경사하강법

경사하강법은 비용 함수를 최소화합니다. 즉, (J(θ))학습 데이터를 기반으로 최소 비용을 갖는 세타 매개변수를 찾는 데 사용됩니다. 다음은 새롭고 보다 적절한 세타 값을 계산하기 위한 단순화된 알고리즘입니다.
Java 개발자를 위한 기계 학습, 2부 - 5
따라서 세타 벡터의 매개변수는 알고리즘을 반복할 때마다 향상됩니다. 학습 계수 α는 각 반복의 계산 수를 지정합니다. 이러한 계산은 "좋은" 세타 값을 찾을 때까지 수행할 수 있습니다. 예를 들어 아래 선형 회귀 함수에는 세 개의 세타 매개변수가 있습니다.
Java 개발자를 위한 기계 학습, 2부 - 6
각 반복에서 각 세타 매개변수( , 및 ) 에 대해 새 값이 계산됩니다 . 각 반복 후에 새로운 세타 벡터 0 , θ 1 , θ 2 } 를 사용하여 새롭고 보다 적절한 구현을 생성할 수 있습니다 . 목록 -4 는 그래디언트 붕괴 알고리즘에 대한 Java 코드를 보여줍니다. 회귀 함수의 Theta는 훈련 데이터, 마커 데이터, 학습률을 사용하여 훈련됩니다 . 결과는 세타 매개변수를 사용하여 향상된 목적 함수가 됩니다. 이 메소드는 이전 계산의 새 목적 함수와 새 세타 매개변수를 전달하면서 계속해서 호출됩니다. 그리고 이러한 호출은 구성된 목적 함수가 최소 안정기에 도달할 때까지 반복됩니다. θ0θ1θ2LinearRegressionFunction(α)train()

목록-4

public static LinearRegressionFunction train(LinearRegressionFunction targetFunction,
 List<ltDouble[]> dataset,
 List<ltDouble> labels,
 double alpha) {
 int m = dataset.size();
 double[] thetaVector = targetFunction.getThetas();
 double[] newThetaVector = new double[thetaVector.length];

 // вычисление нового значения тета для каждого element тета массива
 for (int j = 0; j < thetaVector.length; j++) {
 // сумируем разницу ошибки * признак
 double sumErrors = 0;
 for (int i = 0; i < m; i++) {
 Double[] featureVector = dataset.get(i);
 double error = targetFunction.apply(featureVector) - labels.get(i);
 sumErrors += error * featureVector[j];
 }

 //вычисляем новые значения тета
 double gradient = (1.0 / m) * sumErrors;
 newThetaVector[j] = thetaVector[j] - alpha * gradient;
 }

 return new LinearRegressionFunction(newThetaVector);
}
J(θ)비용이 지속적으로 감소하도록 하려면 각 훈련 단계 후에 비용 함수를 실행할 수 있습니다 . 각 반복 후에 비용은 감소해야 합니다. 이것이 발생하지 않으면 학습 계수의 값이 너무 커서 알고리즘이 최소값을 놓친 것입니다. 이러한 경우 경사 감소 알고리즘이 실패합니다. 아래 플롯은 시작 세타 벡터부터 시작하여 새로 계산된 세타 매개변수를 사용한 목적 함수를 보여줍니다 {1.0, 1.0}. 왼쪽 열은 50회 반복 후 예측 함수의 플롯을 보여줍니다. 200회 반복 후 중간 열; 1000회 반복 후 오른쪽 열. 이를 통해 우리는 각 반복 후에 가격이 감소하고 새로운 목적 함수가 점점 더 잘 맞는다는 것을 알 수 있습니다. 500~600회 반복 후에는 세타 매개변수가 더 이상 크게 변하지 않으며 가격은 안정적인 안정 상태에 도달합니다. 이후에는 이런 방식으로 목표 함수의 정확도를 향상시킬 수 없습니다.
Java 개발자를 위한 기계 학습, 2부 - 7
이 경우 500~600회 반복 후에 비용이 더 이상 크게 감소하지 않더라도 목적 함수는 여전히 최적이 아닙니다. 이는 불일치를 나타냅니다 . 기계 학습에서 "불일치"라는 용어는 학습 알고리즘이 데이터에서 기본 추세를 찾지 못함을 나타내는 데 사용됩니다. 실제 경험을 토대로 대규모 부동산의 경우 평방미터당 가격이 인하될 것으로 예상됩니다. 이를 통해 목표 함수 학습 프로세스에 사용된 모델이 데이터에 충분히 적합하지 않다는 결론을 내릴 수 있습니다. 이러한 불일치는 종종 모델을 지나치게 단순화했기 때문에 발생합니다. 우리의 경우에는 목적 함수가 너무 간단하고 분석을 위해 집의 면적이라는 단일 매개 변수를 사용합니다. 하지만 이 정보만으로는 집값을 정확하게 예측하기에는 부족합니다.

기능 추가 및 확장

목적 함수가 해결하려는 문제와 일치하지 않는 경우 이를 조정해야 합니다. 불일치를 수정하는 일반적인 방법은 특징 벡터에 추가 특징을 추가하는 것입니다. 주택 가격의 예에는 방 수나 주택의 연식과 같은 특성을 추가할 수 있습니다. 즉, {size}집을 설명하기 위해 하나의 특성 값을 가진 벡터를 사용하는 대신 여러 값을 가진 벡터를 사용할 수 있습니다. 예를 들어, {size, number-of-rooms, age}. 사용 가능한 훈련 데이터의 특성 수가 충분하지 않은 경우가 있습니다. 그렇다면 기존 특성을 사용하여 계산된 다항식 특성을 사용해 볼 가치가 있습니다. 예를 들어 주택 가격을 결정하기 위한 목적 함수를 확장하여 평방 미터(x2)의 계산된 특성을 포함할 수 있습니다.
Java 개발자를 위한 기계 학습, 2부 - 8
여러 기능을 사용하려면 다양한 기능에 걸쳐 범위를 표준화하는 데 사용되는 기능 확장이 필요합니다. 따라서 크기 2 속성 의 값 범위는 크기 속성의 값 범위보다 훨씬 큽니다. 기능 확장이 없으면 크기 2가 비용 함수에 과도한 영향을 미칩니다. 크기 2 속성 으로 인한 오류는 크기 속성으로 인한 오류보다 훨씬 더 큽니다. 간단한 기능 확장 알고리즘은 다음과 같습니다.
Java 개발자를 위한 기계 학습, 2부 - 9
FeaturesScaling이 알고리즘은 아래 예제 코드의 클래스에서 구현됩니다 . 이 수업에서는 FeaturesScaling훈련 데이터에 맞춰 조정된 스케일링 함수를 생성하기 위한 상업적인 방법을 제시합니다. 내부적으로 훈련 데이터 인스턴스는 평균, 최소, 최대값을 계산하는 데 사용됩니다. 결과 함수는 특징 벡터를 가져와서 크기가 조정된 특징으로 새로운 벡터를 생성합니다. 아래와 같이 학습 과정과 예측 과정 모두에 특징 확장이 필요합니다.
// создание массива данных
List<ltDouble[]> dataset = new ArrayList<>();
dataset.add(new Double[] { 1.0, 90.0, 8100.0 }); // feature vector of house#1
dataset.add(new Double[] { 1.0, 101.0, 10201.0 }); // feature vector of house#2
dataset.add(new Double[] { 1.0, 103.0, 10609.0 }); // ...
//...

// создание меток
List<ltDouble> labels = new ArrayList<>();
labels.add(249.0); // price label of house#1
labels.add(338.0); // price label of house#2
labels.add(304.0); // ...
//...

// создание расширенного списка признаков
Function<ltDouble[], Double[]> scalingFunc = FeaturesScaling.createFunction(dataset);
List<ltDouble[]> scaledDataset = dataset.stream().map(scalingFunc).collect(Collectors.toList());

// создаем функцию которая инициализирует теты и осуществляет обучение //используя коэффициент обучения 0.1

LinearRegressionFunction targetFunction = new LinearRegressionFunction(new double[] { 1.0, 1.0, 1.0 });
for (int i = 0; i < 10000; i++) {
 targetFunction = Learner.train(targetFunction, scaledDataset, labels, 0.1);
}

// делаем предсказание стоимости дома с площадью 600 m2
Double[] scaledFeatureVector = scalingFunc.apply(new Double[] { 1.0, 600.0, 360000.0 });
double predictedPrice = targetFunction.apply(scaledFeatureVector);
점점 더 많은 기능이 추가될수록 목적 함수에 대한 적합도가 높아지지만 주의하세요. 너무 멀리 나아가서 너무 많은 기능을 추가하면 결국 과적합된 목적 함수를 학습하게 될 수 있습니다.

오버매칭 및 교차 검증

과대적합은 목적 함수나 모델이 훈련 데이터에 너무 잘 맞아서 훈련 데이터의 노이즈나 무작위 변화를 포착할 때 발생합니다. 과적합의 예는 아래 맨 오른쪽 그래프에 나와 있습니다.
Java 개발자를 위한 기계 학습, 2부 - 10
그러나 과적합 모델은 훈련 데이터에서는 매우 잘 수행되지만 실제 알려지지 않은 데이터에서는 성능이 저하됩니다. 과적합을 방지하는 방법에는 여러 가지가 있습니다.
  • 훈련을 위해 더 큰 데이터 세트를 사용하십시오.
  • 위 그래프에 표시된 것처럼 더 적은 수의 기능을 사용하십시오.
  • 정규화를 고려하는 향상된 기계 학습 알고리즘을 사용합니다.
예측 알고리즘이 훈련 데이터에 과적합하는 경우 정확성에 도움이 되지 않는 특징을 제거해야 합니다. 어려운 점은 다른 기능보다 예측 정확도에 더 중요한 영향을 미치는 기능을 찾는 것입니다. 그래프에서 볼 수 있듯이 과적합은 그래프를 통해 시각적으로 확인할 수 있습니다. 이는 좌표가 2개 또는 3개 있는 그래프에 적합하며, 2개 이상의 기능을 사용하면 그래프를 구성하고 평가하기가 어려워집니다. 교차 검증에서는 학습 프로세스가 완료된 후 알고리즘에 알려지지 않은 데이터를 사용하여 학습한 후 모델을 다시 테스트합니다. 사용 가능한 레이블이 지정된 데이터는 3개 세트로 나누어야 합니다.
  • 훈련 데이터;
  • 검증 데이터;
  • 테스트 데이터.
이 경우 주택을 특성화하는 레이블이 지정된 레코드의 60%가 대상 알고리즘의 변형을 훈련하는 과정에서 사용되어야 합니다. 훈련 과정 후에는 (이전에 사용되지 않은) 나머지 데이터의 절반을 사용하여 훈련된 타겟 알고리즘이 알려지지 않은 데이터에 대해 잘 작동하는지 확인해야 합니다. 일반적으로 다른 알고리즘보다 성능이 좋은 알고리즘이 선택되어 사용됩니다. 나머지 데이터는 최종 선택된 모델의 오차 값을 계산하는 데 사용됩니다. k-fold 와 같은 다른 교차 검증 기술이 있습니다 . 그러나 이 기사에서는 이에 대해 설명하지 않습니다.

기계 학습 도구 및 Weka 프레임워크

대부분의 프레임워크와 라이브러리는 광범위한 기계 학습 알고리즘 컬렉션을 제공합니다. 또한 데이터 모델 교육, 테스트 및 처리에 대한 편리한 고급 인터페이스를 제공합니다. Weka는 JVM의 가장 인기 있는 프레임워크 중 하나입니다. Weka는 모델 검증을 위한 그래픽 테스트가 포함된 실용적인 Java 라이브러리입니다. 아래 예에서는 Weka 라이브러리를 사용하여 기능과 레이블이 포함된 교육 데이터 세트를 생성합니다. 방법 setClassIndex()- 마킹용. Weka에서 레이블은 클래스로 정의됩니다.
// определяем атрибуты для признаков и меток
ArrayList<ltAttribute> attributes = new ArrayList<>();
Attribute sizeAttribute = new Attribute("sizeFeature");
attributes.add(sizeAttribute);
Attribute squaredSizeAttribute = new Attribute("squaredSizeFeature");
attributes.add(squaredSizeAttribute);
Attribute priceAttribute = new Attribute("priceLabel");
attributes.add(priceAttribute);


// создаем и заполняем список признаков 5000 примеров
Instances trainingDataset = new Instances("trainData", attributes, 5000);
trainingDataset.setClassIndex(trainingSet.numAttributes() - 1);
Instance instance = new DenseInstance(3);

instance.setValue(sizeAttribute, 90.0);
instance.setValue(squaredSizeAttribute, Math.pow(90.0, 2));
instance.setValue(priceAttribute, 249.0);
trainingDataset.add(instance);
Instance instance = new DenseInstance(3);
instance.setValue(sizeAttribute, 101.0);
...
데이터 세트와 샘플 개체는 파일에서 저장하고 로드할 수 있습니다. Weka는 Weka의 그래픽 벤치마크에서 지원되는 ARFF (Attribute Relation File Format)를 사용합니다. 이 데이터 세트는 Weka에서 분류자로 알려진 목적 함수를 훈련하는 데 사용됩니다. 먼저 목적함수를 정의해야 합니다. 아래 코드는 LinearRegression분류자의 인스턴스를 생성합니다. 이 분류자는 buildClassifier(). 이 방법은 buildClassifier()최상의 목표 모델을 찾기 위해 훈련 데이터를 기반으로 세타 매개변수를 선택합니다. Weka를 사용하면 학습 속도나 반복 횟수 설정에 대해 걱정할 필요가 없습니다. Weka는 또한 기능 확장을 독립적으로 수행합니다.
Classifier targetFunction = new LinearRegression();
targetFunction.buildClassifier(trainingDataset);
이러한 설정이 이루어지면 아래와 같이 목적 함수를 사용하여 주택 가격을 예측할 수 있습니다.
Instances unlabeledInstances = new Instances("predictionset", attributes, 1);
unlabeledInstances.setClassIndex(trainingSet.numAttributes() - 1);
Instance unlabeled = new DenseInstance(3);
unlabeled.setValue(sizeAttribute, 1330.0);
unlabeled.setValue(squaredSizeAttribute, Math.pow(1330.0, 2));
unlabeledInstances.add(unlabeled);

double prediction = targetFunction.classifyInstance(unlabeledInstances.get(0));
EvaluationWeka는 훈련된 분류기 또는 모델을 테스트하는 클래스를 제공합니다 . 아래 코드에서는 잘못된 결과를 방지하기 위해 선택된 검증 데이터 배열을 사용합니다. 측정 결과(오류 비용)가 콘솔에 표시됩니다. 일반적으로 평가 결과는 다양한 기계 학습 알고리즘 또는 이들의 변형을 사용하여 훈련된 모델을 비교하는 데 사용됩니다.
Evaluation evaluation = new Evaluation(trainingDataset);
evaluation.evaluateModel(targetFunction, validationDataset);
System.out.println(evaluation.toSummaryString("Results", false));
위의 예에서는 입력 값을 기반으로 집값 등의 수치를 예측하는 선형 회귀를 사용합니다. 선형 회귀는 연속적인 수치 예측을 지원합니다. 이진값("예" 및 "아니오")을 예측하려면 다른 기계 학습 알고리즘을 사용해야 합니다. 예를 들어 의사결정 트리, 신경망, 로지스틱 회귀 등이 있습니다.
// использование логистической регрессии
Classifier targetFunction = new Logistic();
targetFunction.buildClassifier(trainingSet);
예를 들어 이러한 알고리즘 중 하나를 사용하여 이메일 메시지가 스팸인지 예측하거나 날씨를 예측하거나 집이 잘 팔릴지 예측할 수 있습니다. 날씨나 집이 얼마나 빨리 팔릴지 예측하기 위해 알고리즘을 가르치려면 다른 데이터 세트가 필요합니다.topseller:
// использование атрибута маркера topseller instead of атрибута маркера цена
ArrayList<string> classVal = new ArrayList<>();
classVal.add("true");
classVal.add("false");

Attribute topsellerAttribute = new Attribute("topsellerLabel", classVal);
attributes.add(topsellerAttribute);
이 데이터 세트는 새로운 분류기를 훈련하는 데 사용됩니다 topseller. 훈련이 완료되면 예측 호출은 예측 값을 얻는 데 사용할 수 있는 토큰 클래스 인덱스를 반환해야 합니다.
int idx = (int) targetFunction.classifyInstance(unlabeledInstances.get(0));
String prediction = classVal.get(idx);

결론

기계 학습은 통계와 밀접하게 관련되어 있고 많은 수학적 개념을 사용하지만 기계 학습 툴킷을 사용하면 수학에 대한 깊은 지식 없이도 기계 학습을 프로그램에 통합할 수 있습니다. 그러나 이 기사에서 살펴본 선형 회귀 알고리즘과 같은 기본 기계 학습 알고리즘을 더 잘 이해할수록 올바른 알고리즘을 선택하고 최적의 성능을 위해 조정할 수 있습니다. 영어 번역 . 저자: Gregor Roth, JavaWorld의 소프트웨어 설계자
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION