Sandwood คือภาษา คอมไพเลอร์ และรันไทม์สำหรับโมเดลความน่าจะเป็นที่ใช้ JVM ได้รับการออกแบบมาเพื่อให้โมเดลสามารถเขียนด้วยภาษาที่นักพัฒนา Java คุ้นเคย โมเดลผลลัพธ์จะอยู่ในรูปแบบของอ็อบเจ็กต์ Java ซึ่งทำให้เป็นส่วนประกอบที่เป็นนามธรรมของระบบที่ครอบคลุม
ด้วยโมเดลเบย์เซียนแบบดั้งเดิม ผู้ใช้จะต้องออกแบบโมเดล จากนั้นใช้โค้ดการอนุมานสำหรับการดำเนินการใดๆ ที่พวกเขาต้องการทำกับโมเดล สิ่งนี้ทำให้เกิดปัญหาหลายประการ:
การสร้างโค้ดการอนุมานในทางเทคนิคถือเป็นเรื่องท้าทายและใช้เวลานาน ขั้นตอนนี้เปิดโอกาสให้มีการแนะนำจุดบกพร่องเล็กๆ น้อยๆ
หากมีการแก้ไขโมเดล จะต้องอัปเดตโค้ดการอนุมาน นอกจากนี้ยังใช้เวลานานและมีความท้าทายทางเทคนิค ซึ่งนำไปสู่ปัญหาต่อไปนี้:
มันทำหน้าที่เป็นตัวยับยั้งการปรับเปลี่ยนโมเดล
เป็นไปได้ที่การดำเนินการอนุมานที่แตกต่างกันจะออกนอกขั้นตอน ดังนั้นบางส่วนจึงทำงานกับโมเดลเก่าและบางส่วนใช้กับโมเดลใหม่
มันนำเสนอโอกาสอีกครั้งสำหรับจุดบกพร่องที่จะเข้าไปในอัลกอริธึมการอนุมาน เนื่องจากผู้ใช้พยายามทำการปรับเปลี่ยนโค้ดที่มีอยู่อย่างละเอียด
การเขียนโปรแกรมความน่าจะเป็นเอาชนะปัญหาเหล่านี้โดยอนุญาตให้อธิบายแบบจำลองโดยใช้ API หรือภาษาเฉพาะโดเมน (DSL) เช่นเดียวกับในกรณีของ Sandwood Sandwood DSL ได้รับการคอมไพล์เพื่อสร้างคลาส Java ที่เป็นตัวแทนของโมเดลและใช้การดำเนินการอนุมานที่จำเป็นทั้งหมด สิ่งนี้มีข้อดีหลายประการ:
ไม้แซนด์วูดประกอบด้วย 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 สามารถเข้าถึงได้โดยการเรียกเมธอด compile
ใน org.sandwood.compilation.SandwoodC
และส่งผ่านอาร์เรย์ที่มีอาร์กิวเมนต์ที่จะถูกส่งไปยังบรรทัดคำสั่ง
ปลั๊กอิน Maven สามารถใช้เพื่อทริกเกอร์การคอมไพล์ไฟล์ไม้จันทน์โดยอัตโนมัติเมื่อมีการสร้างโปรเจ็กต์ที่ต้องพึ่งพา หากต้องการใช้ปลั๊กอิน คุณต้องเพิ่มรันไทม์ไม้แซนด์วูดเป็นการพึ่งพา และเพิ่มปลั๊กอินเข้ากับบิลด์ สามารถทำได้โดยการเพิ่มไฟล์ 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
จะทำให้แซนด์วูดสร้างร่องรอยของการกระทำของมัน ค่าเริ่มต้นคือ false
โปรดทราบว่าแฟล็กนี้ใช้สำหรับการแก้ไขข้อผิดพลาดด้วยการกำหนดค่า/คอมไพเลอร์ของคอมไพเลอร์ ไม่ใช่กับโมเดลที่กำลังคอมไพล์ ข้อผิดพลาดและคำเตือนในไฟล์โมเดลไม้จันทน์จะถูกส่งคืนโดยคอมไพเลอร์เสมอ
partialInferenceWarning
ตัวเลือกนี้ใช้เพื่อหยุด SandwoodC จากความล้มเหลวเมื่อไม่สามารถสร้างขั้นตอนการอนุมานบางอย่างได้ การตั้งค่าตัวเลือกนี้เป็น true
จะทำให้ Sandwood สร้างคำเตือนเกี่ยวกับขั้นตอนที่ขาดหายไป ค่าเริ่มต้นเป็น false
sourceDirectory
พารามิเตอร์นี้ตั้งค่าไดเร็กทอรีที่จะค้นหาไฟล์โมเดล ภายในไดเร็กทอรีนี้ โมเดลสามารถอยู่ในแพ็คเกจที่แตกต่างกันได้
outputDirectory
พารามิเตอร์นี้ตั้งค่าไดเร็กทอรีใดที่ซอร์สโค้ด Java สำหรับโมเดลควรถูกวางไว้ ค่าเริ่มต้นคือ ${project.build.directory}/generated-sources/sandwood
calculateIndividualProbabilities
พารามิเตอร์นี้ระบุว่าควรคำนวณความน่าจะเป็นสำหรับตัวแปรสุ่มแต่ละตัวที่สร้างขึ้นในลูปแทนค่าเดียวสำหรับอินสแตนซ์ทั้งหมดหรือไม่ ค่าเริ่มต้นคือ false
javadoc
พารามิเตอร์นี้สั่งให้คอมไพลเลอร์สร้าง JavaDoc เพื่อสนับสนุนโมเดล ค่าเริ่มต้นคือ false
javadocDirectory
พารามิเตอร์นี้ระบุตำแหน่งที่ควรวางที่สร้างขึ้น
executable
พารามิเตอร์นี้อนุญาตให้ระบุ JVM ทางเลือกเพื่อรันคอมไพเลอร์ Sandwood ด้วย
ต่อไปนี้เป็นคำแนะนำเกี่ยวกับวิธีการเขียนโมเดล Sandwood และวิธีใช้คลาสผลลัพธ์ที่ใช้โมเดล
สามารถดูโครงร่างของขั้นตอนที่แบบจำลองต้องดำเนินการได้ในแผนภาพนี้ โมเดลเริ่มต้นเป็นไฟล์ .sandwood
ที่คอมไพล์เป็นชุดของไฟล์คลาส สิ่งเหล่านี้สามารถสร้างอินสแตนซ์ได้หลายครั้งเพื่อสร้างอินสแตนซ์หลายรายการของโมเดลที่มีการกำหนดค่าที่แตกต่างกัน
เป็นตัวอย่าง เราจะใช้ Hidden Markov Model (HMM) แบบจำลองนี้เขียนที่นี่ด้วยไม้แซนด์วูด โมเดลนี้ควรถูกบันทึกไว้ในไฟล์ชื่อ HMM.sandwood
ในไดเร็กทอรีแพ็กเกจ org/sandwood/examples/hmm
สามารถดูคำอธิบายภาษาโดยละเอียดได้ที่นี่
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 Examples และเราขอแนะนำให้ผู้ใช้ใหม่เริ่มต้นด้วยการตรวจสอบและแก้ไขสิ่งเหล่านี้
คุณสามารถดูคำอธิบายภาษาที่ใช้อธิบายโมเดล Sandwood ได้ที่นี่ ภาษานี้สร้างขึ้นโดยมีจุดประสงค์เพื่อให้นักพัฒนา Java คุ้นเคย แต่ไม่มีความสามารถในการสร้างออบเจ็กต์ เราวางแผนที่จะเพิ่มการสนับสนุนสำหรับประเภทเรกคอร์ดในอนาคตเพื่อทำให้การนำเข้าและส่งออกข้อมูลเข้าและออกจากโมเดลง่ายขึ้น
เมื่อโมเดลถูกคอมไพล์ ไฟล์คลาสจำนวนหนึ่งจะถูกสร้างขึ้นในแพ็คเกจเดียวกับที่โมเดลนั้นถูกกำหนดไว้ หนึ่งในคลาสเหล่านี้จะมีชื่อเดียวกันกับชื่อที่กำหนดให้กับโมเดล ดังนั้นในกรณีนี้ HMM.class และสิ่งนี้ คือคลาสที่ผู้ใช้ควรสร้างอินสแตนซ์เพื่อให้มีอินสแตนซ์ของโมเดล ตัวแปรแต่ละตัวที่เปิดเผยต่อสาธารณะในโมเดลจะสอดคล้องกับฟิลด์ในคลาสที่สร้างขึ้น ตัวอย่าง HMM สามารถดูได้ด้านล่าง
โดยการรันคอมไพเลอร์ด้วยชุดแฟล็ก javadoc
JavaDoc จะถูกสร้างขึ้นสำหรับแต่ละเมธอดสาธารณะและคลาสในไฟล์โมเดลที่สร้างขึ้น
เมื่อโมเดลได้รับการคอมไพล์แล้ว เราจำเป็นต้องสร้างอินสแตนซ์ของโมเดลนั้น อินสแตนซ์เหล่านี้มีความเป็นอิสระและผู้ใช้สามารถสร้างสำเนาของโมเดลต่างๆ ได้มากเท่าที่ต้องการ
อินสแตนซ์ของวัตถุโมเดลถูกสร้างขึ้นผ่านตัวสร้างคลาส ตามที่อธิบายไว้ก่อนหน้านี้ โดยทั่วไปแล้วจะมีตัวสร้าง 3 ตัวสำหรับโมเดล กรณีเดียวที่จะมีน้อยลงคือเมื่อตัวแปรที่แตกต่างกันของแมปตัวสร้างไปยังลายเซ็นเดียวกัน ซึ่งในกรณีนี้ตัวสร้างตัวหนึ่งจะนำไปใช้กับสถานการณ์เหล่านี้มากกว่าหนึ่งสถานการณ์
ตัวสร้างแบบเต็ม - ตัวสร้างนี้รับอาร์กิวเมนต์ทั้งหมดที่ปรากฏในลายเซ็นโมเดลและตั้งค่า ตัวสร้างนี้ใช้สำหรับค่าอนุมานและอนุมานการดำเนินการของความน่าจะเป็น
ตัวสร้างว่างเปล่า - ตัวสร้างนี้ไม่มีการโต้แย้ง โดยปล่อยให้พารามิเตอร์ให้ผู้ใช้ตั้งค่าในภายหลัง
ตัวสร้างการดำเนินการ - ตัวสร้างนี้จะลบอาร์กิวเมนต์ที่สังเกตได้เท่านั้น และสำหรับอาร์กิวเมนต์ที่สังเกตซึ่งมีมิติข้อมูลที่ใช้เป็นอินพุตของโค้ด จะใช้มิติข้อมูลเหล่านั้นแทนพารามิเตอร์แบบเต็ม ดังนั้นในตัวอย่าง HMM พารามิเตอร์ eventsMeasured จะกลายเป็นจำนวนเต็มที่อธิบายความยาวของลำดับ
ตัวอย่างโค้ดเหล่านี้สาธิตวิธีการเรียกโมเดลที่คอมไพล์แล้ว
การโต้ตอบกับโมเดลผ่านออบเจ็กต์โมเดลมีสองรูปแบบ:
การเรียกใช้โมเดลเมธอดออบเจ็กต์สำหรับการดำเนินงานทั่วโลก เช่น การตั้งค่านโยบายการเก็บรักษาเริ่มต้น การตรวจสอบว่าโมเดลพร้อมสำหรับการอนุมานหรือไม่ และการเริ่มต้นขั้นตอนการอนุมาน เป็นต้น
การเรียกไปยังวัตถุพารามิเตอร์แบบจำลอง ตัวแปรสาธารณะที่มีชื่อแต่ละตัวในโมเดลจะแสดงด้วยฟิลด์ที่เกี่ยวข้องในออบเจ็กต์โมเดล ตัวแปรเป็นแบบสาธารณะหากมีการประกาศในขอบเขตภายนอกสุดของโมเดลและไม่มีป้ายกำกับ private
หรือประกาศในขอบเขตภายในและไม่มีป้ายกำกับ public
หากฟิลด์ถูกประกาศต่อสาธารณะในขอบเขตการวนซ้ำภายใน เช่น เนื้อความของ for loop ค่าจากการวนซ้ำแต่ละครั้งจะถูกเก็บไว้
ประเภทของวัตถุจะขึ้นอยู่กับตัวแปร สิ่งเหล่านี้สามารถแบ่งออกเป็น 3 ประเภท:
แต่ละฟิลด์เหล่านี้อ้างอิงออบเจ็กต์ด้วยชุดวิธีการที่อนุญาตให้ผู้ใช้ตั้งค่าและอ่านค่าและคุณสมบัติจากพารามิเตอร์ คุณสมบัติที่สามารถตั้งค่าและอ่านได้จะรวมถึงความน่าจะเป็นของพารามิเตอร์ นโยบายการเก็บรักษาของพารามิเตอร์ และพารามิเตอร์ควรคงที่เป็นค่าปัจจุบันหรือไม่
วิธีการที่สำคัญบางประการของออบเจ็กต์พารามิเตอร์เมื่อทำการอนุมานโมเดลคือ:
getSamples เพื่อส่งกลับค่าตัวอย่าง
getMAP เพื่อส่งคืนค่าสูงสุด A Posteriori
setValue เพื่ออนุญาตให้ตั้งค่าเป็นค่าเฉพาะ
setFixed ซึ่งใช้ boolean
เพื่อทำเครื่องหมายค่าว่าคงที่ และดังนั้นจึงไม่ได้รับการอัปเดตในระหว่างการอนุมาน สิ่งสำคัญคือต้องตั้งค่าของพารามิเตอร์ก่อนทำการแก้ไข
getLogProbability ซึ่งรับความน่าจะเป็นของบันทึกของตัวแปรหลังจากการอนุมานความน่าจะเป็น
มีวิธีการมากกว่านี้ และเราขอแนะนำให้ปรึกษา JavaDoc เพื่อทำความคุ้นเคยกับวิธีการเหล่านั้น
มีการดำเนินการพื้นฐาน 3 ประเภทที่สามารถทำได้บนแบบจำลอง:
setRentionPolicy
ในคลาสโมเดล ตัวแปรแต่ละตัวที่เป็นทางเลือกสามารถกำหนดนโยบายการเก็บรักษาโดยการเรียกไปยังเมธอด setRetentionPolicy
ที่สอดคล้องกันในแต่ละอ็อบเจ็กต์ตัวแปรมีนโยบายการสุ่มตัวอย่าง 3 แบบ:
NONE จะไม่บันทึกค่าใดๆ สิ่งนี้มีประโยชน์อย่างยิ่งหากตัวแปรตัวใดตัวหนึ่งมีขนาดใหญ่ ดังนั้นการสละเวลาและพื้นที่ในการจัดเก็บจะสิ้นเปลือง
SAMPLE บันทึกค่าจากการวนซ้ำทุกครั้งของอัลกอริธึมการอนุมาน ดังนั้นหากมีการวนซ้ำ 1,000 ครั้ง ค่า 1,000 ค่าจะถูกสุ่มตัวอย่างจากตัวแปรแต่ละตัวที่ตั้งค่าเป็นนโยบายการเก็บรักษานี้ สิ่งนี้มีประโยชน์สำหรับการคำนวณความแปรปรวนและค่าเฉลี่ย มีจุดอ่อนในเรื่องนี้ แม้ว่าตำแหน่งของค่าภายในโมเดลสามารถเคลื่อนที่ได้ในระหว่างการอนุมาน ค่าจะไม่สามารถหาค่าเฉลี่ยได้ ตัวอย่างเช่น หัวข้อโมเดลหัวข้อ 2 และ 3 อาจสลับตำแหน่งระหว่างการอนุมาน ดังนั้น การหาค่าเฉลี่ยของค่าทั้งหมดสำหรับหัวข้อ 2 ด้วยการสร้างส่วนผสมของหัวข้อ 2 และหัวข้อ 3 ในการเอาชนะค่า Maximum A Posteriori (MAP) ก็มีให้ไว้เป็น นโยบายการเก็บรักษา
MAP หรือ Maximum A Posteriori (MAP) จะบันทึกค่าของตัวแปรเมื่อโมเดลอยู่ในสถานะที่เป็นไปได้มากที่สุด วิธีนี้จะช่วยแก้ปัญหาเกี่ยวกับตำแหน่งค่าชั่วคราว ซึ่งหมายความว่าค่าต่างๆ ไม่สามารถหาค่าเฉลี่ยได้ แต่ต้องแลกมาด้วยความสามารถในการคำนวณขอบเขต ตัวเลือกนี้ยังมีข้อได้เปรียบด้านพื้นที่หากตัวแปรบางตัวมีขนาดใหญ่
การกำหนดค่า: การเรียกใช้เมธอดเพิ่มเติมบนออบเจ็กต์โมเดลทำให้ผู้ใช้สามารถตั้งค่าคุณสมบัติ เช่น การเบิร์นอิน และ การทำให้ผอมบาง เมื่อดำเนินการขั้นตอนการอนุมานนี้ Burnin จะละเว้นค่าจากการวนซ้ำ n ครั้งแรก ซึ่งทำให้โมเดลย้ายออกจากจุดเริ่มต้นที่น่าจะเป็นไปได้ต่ำก่อนที่จะเริ่มสุ่มตัวอย่าง การทำให้ผอมบางจะลดความสัมพันธ์อัตโนมัติที่เกิดจากขั้นตอน MCMC โดยพิจารณาเฉพาะค่าจากการวนซ้ำทุกๆ n ครั้ง
อนุมานความน่า จะเป็น การตั้งค่าของพารามิเตอร์บางส่วนหรือทั้งหมดในแบบจำลองจะคำนวณความน่าจะเป็นในการสร้างค่าเหล่านั้น ซึ่งสามารถคำนวณได้สำหรับแต่ละตัวแปรในโมเดลและสำหรับโมเดลโดยรวม
ดำเนินการโมเดล รันโมเดลราวกับว่าเป็นโค้ดปกติที่สร้างค่าใหม่สำหรับพารามิเตอร์ใดๆ ที่ผู้ใช้ไม่ได้รับการแก้ไข ตัวอย่างว่าเมื่อใดที่ลักษณะการทำงานนี้จะถูกนำมาใช้คือสำหรับโมเดลการถดถอยเชิงเส้น ในกรณีนี้ ค่าสัมประสิทธิ์แบบจำลองจะถูกอนุมานโดยใช้ข้อมูลการฝึกอบรมก่อน เมื่อพวกเขาได้รับการอนุมานแล้วพวกเขาจะได้รับการแก้ไขและชุดข้อมูลอินพุตใหม่ จากนั้นแบบจำลองจะถูกดำเนินการเพื่อสร้างการคาดการณ์ที่สอดคล้องกันสำหรับข้อมูลอินพุตใหม่นี้ รูปแบบการดำเนินการนี้ยังสามารถใช้เพื่อสร้างข้อมูลสังเคราะห์ที่เป็นตัวแทนจากแบบจำลองที่ผ่านการฝึกอบรมแล้ว
สร้างและฝึกแบบจำลอง
//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 และ/หรือบริษัทในเครือ
เผยแพร่ภายใต้ Universal Permissive License v1.0 ดังแสดงที่ https://oss.oracle.com/licenses/upl/