Skip to content

Commit 93091b8

Browse files
authored
Merge pull request #70 from comet-ml/CM-1580-log-curve-asset
[CM-1580]: Log curve type of the asset
2 parents 030c124 + 01d6e4e commit 93091b8

File tree

17 files changed

+375
-5
lines changed

17 files changed

+375
-5
lines changed

comet-examples/src/main/java/ml/comet/examples/BaseExample.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package ml.comet.examples;
22

33
import ml.comet.experiment.OnlineExperiment;
4+
import ml.comet.experiment.model.Curve;
5+
import ml.comet.experiment.model.DataPoint;
46
import org.apache.commons.io.file.PathUtils;
57

68
import java.io.IOException;
@@ -10,6 +12,7 @@
1012
import java.util.Map;
1113
import java.util.Objects;
1214

15+
import static java.lang.Math.log;
1316
import static ml.comet.examples.Utils.getResourceFile;
1417
import static ml.comet.examples.Utils.readResourceToString;
1518

@@ -78,4 +81,12 @@ static Map<String, Object> createMetaData() {
7881
metadata.put("someBoolean", true);
7982
return metadata;
8083
}
84+
85+
static Curve buildCurve(String name, int pointsCount) {
86+
DataPoint[] dataPoints = new DataPoint[pointsCount];
87+
for (int i = 0; i < pointsCount; i++) {
88+
dataPoints[i] = DataPoint.of(i, (float) log((i + 1) * 10));
89+
}
90+
return new Curve(dataPoints, name);
91+
}
8192
}

comet-examples/src/main/java/ml/comet/examples/OnlineExperimentExample.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import ml.comet.experiment.ExperimentBuilder;
44
import ml.comet.experiment.OnlineExperiment;
55
import ml.comet.experiment.context.ExperimentContext;
6+
import ml.comet.experiment.model.Curve;
67
import org.apache.commons.io.file.PathUtils;
78

89
import java.net.URI;
@@ -77,6 +78,10 @@ private static void run(OnlineExperiment experiment) throws Exception {
7778
.withStep(12).build(),
7879
SOME_METADATA);
7980

81+
Curve curve = BaseExample.buildCurve("Sample curve", 100);
82+
experiment.logCurve(curve, false);
83+
84+
8085
// upload assets
8186
//
8287
experiment.uploadAsset(getResourceFile(CHART_IMAGE_FILE), "amazing chart.png", false);

comet-java-client/src/main/java/ml/comet/experiment/Experiment.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import ml.comet.experiment.artifact.LoggedArtifact;
55
import ml.comet.experiment.asset.LoggedExperimentAsset;
66
import ml.comet.experiment.context.ExperimentContext;
7+
import ml.comet.experiment.model.Curve;
78
import ml.comet.experiment.model.ExperimentMetadata;
89
import ml.comet.experiment.model.GitMetaData;
910
import ml.comet.experiment.model.Value;
@@ -322,6 +323,19 @@ public interface Experiment extends AutoCloseable {
322323

323324
void logText(String text);
324325

326+
/**
327+
* Allows to log x/y curve into your Comet experiment. This can be, for example, the time-series data, etc.
328+
*
329+
* @param curve the {@code Curve} object holding the data points.
330+
* @param overwrite allows to override the previously logged curve with the same name.
331+
* @param context the experiment context to be associated with data record (step, epoch, context ID).
332+
*/
333+
void logCurve(Curve curve, boolean overwrite, ExperimentContext context);
334+
335+
void logCurve(Curve curve, boolean overwrite);
336+
337+
void logCurve(Curve curve);
338+
325339
/**
326340
* Upload an asset to be associated with the experiment, for example the trained weights of a neural net.
327341
* For running experiment updates current step to one from param!

comet-java-client/src/main/java/ml/comet/experiment/impl/BaseExperiment.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import ml.comet.experiment.impl.utils.ExceptionUtils;
4242
import ml.comet.experiment.impl.utils.FileUtils;
4343
import ml.comet.experiment.impl.utils.SystemUtils;
44+
import ml.comet.experiment.model.Curve;
4445
import ml.comet.experiment.model.ExperimentMetadata;
4546
import ml.comet.experiment.model.GitMetaData;
4647
import ml.comet.experiment.model.Value;
@@ -95,6 +96,7 @@
9596
import static ml.comet.experiment.impl.resources.LogMessages.GET_ARTIFACT_FAILED_UNEXPECTEDLY;
9697
import static ml.comet.experiment.impl.resources.LogMessages.REMOTE_ASSET_CANNOT_BE_DOWNLOADED;
9798
import static ml.comet.experiment.impl.resources.LogMessages.getString;
99+
import static ml.comet.experiment.impl.utils.AssetUtils.createAssetFromCurve;
98100
import static ml.comet.experiment.impl.utils.AssetUtils.createAssetFromData;
99101
import static ml.comet.experiment.impl.utils.AssetUtils.createAssetFromFile;
100102
import static ml.comet.experiment.impl.utils.RestApiUtils.createArtifactUpsertRequest;
@@ -450,7 +452,7 @@ public void logCode(File file) {
450452
}
451453

452454
@Override
453-
public void logText(String text, ExperimentContext context, Map<String, Object> metadata) {
455+
public void logText(@NonNull String text, @NonNull ExperimentContext context, Map<String, Object> metadata) {
454456
if (getLogger().isDebugEnabled()) {
455457
getLogger().debug("logging text {} with context {}", text, context);
456458
}
@@ -461,7 +463,7 @@ public void logText(String text, ExperimentContext context, Map<String, Object>
461463
}
462464

463465
@Override
464-
public void logText(String text, ExperimentContext context) {
466+
public void logText(String text, @NonNull ExperimentContext context) {
465467
this.logText(text, context, null);
466468
}
467469

@@ -470,6 +472,25 @@ public void logText(String text) {
470472
this.logText(text, ExperimentContext.empty());
471473
}
472474

475+
@Override
476+
public void logCurve(@NonNull Curve curve, boolean overwrite, @NonNull ExperimentContext context) {
477+
if (getLogger().isDebugEnabled()) {
478+
getLogger().debug("logging curve {} with context {}", curve, context);
479+
}
480+
AssetImpl asset = createAssetFromCurve(curve, overwrite);
481+
this.logAsset(asset, context);
482+
}
483+
484+
@Override
485+
public void logCurve(@NonNull Curve curve, boolean overwrite) {
486+
this.logCurve(curve, overwrite, ExperimentContext.empty());
487+
}
488+
489+
@Override
490+
public void logCurve(@NonNull Curve curve) {
491+
this.logCurve(curve, false);
492+
}
493+
473494
@Override
474495
public void uploadAsset(@NonNull File file, @NonNull String logicalPath,
475496
boolean overwrite, @NonNull ExperimentContext context) {

comet-java-client/src/main/java/ml/comet/experiment/impl/BaseExperimentAsync.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ void logAssetFileAsync(@NonNull File file, @NonNull String fileName, boolean ove
575575
* either successful or failure.
576576
*/
577577
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
578-
private void logAssetAsync(@NonNull final Asset asset, @NonNull ExperimentContext context,
578+
void logAssetAsync(@NonNull final Asset asset, @NonNull ExperimentContext context,
579579
@NonNull Optional<Action> onComplete) {
580580
this.logAssetAsync(getRestApiClient()::logAsset, asset, context, onComplete);
581581
}

comet-java-client/src/main/java/ml/comet/experiment/impl/OnlineExperimentImpl.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import ml.comet.experiment.artifact.LoggedArtifact;
1010
import ml.comet.experiment.context.ExperimentContext;
1111
import ml.comet.experiment.exception.CometApiException;
12+
import ml.comet.experiment.impl.asset.AssetImpl;
1213
import ml.comet.experiment.impl.asset.AssetType;
1314
import ml.comet.experiment.impl.log.StdOutLogger;
1415
import ml.comet.experiment.impl.rest.ExperimentStatusResponse;
16+
import ml.comet.experiment.model.Curve;
1517
import ml.comet.experiment.model.GitMetaData;
1618
import org.awaitility.Awaitility;
1719
import org.slf4j.Logger;
@@ -47,12 +49,14 @@
4749
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_ASSET;
4850
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_ASSET_FOLDER;
4951
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_CODE_ASSET;
52+
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_CURVE_ASSET;
5053
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_MODEL_ASSET;
5154
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_MODEL_FOLDER;
5255
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_REMOTE_ASSET;
5356
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_LOG_TEXT_ASSET;
5457
import static ml.comet.experiment.impl.resources.LogMessages.TIMEOUT_FOR_EXPERIMENT_INVENTORY_CLEANUP;
5558
import static ml.comet.experiment.impl.resources.LogMessages.getString;
59+
import static ml.comet.experiment.impl.utils.AssetUtils.createAssetFromCurve;
5660

5761
/**
5862
* The implementation of the {@link OnlineExperiment} to work with Comet API asynchronously.
@@ -466,7 +470,7 @@ public void logCode(@NonNull File file) {
466470
}
467471

468472
@Override
469-
public void logText(String text, ExperimentContext context, Map<String, Object> metadata) {
473+
public void logText(@NonNull String text, @NonNull ExperimentContext context, Map<String, Object> metadata) {
470474
this.executeLogAction(() ->
471475
this.logAssetDataAsync(
472476
text.getBytes(StandardCharsets.UTF_8), AUTOGENERATED_LOGICAL_PATH_HOLDER,
@@ -476,7 +480,7 @@ public void logText(String text, ExperimentContext context, Map<String, Object>
476480
}
477481

478482
@Override
479-
public void logText(String text, ExperimentContext context) {
483+
public void logText(String text, @NonNull ExperimentContext context) {
480484
this.logText(text, context, null);
481485
}
482486

@@ -485,6 +489,24 @@ public void logText(String text) {
485489
this.logText(text, ExperimentContext.empty());
486490
}
487491

492+
@Override
493+
public void logCurve(@NonNull Curve curve, boolean overwrite, @NonNull ExperimentContext context) {
494+
AssetImpl asset = createAssetFromCurve(curve, overwrite);
495+
this.executeLogAction(() -> this.logAssetAsync(
496+
asset, context, this.getLogAssetOnCompleteAction()),
497+
this.assetsInProgress, getString(FAILED_TO_LOG_CURVE_ASSET));
498+
}
499+
500+
@Override
501+
public void logCurve(@NonNull Curve curve, boolean overwrite) {
502+
this.logCurve(curve, overwrite, ExperimentContext.empty());
503+
}
504+
505+
@Override
506+
public void logCurve(@NonNull Curve curve) {
507+
this.logCurve(curve, false);
508+
}
509+
488510
@Override
489511
public CompletableFuture<LoggedArtifact> logArtifact(Artifact artifact) throws ArtifactException {
490512
this.checkExperimentActiveState();

comet-java-client/src/main/java/ml/comet/experiment/impl/resources/LogMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public class LogMessages {
5555
public static final String FAILED_TO_LOG_REMOTE_ASSET = "FAILED_TO_LOG_REMOTE_ASSET";
5656
public static final String FAILED_TO_LOG_CODE_ASSET = "FAILED_TO_LOG_CODE_ASSET";
5757
public static final String FAILED_TO_LOG_TEXT_ASSET = "FAILED_TO_LOG_TEXT_ASSET";
58+
public static final String FAILED_TO_LOG_CURVE_ASSET = "FAILED_TO_LOG_CURVE_ASSET";
5859
public static final String FAILED_TO_LOG_SOME_ASSET_FROM_FOLDER = "FAILED_TO_LOG_SOME_ASSET_FROM_FOLDER";
5960
public static final String ARTIFACT_NOT_FOUND = "ARTIFACT_NOT_FOUND";
6061
public static final String ARTIFACT_NOT_READY = "ARTIFACT_NOT_READY";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package ml.comet.experiment.impl.rest;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import lombok.Data;
5+
import ml.comet.experiment.model.Curve;
6+
import ml.comet.experiment.model.DataPoint;
7+
8+
@Data
9+
@JsonInclude(JsonInclude.Include.NON_NULL)
10+
@SuppressWarnings("checkstyle:MemberName")
11+
public class CurveData {
12+
private String name;
13+
private float[] x;
14+
private float[] y;
15+
16+
private CurveData() {
17+
}
18+
19+
/**
20+
* The factory to create data from provided {@code Curve} instance.
21+
*
22+
* @param curve the {@code Curve} instance.
23+
* @return the initialized data holder.
24+
*/
25+
public static CurveData from(Curve curve) {
26+
CurveData data = new CurveData();
27+
data.name = curve.getName();
28+
DataPoint[] dataPoints = curve.getDataPoints();
29+
data.x = new float[dataPoints.length];
30+
data.y = new float[dataPoints.length];
31+
for (int i = 0; i < dataPoints.length; i++) {
32+
data.x[i] = dataPoints[i].getX();
33+
data.y[i] = dataPoints[i].getY();
34+
}
35+
return data;
36+
}
37+
}

comet-java-client/src/main/java/ml/comet/experiment/impl/utils/AssetUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
import ml.comet.experiment.impl.asset.AssetImpl;
88
import ml.comet.experiment.impl.asset.AssetType;
99
import ml.comet.experiment.impl.asset.RemoteAssetImpl;
10+
import ml.comet.experiment.impl.rest.CurveData;
11+
import ml.comet.experiment.model.Curve;
1012
import org.apache.commons.io.FilenameUtils;
1113
import org.apache.commons.lang3.StringUtils;
1214

1315
import java.io.File;
1416
import java.io.IOException;
1517
import java.net.URI;
18+
import java.nio.charset.StandardCharsets;
1619
import java.nio.file.Path;
1720
import java.util.Locale;
1821
import java.util.Map;
1922
import java.util.Optional;
2023
import java.util.stream.Stream;
2124

25+
import static ml.comet.experiment.impl.asset.AssetType.CURVE;
2226
import static ml.comet.experiment.impl.asset.AssetType.POINTS_3D;
2327
import static ml.comet.experiment.impl.asset.AssetType.UNKNOWN;
2428

@@ -128,6 +132,20 @@ public static AssetImpl createAssetFromData(byte[] data, @NonNull String logical
128132
return updateAsset(asset, overwrite, metadata, type);
129133
}
130134

135+
/**
136+
* Creates {@code Asset} from provided {@code Curve} instance.
137+
*
138+
* @param curve the {@code Curve} instance with data points.
139+
* @param overwrite if {@code true} mark as override
140+
* @return the instance of the {@link AssetImpl} with file-like data.
141+
*/
142+
public static AssetImpl createAssetFromCurve(@NonNull Curve curve, boolean overwrite) {
143+
CurveData data = CurveData.from(curve);
144+
String json = JsonUtils.toJson(data);
145+
return createAssetFromData(json.getBytes(StandardCharsets.UTF_8), curve.getName(), overwrite,
146+
Optional.empty(), Optional.of(CURVE.type()));
147+
}
148+
131149
/**
132150
* Updates provided {@link AssetImpl} with values from optionals or with defaults.
133151
*
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package ml.comet.experiment.model;
2+
3+
import lombok.Data;
4+
import lombok.NonNull;
5+
6+
/**
7+
* Represents data of the curve as x/y pairs.
8+
*/
9+
@Data
10+
@SuppressWarnings("checkstyle:MemberName")
11+
public class Curve {
12+
private DataPoint[] dataPoints;
13+
private String name;
14+
15+
/**
16+
* Creates new instance with specified parameters.
17+
*
18+
* @param dataPoints the curve data points.
19+
* @param name the name of the curve.
20+
*/
21+
public Curve(@NonNull DataPoint[] dataPoints, @NonNull String name) {
22+
this.dataPoints = dataPoints;
23+
this.name = name;
24+
}
25+
}

0 commit comments

Comments
 (0)