Skip to content

Move the Torch wrapper to the separate module #821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include 'utbot-sample'
include 'utbot-fuzzers'
include 'utbot-junit-contest'
include 'utbot-analytics'
include 'utbot-analytics-torch'
include 'utbot-cli'
include 'utbot-api'
include 'utbot-instrumentation'
Expand Down
63 changes: 63 additions & 0 deletions utbot-analytics-torch/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
apply from: "${parent.projectDir}/gradle/include/jvm-project.gradle"

configurations {
torchmodels
}

def osName = System.getProperty('os.name').toLowerCase().split()[0]
if (osName == "mac") osName = "macosx"
String classifier = osName + "-x86_64"

evaluationDependsOn(':utbot-framework')
compileTestJava.dependsOn tasks.getByPath(':utbot-framework:testClasses')

dependencies {
api project(':utbot-analytics')
testImplementation project(':utbot-sample')
testImplementation group: 'junit', name: 'junit', version: junit4_version

implementation group: 'org.bytedeco', name: 'arpack-ng', version: "3.7.0-1.5.4", classifier: "$classifier"
implementation group: 'org.bytedeco', name: 'openblas', version: "0.3.10-1.5.4", classifier: "$classifier"
implementation group: 'org.bytedeco', name: 'javacpp', version: javacpp_version, classifier: "$classifier"
implementation group: 'org.jsoup', name: 'jsoup', version: jsoup_version

implementation "ai.djl:api:$djl_api_version"
implementation "ai.djl.pytorch:pytorch-engine:$djl_api_version"
implementation "ai.djl.pytorch:pytorch-native-auto:$pytorch_native_version"

testImplementation project(':utbot-framework').sourceSets.test.output
}

test {
minHeapSize = "128m"
maxHeapSize = "3072m"

jvmArgs '-XX:MaxHeapSize=3072m'

useJUnitPlatform() {
excludeTags 'slow', 'IntegrationTest'
}
}

processResources {
configurations.torchmodels.resolvedConfiguration.resolvedArtifacts.each { artifact ->
from(zipTree(artifact.getFile())) {
into "models"
}
}
}

jar {
dependsOn classes
manifest {
attributes 'Main-Class': 'org.utbot.QualityAnalysisKt'
}

dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}

duplicatesStrategy = DuplicatesStrategy.EXCLUDE
zip64 = true
}
10 changes: 10 additions & 0 deletions utbot-analytics-torch/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
To enable support of the `utbot-analytics-torch` models in `utbot-intellij` module the following steps should be made:

- change the row `api project(':utbot-analytics-torch')` to the `api project(':utbot-analytics-torch')` in the `build.gradle` file in the `utbot-intellij` module
- change the `pathSelectorType` in the `UtSettings.kt` to the `PathSelectorType.TORCH_SELECTOR`
- don't forget the put the Torch model in the path ruled by the setting `modelPath` in the `UtSettings.kt`

NOTE: for Windows you could obtain the error message related to the "engine not found problem" from DJL library during the Torch model initialization.
The proposed solution from DJL authors includes the installation of the [Microsoft Visual C++ Redistributable.](https://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170)

But at this moment it doesn't work on Windows at all.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.utbot

import org.utbot.analytics.EngineAnalyticsContext
import org.utbot.features.FeatureExtractorFactoryImpl
import org.utbot.features.FeatureProcessorWithStatesRepetitionFactory
import org.utbot.predictors.StateRewardPredictorWithTorchModelsSupportFactoryImpl

/**
* The basic configuration of the utbot-analytics-torch module used in utbot-intellij and (as planned) in utbot-cli
* to implement the hidden configuration initialization to avoid direct calls of this configuration and usage of utbot-analytics-torch imports.
*
* @see <a href="https://github.com/UnitTestBot/UTBotJava/issues/725">
* Issue: Enable utbot-analytics module in utbot-intellij module</a>
*/
object AnalyticsTorchConfiguration {
init {
EngineAnalyticsContext.featureProcessorFactory = FeatureProcessorWithStatesRepetitionFactory()
EngineAnalyticsContext.featureExtractorFactory = FeatureExtractorFactoryImpl()
EngineAnalyticsContext.stateRewardPredictorFactory = StateRewardPredictorWithTorchModelsSupportFactoryImpl()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.utbot.predictors

import org.utbot.analytics.StateRewardPredictorFactory
import org.utbot.framework.UtSettings

/**
* Creates [StateRewardPredictor], by checking the [UtSettings] configuration.
*/
class StateRewardPredictorWithTorchModelsSupportFactoryImpl : StateRewardPredictorFactory {
override operator fun invoke() = StateRewardPredictorTorch()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import java.io.Closeable
import java.nio.file.Paths

class StateRewardPredictorTorch : StateRewardPredictor, Closeable {
val model: Model = Model.newInstance("model")
val model: Model

init {
model.load(Paths.get(UtSettings.rewardModelPath, "model.pt1"))
model = Model.newInstance("model")
model.load(Paths.get(UtSettings.modelPath, "model.pt1"))
}

private val predictor: Predictor<List<Float>, Float> = model.newPredictor(object : Translator<List<Float>, Float> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.utbot.predictors

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.utbot.analytics.StateRewardPredictor
import org.utbot.testcheckers.withModelPath
import kotlin.system.measureNanoTime

class NNStateRewardPredictorTest {
@Test
@Disabled("Just to see the performance of predictors")
fun simpleTest() {
withModelPath("src/test/resources") {
val pred = StateRewardPredictorTorch()

val features = listOf(0.0, 0.0)

assertEquals(5.0, pred.predict(features))
}
}

@Disabled("Just to see the performance of predictors")
@Test
fun performanceTest() {
val features = (1..13).map { 1.0 }.toList()
withModelPath("models") {
val averageTime = calcAverageTimeForModelPredict(::StateRewardPredictorTorch, 100, features)
println(averageTime)
}
}

private fun calcAverageTimeForModelPredict(
model: () -> StateRewardPredictor,
iterations: Int,
features: List<Double>
): Double {
val pred = model()

(1..iterations).map {
pred.predict(features)
}

return (1..iterations)
.map { measureNanoTime { pred.predict(features) } }
.average()
}
}
40 changes: 40 additions & 0 deletions utbot-analytics-torch/src/test/resources/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<RollingFile name="FrameworkAppender"
fileName="logs/utbot.log"
filePattern="logs/utbot-%d{MM-dd-yyyy-HH-mm-ss}.log.gz"
ignoreExceptions="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} | %-5level | %c{1} | %msg%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="100 MB"/>
</Policies>
</RollingFile>

<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} | %-5level | %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="smile" level="trace">
<AppenderRef ref="Console"/>
</Logger>


<Logger name="org.utbot.models" level="trace"/>

<Logger name="org.utbot" level="debug">
<AppenderRef ref="FrameworkAppender"/>
</Logger>

<!-- uncomment to log solver check -->
<!-- <Logger name="org.utbot.engine.pc" level="trace">-->
<!-- <AppenderRef ref="Console"/>-->
<!-- </Logger>-->

<Root level="info">
<!-- <AppenderRef ref="Console"/>-->
</Root>
</Loggers>
</Configuration>
22 changes: 7 additions & 15 deletions utbot-analytics/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ evaluationDependsOn(':utbot-framework')
compileTestJava.dependsOn tasks.getByPath(':utbot-framework:testClasses')

dependencies {
implementation(project(":utbot-api"))
implementation(project(":utbot-core"))
implementation(project(":utbot-summary"))
implementation(project(":utbot-framework-api"))
implementation(project(":utbot-fuzzers"))
implementation(project(":utbot-instrumentation"))
implementation(project(":utbot-framework"))
api(project(":utbot-api"))
api(project(":utbot-core"))
api(project(":utbot-summary"))
api(project(":utbot-framework-api"))
api(project(":utbot-fuzzers"))
api(project(":utbot-instrumentation"))
api(project(":utbot-framework"))
testImplementation project(':utbot-sample')
testImplementation group: 'junit', name: 'junit', version: junit4_version

Expand All @@ -38,20 +38,12 @@ dependencies {
implementation group: 'tech.tablesaw', name: 'tablesaw-jsplot', version: '0.38.2'

implementation group: 'org.apache.commons', name: 'commons-text', version: '1.9'

implementation group: 'com.github.javaparser', name: 'javaparser-core', version: '3.22.1'

implementation group: 'org.jsoup', name: 'jsoup', version: jsoup_version

implementation "ai.djl:api:$djl_api_version"
implementation "ai.djl.pytorch:pytorch-engine:$djl_api_version"
implementation "ai.djl.pytorch:pytorch-native-auto:$pytorch_native_version"

testImplementation project(':utbot-framework').sourceSets.test.output
}

test {

minHeapSize = "128m"
maxHeapSize = "3072m"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private val logger = KotlinLogging.logger {}
* Last weight is bias
*/
private fun loadWeights(path: String): Matrix {
val weightsFile = File("${UtSettings.rewardModelPath}/${path}")
val weightsFile = File("${UtSettings.modelPath}/${path}")
lateinit var weightsArray: DoubleArray

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ data class NNJson(
}

internal fun loadModel(path: String): NNJson {
val modelFile = Paths.get(UtSettings.rewardModelPath, path).toFile()
val modelFile = Paths.get(UtSettings.modelPath, path).toFile()
lateinit var nnJson: NNJson

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import org.utbot.framework.UtSettings
class StateRewardPredictorFactoryImpl : StateRewardPredictorFactory {
override operator fun invoke() = when (UtSettings.stateRewardPredictorType) {
StateRewardPredictorType.BASE -> NNStateRewardPredictorBase()
StateRewardPredictorType.TORCH -> StateRewardPredictorTorch()
StateRewardPredictorType.LINEAR -> LinearStateRewardPredictor()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ data class StandardScaler(val mean: Matrix?, val variance: Matrix?)

internal fun loadScaler(path: String): StandardScaler =
try {
Paths.get(UtSettings.rewardModelPath, path).toFile().bufferedReader().use {
Paths.get(UtSettings.modelPath, path).toFile().bufferedReader().use {
val mean = it.readLine()?.splitByCommaIntoDoubleArray() ?: error("There is not mean in $path")
val variance = it.readLine()?.splitByCommaIntoDoubleArray() ?: error("There is not variance in $path")
StandardScaler(Matrix(mean), Matrix(variance))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import org.junit.jupiter.api.Test
import org.utbot.framework.PathSelectorType
import org.utbot.framework.UtSettings
import org.utbot.testcheckers.withPathSelectorType
import org.utbot.testcheckers.withRewardModelPath
import org.utbot.testcheckers.withModelPath

class LinearStateRewardPredictorTest {
@Test
fun simpleTest() {
withRewardModelPath("src/test/resources") {
withModelPath("src/test/resources") {
val pred = LinearStateRewardPredictor()

val features = listOf(
Expand All @@ -24,8 +24,8 @@ class LinearStateRewardPredictorTest {

@Test
fun wrongFormatTest() {
withRewardModelPath("src/test/resources") {
withPathSelectorType(PathSelectorType.NN_REWARD_GUIDED_SELECTOR) {
withModelPath("src/test/resources") {
withPathSelectorType(PathSelectorType.ML_SELECTOR) {
LinearStateRewardPredictor("wrong_format_linear.txt")
assertEquals(PathSelectorType.INHERITORS_SELECTOR, UtSettings.pathSelectorType)
}
Expand All @@ -34,7 +34,7 @@ class LinearStateRewardPredictorTest {

@Test
fun simpleTestNotBatch() {
withRewardModelPath("src/test/resources") {
withModelPath("src/test/resources") {
val pred = LinearStateRewardPredictor()

val features = listOf(2.0, 3.0)
Expand Down
Loading