Sandwood는 JVM 기반 확률 모델을 위한 언어, 컴파일러 및 런타임입니다. 이는 Java 개발자에게 친숙한 언어로 모델을 작성할 수 있도록 설계되었습니다. 결과 모델은 Java 개체의 형태를 취하므로 주변 시스템의 잘 추상화된 구성 요소가 될 수 있습니다.
전통적인 베이지안 모델을 사용하면 사용자는 모델을 설계한 다음 모델에서 수행하려는 모든 작업에 대한 추론 코드를 구현해야 합니다. 이로 인해 여러 가지 문제가 발생합니다.
추론 코드를 구성하는 것은 기술적으로 어렵고 시간이 많이 걸립니다. 이 단계에서는 미묘한 버그가 발생할 수 있는 기회가 제공됩니다.
모델이 수정되면 추론 코드도 업데이트되어야 합니다. 이는 또한 시간이 많이 걸리고 기술적으로 까다로워서 다음과 같은 문제가 발생합니다.
이는 모델 수정을 억제하는 역할을 합니다.
다양한 추론 작업이 단계에서 벗어나 일부는 이전 모델에서 작동하고 일부는 새 모델에서 작동하는 것이 가능합니다.
이는 사용자가 기존 코드를 미묘하게 조정하려고 할 때 추론 알고리즘에 버그가 들어갈 또 다른 기회를 제공합니다.
확률적 프로그래밍은 Sandwood의 경우처럼 API나 DSL(도메인 특정 언어)을 사용하여 모델을 설명할 수 있도록 하여 이러한 문제를 극복합니다. Sandwood DSL은 모델을 나타내고 필요한 모든 추론 작업을 구현하는 Java 클래스를 생성하도록 컴파일됩니다. 여기에는 여러 가지 장점이 있습니다.
Sandwood는 해당 디렉토리에 각각 3개의 구성 요소로 구성됩니다.
각 조각은 이전 조각에 종속됩니다. 각 구성 요소 디렉터리에는 구성 요소를 구성하는 Maven POM 파일이 포함되어 있습니다. 컴파일러와 플러그인의 경우 이후 단계에서 사용할 수 있도록 install
시 호출해야 합니다(예: mvn clean install
. 예제는 mvn clean package
로만 빌드되어야 합니다.
Sandwood를 설치한 후 현재 모델을 컴파일하는 방법은 3가지가 있습니다.
컴파일러와 런타임이 구축된 후 명령줄에서 Sandwood를 사용하려면 javac
와 유사한 기능을 가진 명령줄 스크립트를 commandline/SandwoodC/bin
에서 찾을 수 있습니다. 이를 사용하려면 사용자는 일반적으로 경로에 bin 디렉터리를 추가한 다음 sandwoodc.sh HMM.sandwood를 호출하여 HMM 모델을 컴파일합니다. sandwoodc.sh -h
또는 sandwoodc.bat -h
실행하면 사용법에 대한 설명과 사용 가능한 옵션이 인쇄됩니다.
SandwoodC의 모든 기능은 org.sandwood.compilation.SandwoodC
에서 compile
메소드를 호출하고 명령줄에 전달된 인수가 포함된 배열을 전달하여 접근할 수 있습니다.
Maven 플러그인을 사용하면 종속 프로젝트가 빌드될 때 샌드우드 파일 컴파일을 자동으로 트리거할 수 있습니다. 플러그인을 사용하려면 sandwood 런타임을 종속성으로 추가하고 플러그인을 빌드에 추가해야 합니다. 이는 POM 파일에 다음을 추가하여 달성됩니다.
<dependencies>
<dependency>
<groupId>org.sandwood</groupId>
<artifactId>sandwood-runtime</artifactId>
<version>0.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.sandwood</groupId>
<artifactId>sandwoodc-maven-plugin</artifactId>
<version>0.3-SNAPSHOT</version>
<executions>
<execution>
<configuration>
<partialInferenceWarning>true</partialInferenceWarning>
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
</configuration>
<goals>
<goal>sandwoodc</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>`
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
요소를 포함하면 모델을 찾을 디렉터리를 플러그인에 지시합니다. 기타 유용한 플래그는 다음과 같습니다.
debug
이 옵션은 SandwoodC에서 디버깅 정보를 얻는 데 사용됩니다. 이 옵션을 true
로 설정하면 Sandwood가 해당 작업의 추적을 생성합니다. 기본값은 false
입니다. 이 플래그는 컴파일되는 모델이 아닌 컴파일러 구성/컴파일러의 오류를 디버깅하기 위한 것입니다. 샌드우드 모델 파일의 오류와 경고는 항상 컴파일러에 의해 반환됩니다.
partialInferenceWarning
이 옵션은 일부 추론 단계를 구성할 수 없을 때 SandwoodC가 실패하는 것을 방지하는 데 사용됩니다. 이 옵션을 true
로 설정하면 Sandwood는 누락된 단계에 대해서만 경고를 생성합니다. 기본값은 false
입니다.
sourceDirectory
이 매개변수는 모델 파일을 찾을 디렉터리를 설정합니다. 이 디렉토리 내에서 모델은 다른 패키지에 위치할 수 있습니다.
outputDirectory
이 매개변수는 모델의 Java 소스 코드가 배치되어야 하는 디렉토리를 설정합니다. 기본값은 ${project.build.directory}/generated-sources/sandwood
입니다.
calculateIndividualProbabilities
이 매개변수는 루프에 구성된 각 무작위 변수의 확률을 모든 인스턴스에 대해 단일 값 대신 계산해야 하는지 여부를 지정합니다. 기본값은 false
입니다.
javadoc
이 매개변수는 모델을 보완하기 위해 JavaDoc을 생성하도록 컴파일러에 지시합니다. 기본값은 false
입니다.
javadocDirectory
이 매개변수는 생성된 파일이 배치되어야 하는 위치를 지정합니다.
executable
파일 이 매개변수를 사용하면 Sandwood 컴파일러를 실행하기 위해 대체 JVM을 지정할 수 있습니다.
다음은 Sandwood 모델을 작성하는 방법과 모델을 구현하는 결과 클래스를 사용하는 방법에 대한 소개입니다.
모델이 거치는 단계의 개요는 이 다이어그램에서 볼 수 있습니다. 모델은 클래스 파일 세트로 컴파일되는 .sandwood
파일로 시작됩니다. 이는 여러 번 인스턴스화되어 다양한 구성으로 모델의 여러 인스턴스를 생성할 수 있습니다.
실행 예제로 HMM(Hidden Markov Model)을 사용합니다. 이 모델은 여기 Sandwood로 작성되었습니다. 이 모델은 패키지 디렉터리 org/sandwood/examples/hmm
에 HMM.sandwood
라는 파일에 저장되어야 합니다. 언어에 대한 자세한 설명은 여기에서 확인할 수 있습니다.
package org . sandwood . examples . hmm ;
model HMM ( int [] eventsMeasured , int numStates , int numEvents ) {
//Construct a transition matrix m.
double [] v = new double [ numStates ] <~ 0.1 ;
double [][] m = dirichlet ( v ). sample ( numStates );
//Construct weighting for which state to start in.
double [] initialState = new Dirichlet ( v ). sample ();
//Construct weighting for each event in each state.
double [] w = new double [ numEvents ] <~ 0.1 ;
double [][] bias = dirichlet ( w ). sample ( numStates );
//Allocate space to record the sequence of states.
int sequenceLength = eventsMeasured . length ;
int [] st = new int [ sequenceLength ];
//Calculate the movements between states.
st [ 0 ] = categorical ( initialState ). sampleDistribution ();
for ( int i : [ 1. . sequenceLength ) )
st [ i ] = categorical ( m [ st [ i - 1 ]]). sampleDistribution ();
//Emit the events for each state.
int [] events = new int [ sequenceLength ];
for ( int j = 0 ; j < sequenceLength ; j ++)
events [ j ] = new Categorical ( bias [ st [ j ]]). sample ();
//Assert that the events match the eventsMeasured data.
events . observe ( eventsMeasured );
}
모델에 대해 생성할 수 있는 Sandwood 언어 및 JavaDoc 주석의 문서 외에도 Sandwood 예제 디렉토리에 많은 예제가 있으며 새로운 사용자는 이를 검토하고 수정하는 것부터 시작하는 것이 좋습니다.
Sandwood 모델을 설명하는 데 사용되는 언어에 대한 설명은 여기에서 찾을 수 있습니다. 언어는 Java 개발자에게 친숙하도록 구성되었지만 객체를 구성하는 기능은 포함하지 않습니다. 앞으로는 레코드 유형에 대한 지원을 추가하여 모델에서 데이터를 더 쉽게 가져오고 내보낼 수 있도록 할 계획입니다.
모델이 컴파일되면 모델이 정의된 동일한 패키지에 여러 클래스 파일이 생성됩니다. 이러한 클래스 중 하나는 모델에 제공된 이름과 동일한 이름을 가지므로 이 경우 HMM.class 모델의 인스턴스를 갖기 위해 사용자가 인스턴스화해야 하는 클래스입니다. 모델에서 공개적으로 표시되는 각 변수는 생성된 클래스의 필드에 해당합니다. HMM 예시는 아래에서 볼 수 있습니다.
javadoc
플래그 세트를 사용하여 컴파일러를 실행하면 생성된 모델 파일의 각 공용 메소드 및 클래스에 대해 JavaDoc이 생성됩니다.
모델이 컴파일되면 인스턴스를 인스턴스화해야 합니다. 이러한 인스턴스는 독립적이며 사용자는 원하는 만큼 모델의 다양한 복사본을 만들 수 있습니다.
모델 객체의 인스턴스는 클래스 생성자를 통해 생성됩니다. 앞서 설명한 대로 모델에는 일반적으로 3개의 생성자가 있습니다. 더 적은 수의 유일한 경우는 생성자의 다양한 변형이 동일한 시그니처에 매핑되는 경우입니다. 이 경우 하나의 생성자가 이러한 시나리오 중 둘 이상에 적용됩니다.
전체 생성자 - 이 생성자는 모델 서명에 나타나는 모든 인수를 가져와서 설정합니다. 이 생성자는 값 추론 및 확률 추론 작업에 사용됩니다.
빈 생성자 - 이 생성자는 인수를 사용하지 않으며 사용자가 나중에 설정할 수 있도록 매개변수를 남겨둡니다.
실행 생성자 - 이 생성자는 관찰된 인수만 제거하고 차원이 코드에 대한 입력으로 사용되는 관찰된 인수의 경우 전체 매개 변수 대신 해당 차원을 사용합니다. 따라서 HMM 예에서 eventsMeasured 매개변수는 시퀀스 길이를 설명하는 정수가 됩니다.
이 코드 샘플은 컴파일된 모델을 호출하는 방법을 보여줍니다.
모델 객체를 통한 모델과의 상호 작용은 두 가지 형태를 취합니다.
기본 보존 정책 설정, 모델이 추론할 준비가 되었는지 확인, 추론 단계 시작 등과 같은 전역 작업을 위한 모델 객체 메서드 호출
모델 매개변수 개체를 호출합니다. 모델의 각 명명된 공용 변수는 모델 개체의 해당 필드로 표시됩니다. 변수가 모델의 가장 바깥쪽 범위에서 선언되고 private
레이블이 붙지 않은 경우 또는 내부 범위에서 선언되고 public
레이블이 지정되지 않은 경우 변수는 public입니다. 내부 반복 범위(예: for 루프 본문)에서 필드가 공개로 선언되면 각 반복의 값이 저장됩니다.
객체의 유형은 변수에 따라 달라집니다. 이는 3가지 범주로 나눌 수 있습니다.
이러한 각 필드는 사용자가 매개변수의 값과 속성을 설정하고 읽을 수 있는 메서드 집합이 있는 개체를 참조합니다. 설정하고 읽을 수 있는 속성에는 매개변수의 확률, 매개변수의 보존 정책 및 매개변수를 현재 값으로 고정해야 하는지 여부가 포함됩니다.
모델 추론을 수행할 때 매개변수 개체의 더 중요한 메서드 중 일부는 다음과 같습니다.
getSamples는 샘플링된 값을 반환합니다.
getMAP은 최대 A 사후 값을 반환합니다.
setValue를 사용하면 값을 특정 값으로 설정할 수 있습니다.
setFixed는 boolean
을 사용하여 값을 고정된 것으로 표시하므로 추론 중에 업데이트되지 않습니다. 매개변수를 수정하기 전에 매개변수 값을 설정하는 것이 중요합니다.
확률을 추론한 후 변수의 로그 확률을 가져오는 getLogProbability입니다.
더 많은 방법이 있으며 JavaDoc을 참조하여 해당 방법에 익숙해지는 것이 좋습니다.
모델에서 수행할 수 있는 기본 작업 유형은 3가지입니다.
setRentionPolicy
메소드를 호출하여 전체 모델에 대한 보존 정책을 설정할 수 있습니다. 선택적으로 개별 변수는 각 변수 객체의 해당 setRetentionPolicy
메소드를 호출하여 보존 정책을 설정할 수 있습니다.샘플링 정책에는 3가지가 있습니다.
NONE은 값을 기록하지 않습니다. 이는 변수 중 하나가 커서 이를 저장하는 데 시간과 공간을 들이는 것이 낭비일 경우 특히 유용합니다.
SAMPLE은 추론 알고리즘의 모든 반복에서 값을 기록하므로 1000회 반복이 수행되면 이 보존 정책에 설정된 각 변수에서 1000개의 값이 샘플링됩니다. 이는 평균값뿐만 아니라 분산을 계산하는 데 유용합니다. 그러나 여기에는 약점이 있습니다. 추론 중에 모델 내의 값 위치가 이동할 수 있으면 값의 평균을 계산할 수 없습니다. 예를 들어 토픽 모델의 경우 토픽 2와 토픽 3은 추론 중에 위치를 바꿀 수 있으므로 토픽 2의 모든 값을 평균화하여 토픽 2와 토픽 3의 혼합을 생성합니다. 이를 극복하기 위해 MAP(Maximum A Posteriori)도 다음과 같이 제공됩니다. 보존 정책.
MAP 또는 MAP(Maximum A Posteriori)는 모델이 가장 가능성 있는 상태에 있을 때 변수 값을 기록합니다. 이는 값을 평균화할 수 없지만 경계를 계산할 수 있음을 의미하는 일시적인 값 위치 문제를 극복합니다. 이 옵션은 일부 변수가 큰 경우 공간적 이점도 있습니다.
구성: 모델 객체에 대한 추가 메서드 호출을 통해 사용자는 이 추론 단계를 수행할 때 번인(burnin) 및 희석(thinning) 과 같은 속성을 설정할 수 있습니다. Burnin은 모델이 샘플링을 시작하기 전에 낮은 확률의 시작점에서 벗어날 수 있도록 처음 n 반복의 값을 무시합니다. Thinning은 매 n 번째 반복의 값만 고려하여 MCMC 절차에 의해 유도된 자기상관을 감소시킵니다.
확률 추론 모델의 일부 또는 모든 매개변수 값을 설정하면 해당 값이 생성될 확률이 계산됩니다. 이는 모델의 각 변수와 모델 전체에 대해 계산될 수 있습니다.
모델 실행 사용자가 수정하지 않은 매개변수에 대해 새 값을 생성하는 일반 코드인 것처럼 모델을 실행합니다. 이 동작이 사용되는 예는 선형 회귀 모델에 대한 것입니다. 이 경우 모델 계수는 먼저 훈련 데이터를 사용하여 추론됩니다. 일단 추론되면 고정되고 새로운 입력 데이터 세트가 됩니다. 그런 다음 모델이 실행되어 이 새로운 입력 데이터에 대한 해당 예측을 생성합니다. 이러한 실행 형태는 훈련된 모델에서 대표적인 합성 데이터를 생성하는 데에도 사용될 수 있습니다.
모델 구성 및 학습
//Load inputs
int nStates = 25 ;
int [] actions = loadActions (....);
int nActions = maxActions (....);
//Construct the model
HMM model = new HMM ( actions , nActions , nStates );
//Set the retention policies
model . setDefaultRetentionPolicy ( RetentionPolicy . MAP );
model . st . setRetentionPolicy ( RetentionPolicy . NONE );
//Pick a random number generator. The ones introduced in Java 17 are faster and better quality.
model . setRNGType ( RandomType . L64X1024MixRandom );
//Instruct the model to use the ForkJoin framework for parallel execution.
model . setExecutionTarget ( ExecutionTarget . forkJoin );
//Run 2000 inference steps to infer model values
model . inferValues ( 2000 );
//Gather the results.
double [] initialState = model . initialState . getMAP ();
double [][] bias = model . bias . getMAP ();
double [][] transitions = model . m . getMAP ();
모델 구축 및 확률 추론
//Load inputs
int nStates = 25 ;
int [] actions = loadActions (....);
int nActions = maxActions (....);
//Load model parameters
double [][] bias = model . bias . getMAP ();
double [][] transitions = model . m . getMAP ();
//Construct the model
HMM model = new HMM ( actions , nActions , nStates );
//Set and fix trained values
model . bias . setValue ( bias );
Model . m . setValue ( transitions );
//Run 2000 inference steps to infer probabilities
model . inferProbabilities ( 2000 );
//Recover the probabilities of the model parameter actions.
double actionsProbability = model . actions . getProbability ();
//Recover the probability of the model as a whole
double modelProbability = model . getProbability ()
Sandwood에 대한 도움이 필요하면 토론 페이지에서 토론을 시작하거나 참여하세요.
이 프로젝트는 커뮤니티의 기여를 환영합니다. 끌어오기 요청을 제출하기 전에 기여 가이드를 검토하세요.
책임 있는 보안 취약점 공개 프로세스에 대해서는 보안 가이드를 참조하세요.
저작권 (c) 2019-2024 Oracle 및/또는 그 계열사.
https://oss.oracle.com/licenses/upl/에 표시된 것처럼 Universal Permissive License v1.0에 따라 릴리스되었습니다.