Skip to content
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

Metrics Phase 1 #180

Merged
merged 67 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
c57a2e7
Merge pull request #3 from tensorflow/master
JimClarke5 Oct 8, 2020
09fc07e
Merge pull request #4 from tensorflow/master
JimClarke5 Oct 27, 2020
a99dcb4
Merge pull request #5 from tensorflow/master
JimClarke5 Nov 17, 2020
ba294ea
Merge pull request #6 from tensorflow/master
JimClarke5 Nov 19, 2020
04f419a
Merge pull request #7 from tensorflow/master
JimClarke5 Dec 30, 2020
ad466ee
Initial checkin
JimClarke5 Jan 1, 2021
092b47d
Initial checkin and sync with master
JimClarke5 Jan 1, 2021
4887b5b
Initial checkin and sync with master
JimClarke5 Jan 1, 2021
04eeea6
JavaDoc cleanup
JimClarke5 Jan 1, 2021
dcb2414
Javadoc fixes
JimClarke5 Jan 3, 2021
82f18bf
Change LossInterface to LossMetric.
JimClarke5 Jan 5, 2021
9aa1511
Removed hashmap for variables, they are not needed as the variables o…
JimClarke5 Jan 7, 2021
1097722
reformat code
JimClarke5 Jan 7, 2021
bc0f468
Add tests for assertBroadcastable
JimClarke5 Jan 11, 2021
41876d5
Change type to resultType
JimClarke5 Jan 11, 2021
61af528
Added V data type for sampleWeights so that it is not forced to be th…
JimClarke5 Jan 11, 2021
c121c07
change 'type' to 'resultType'
JimClarke5 Jan 11, 2021
e9ee98f
clean up mean and fix assert assertBroadcastable
JimClarke5 Jan 11, 2021
9788983
fix error message
JimClarke5 Jan 11, 2021
8857a66
Change sampleWeights to have its own generic type <S extends TNumber>
JimClarke5 Jan 12, 2021
34a779f
Add commment about invalid tests expecting IllegalArgumentExceptions
JimClarke5 Jan 12, 2021
748f16d
Add this exception instead of the more generic IllegalArgumentExcepti…
JimClarke5 Jan 12, 2021
212541b
change IllegalArgumentException to NotBroadcastableException.
JimClarke5 Jan 12, 2021
f0d72d2
reformat code
JimClarke5 Jan 12, 2021
8b49c60
Fis=x Javadoc
JimClarke5 Jan 13, 2021
20c6e98
Fix Reduce to use boradcastWeights,
JimClarke5 Jan 17, 2021
d3d7ee9
Added comment to count to indicate that it may be weighted.
JimClarke5 Jan 17, 2021
fe86b0b
Added SetsOps and fixed AssertBroadcastable to use SetsOps methods,
JimClarke5 Jan 19, 2021
0edd114
Fixed based on various PR comments.
JimClarke5 Jan 19, 2021
7d78fd3
Deleted, no longer needed after change to Variable handling in Metrics.
JimClarke5 Jan 19, 2021
02e7ebf
Merge pull request #8 from tensorflow/master
JimClarke5 Jan 29, 2021
af1b49f
Nicer error messages for mode-forbidden ops (#169)
rnett Jan 2, 2021
7732601
Initialization imprvements (#178)
rnett Jan 7, 2021
a737334
Clairify tensorOf lifetime requirements (#190)
rnett Jan 19, 2021
253cc73
Remove extra generics from op generation (#193)
rnett Jan 26, 2021
22cb5b2
Add Java 11 support - Initial Phase (#185)
JimClarke5 Jan 26, 2021
4d1aa20
Update manual ops for new codegen (#196)
rnett Jan 26, 2021
2b7f6ed
Fix Losses to use CHANNELS_FIRST/LAST for CategoricalCrossentropy
JimClarke5 Jan 20, 2021
3800b71
Fix SetOps to properly convert sparse tensor to dense tensor using tf…
JimClarke5 Jan 30, 2021
3045999
Initial checkin
JimClarke5 Jan 1, 2021
9eb5adf
Initial checkin and sync with master
JimClarke5 Jan 1, 2021
187c17c
Initial checkin and sync with master
JimClarke5 Jan 1, 2021
050fe28
JavaDoc cleanup
JimClarke5 Jan 1, 2021
b640406
Javadoc fixes
JimClarke5 Jan 3, 2021
3715513
Change LossInterface to LossMetric.
JimClarke5 Jan 5, 2021
a1c1976
Removed hashmap for variables, they are not needed as the variables o…
JimClarke5 Jan 7, 2021
6641fca
reformat code
JimClarke5 Jan 7, 2021
fa76043
Add tests for assertBroadcastable
JimClarke5 Jan 11, 2021
e136f4d
Change type to resultType
JimClarke5 Jan 11, 2021
e00f2ef
Added V data type for sampleWeights so that it is not forced to be th…
JimClarke5 Jan 11, 2021
bc6c64b
change 'type' to 'resultType'
JimClarke5 Jan 11, 2021
02da963
clean up mean and fix assert assertBroadcastable
JimClarke5 Jan 11, 2021
44cdc35
fix error message
JimClarke5 Jan 11, 2021
49370b9
Change sampleWeights to have its own generic type <S extends TNumber>
JimClarke5 Jan 12, 2021
24b4125
Add commment about invalid tests expecting IllegalArgumentExceptions
JimClarke5 Jan 12, 2021
43c6b7b
Add this exception instead of the more generic IllegalArgumentExcepti…
JimClarke5 Jan 12, 2021
78e9dab
change IllegalArgumentException to NotBroadcastableException.
JimClarke5 Jan 12, 2021
5508969
reformat code
JimClarke5 Jan 12, 2021
c662524
Fis=x Javadoc
JimClarke5 Jan 13, 2021
512a153
Fix Reduce to use boradcastWeights,
JimClarke5 Jan 17, 2021
0663c3c
Added comment to count to indicate that it may be weighted.
JimClarke5 Jan 17, 2021
122e06b
Added SetsOps and fixed AssertBroadcastable to use SetsOps methods,
JimClarke5 Jan 19, 2021
b7b14b1
Fixed based on various PR comments.
JimClarke5 Jan 19, 2021
13639d3
Deleted, no longer needed after change to Variable handling in Metrics.
JimClarke5 Jan 19, 2021
561322f
Fix Losses to use CHANNELS_FIRST/LAST for CategoricalCrossentropy
JimClarke5 Jan 20, 2021
2a13012
Fix SetOps to properly convert sparse tensor to dense tensor using tf…
JimClarke5 Jan 30, 2021
36f3a69
Merge remote-tracking branch 'upstream/metrics1' into metrics1
JimClarke5 Jan 30, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
public class CategoricalCrossentropy extends Loss {
public static final boolean FROM_LOGITS_DEFAULT = false;
public static final float LABEL_SMOOTHING_DEFAULT = 0.0f;
public static final int DEFAULT_AXIS = -1;
public static final int DEFAULT_AXIS = Losses.CHANNELS_LAST;

private final boolean fromLogits;
private final float labelSmoothing;
Expand Down Expand Up @@ -203,8 +203,9 @@ public CategoricalCrossentropy(
* confidence on label values are relaxed. e.g. <code>labelSmoothing=0.2</code> means that we will use a
* value of <code>0.1</code> for label <code>0</code> and <code>0.9</code> for label <code>1</code>
* @param reduction Type of Reduction to apply to loss.
* @param axis The channels axis. <code>axis=-1</code> corresponds to data format `Channels Last'
* and <code>axis=1</code> corresponds to data format 'Channels First'.
* @param axis The channels axis. <code>axis=-1</code> corresponds to data format "Channels Last"
* and <code>axis=1</code> corresponds to data format "Channels First".
* {@link Losses#CHANNELS_LAST} and {@link Losses#CHANNELS_FIRST}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intend to add a "See" in front of the links?

* @throws IllegalArgumentException if labelSmoothing is not in the inclusive range of 0. - 1.
*/
public CategoricalCrossentropy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class Losses {
/** Default Fuzz factor. */
public static final float EPSILON = 1e-7f;

public static final int CHANNELS_LAST = -1;
public static final int CHANNELS_FIRST = 1;

/**
* Calculates the mean absolute error between labels and predictions.
*
Expand Down Expand Up @@ -239,7 +242,7 @@ public static <T extends TNumber, U extends TNumber> Operand<T> categoricalCross
tLabels = smoothCategoricalLabels(tf, tLabels, labelSmoothing);
}
if (fromLogits) {
return tf.nn.softmaxCrossEntropyWithLogits(tLabels, predictions, -1);
return tf.nn.softmaxCrossEntropyWithLogits(tLabels, predictions, axis);
}
/* TODO
if (!(predictions instanceof Variable) && (!tf.scope().env().isEager())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=======================================================================*/
package org.tensorflow.framework.metrics;

import org.tensorflow.Operand;
import org.tensorflow.framework.losses.Losses;
import org.tensorflow.framework.metrics.impl.LossMetric;
import org.tensorflow.framework.metrics.impl.MeanMetricWrapper;
import org.tensorflow.op.Ops;
import org.tensorflow.types.family.TNumber;

/**
* A Metric that computes the binary cross-entropy loss between true labels and predicted labels.
*
* <p>This is the crossentropy metric class to be used when there are only two label classes (0 and
* 1).
*
* @param <U> the data type for the predictions.
* @param <T> The data type for the metric result
*/
public class BinaryCrossentropy<U extends TNumber, T extends TNumber>
extends MeanMetricWrapper<U, T> implements LossMetric<T> {

private final boolean fromLogits;
private final float labelSmoothing;

/**
* Creates a BinaryCrossentropy metric
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param fromLogits Whether to interpret predictions as a tensor of logit values as opposed to a probability distribution.
* @param labelSmoothing value used to smooth labels, When 0, no smoothing occurs. When &gt; 0,
* compute the loss between the predicted labels and a smoothed version of the true labels,
* where the smoothing squeezes the labels towards 0.5. Larger values of label_smoothing
* correspond to heavier smoothing.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public BinaryCrossentropy(
Ops tf, String name, boolean fromLogits, float labelSmoothing, long seed, Class<T> type) {
super(tf, name, seed, type);
setLoss(this);
this.fromLogits = fromLogits;
this.labelSmoothing = labelSmoothing;
}

/** {@inheritDoc} */
@Override
public <V extends TNumber> Operand<T> call(Operand<V> labels, Operand<T> predictions) {
return Losses.binaryCrossentropy(getTF(), labels, predictions, fromLogits, labelSmoothing);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=======================================================================*/
package org.tensorflow.framework.metrics;

import org.tensorflow.Operand;
import org.tensorflow.framework.losses.Losses;
import org.tensorflow.framework.metrics.impl.LossMetric;
import org.tensorflow.framework.metrics.impl.MeanMetricWrapper;
import org.tensorflow.op.Ops;
import org.tensorflow.types.family.TNumber;

/**
* A Metric that computes the categorical cross-entropy loss between true labels and predicted
* labels.
*
* <p>This is the crossentropy metric class to be used when there are multiple label classes (2 or
* more). The labels should be given as a one_hot representation. eg., When labels values are <code>
* [2, 0, 1]</code>, the labels Operand contains = <code>[[0, 0, 1], [1, 0, 0], [0, 1, 0]]
* </code>.
*
* @param <U> the data type for the predictions.
* @param <T> The data type for the metric result
*/
public class CategoricalCrossentropy<U extends TNumber, T extends TNumber>
extends MeanMetricWrapper<U, T> implements LossMetric<T> {

private final boolean fromLogits;
private final float labelSmoothing;
private final int axis;

/**
* Creates a CategoricalCrossentropy metric that computes the crossentropy metric between the
* labels and predictions.
*
* <p>Uses a {@link Losses#CHANNELS_LAST} for the channel axis.
karllessard marked this conversation as resolved.
Show resolved Hide resolved
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param fromLogits Whether to interpret predictions as a tensor of logit values oras opposed to a probability distribution.
* @param labelSmoothing value used to smooth labels, When &gt; 0, label values are smoothed,
* meaning the confidence on label values are relaxed. e.g. <code>labelSmoothing=0.2</code>
* means that we will use a value of <code>0.1</code> for label <code>0</code> and <code>0.9
* </code> for label <code>1</code>
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CategoricalCrossentropy(
Ops tf, String name, boolean fromLogits, float labelSmoothing, long seed, Class<T> type) {
this(tf, name, fromLogits, labelSmoothing, Losses.CHANNELS_LAST, seed, type);
}

/**
* Creates a CategoricalCrossentropy metric that computes the crossentropy metric between the
* labels and predictions.
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param fromLogits Whether to interpret predictions as a tensor of logit values as opposed to a probability distribution.
* @param labelSmoothing value used to smooth labels, When &gt; 0, label values are smoothed,
* meaning the confidence on label values are relaxed. e.g. <code>labelSmoothing=0.2</code>
* means that we will use a value of <code>0.1</code> for label <code>0</code> and <code>0.9
* </code> for label <code>1</code>
* @param axis Int specifying the channels axis. <code>axis={@link Losses#CHANNELS_LAST}</code>
* corresponds to data format <code>channels_last</code>, and <code>
* axis={@link Losses#CHANNELS_FIRST}</code> corresponds to data format <code>
* channels_first</code>.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CategoricalCrossentropy(
Ops tf,
String name,
boolean fromLogits,
float labelSmoothing,
int axis,
long seed,
Class<T> type) {
super(tf, name, seed, type);
setLoss(this);
this.fromLogits = fromLogits;
this.labelSmoothing = labelSmoothing;
this.axis = axis;
}

/** {@inheritDoc} */
@Override
public <V extends TNumber> Operand<T> call(Operand<V> labels, Operand<T> predictions) {
return Losses.categoricalCrossentropy(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure there's a bug in the method called here, Losses.categoricalCrossentropy. I saw it while tracing through the uses of axis. org/tensorflow/framework/losses/Losses.java:245 reads:

      return tf.nn.softmaxCrossEntropyWithLogits(tLabels, predictions, -1);

I believe the final parameter should be axis instead of -1.

It's not a bug in this PR, of course, but perhaps worth fixing in this PR to reduce process?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In TF Python,losses.categorical_crossentropy calls the K.categorical_crossentropy(y_true, y_pred, from_logits=from_logits) with the default value for axis being -1. Therefore, the default value -1 was used here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-/ Isn't that a bug in TF Python? Seems clear that the axis parameter passed to softmaxCrossEntropyWithLogits (documented as "class dimension") should be the incoming axis parameter of Losses.categoricalCrossentropy?'

Interestingly, that latter axis parameter has a documentation glitch: its documentation says just "the". But it is the class axis. And in the method being reviewed by this comment, we pass our incoming axis parameter to it.

getTF(), labels, predictions, fromLogits, labelSmoothing, axis);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=======================================================================*/
package org.tensorflow.framework.metrics;

import org.tensorflow.Operand;
import org.tensorflow.framework.losses.Losses;
import org.tensorflow.framework.metrics.impl.LossMetric;
import org.tensorflow.framework.metrics.impl.MeanMetricWrapper;
import org.tensorflow.op.Ops;
import org.tensorflow.types.family.TNumber;

/**
* A Metric that computes the categorical hinge loss metric between labels and predictions.
*
* @param <U> the data type for the predictions.
* @param <T> The data type for the metric result
*/
public class CategoricalHinge<U extends TNumber, T extends TNumber> extends MeanMetricWrapper<U, T>
implements LossMetric<T> {

/**
* Creates a CategoricalHinge metric
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CategoricalHinge(Ops tf, String name, long seed, Class<T> type) {
super(tf, name, seed, type);
setLoss(this);
}

/** {@inheritDoc} */
@Override
public <V extends TNumber> Operand<T> call(Operand<V> labels, Operand<T> predictions) {
return Losses.categoricalHinge(getTF(), labels, predictions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=======================================================================*/
package org.tensorflow.framework.metrics;

import org.tensorflow.Operand;
import org.tensorflow.framework.metrics.impl.LossMetric;
import org.tensorflow.framework.metrics.impl.MeanMetricWrapper;
import org.tensorflow.op.Ops;
import org.tensorflow.types.family.TNumber;

/**
* A metric that computes the cosine similarity metric between labels and predictions.
*
* @param <U> the data type for the predictions.
* @param <T> The data type for the metric result.
*/
public class CosineSimilarity<U extends TNumber, T extends TNumber> extends MeanMetricWrapper<U, T>
implements LossMetric<T> {
public static final int DEFAULT_AXIS = -1;
private final int[] axis;

/**
* Creates a metric that computes the cosine similarity metric between labels and predictions with
* a default axis, {@link #DEFAULT_AXIS}
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CosineSimilarity(Ops tf, String name, long seed, Class<T> type) {
this(tf, name, DEFAULT_AXIS, seed, type);
}

/**
* Creates a metric that computes the cosine similarity metric between labels and predictions.
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param axis The dimension along which the cosine similarity is computed.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CosineSimilarity(Ops tf, String name, int axis, long seed, Class<T> type) {
this(tf, name, new int[] {axis}, seed, type);
}
/**
* Creates a CosineSimilarity metric
*
* @param tf the TensorFlow Ops
* @param name the name of this metric, if null then metric name is {@link Class#getSimpleName()}.
* @param axis The dimension along which the cosine similarity is computed.
* @param seed the seed for random number generation. An initializer created with a given seed
* will always produce the same random tensor for a given shape and data type.
* @param type the type for the variables and result
*/
public CosineSimilarity(Ops tf, String name, int[] axis, long seed, Class<T> type) {
super(tf, name, seed, type);
this.axis = axis;
setLoss(this);
}

/** {@inheritDoc} */
@Override
public <V extends TNumber> Operand<T> call(Operand<V> labels, Operand<T> predictions) {
// NOTE: cosineProximity is a different algorithm than Losses.cosineSimilarity
return Metrics.cosineProximity(getTF(), labels, predictions, axis);
}
}
Loading