-
Notifications
You must be signed in to change notification settings - Fork 328
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
Extend docstrings of loss functions #64
Extend docstrings of loss functions #64
Conversation
…rning into extend_loss_docstring_#49
This class computes the L1 loss: sum |target - predict| | ||
""" | ||
|
||
def evaluate(self, predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When overridding a base class, where we have (and should have) documentation on base class method, there is no need to duplicate/repeat it on derived classes. The base class documentation is inherited via Sphinx which means it can be updated/managed in one place rather than having to deal with copies of it all over the place in derived classes. I think we can say in the base class that it Raises: QiskitMachineLearingError if the shape is incorrect or if used for a classification it does not support, e.g it can only handle binary but is given multiclass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
return self.evaluate(predict, target) | ||
|
||
@abstractmethod | ||
def evaluate(self, predict, target): | ||
""" evaluate """ | ||
def evaluate(self, predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see in the derived classes they document this returning a float and the meaning of the float. In which case I think the signature here should be updated to return a float ie def evaluate(self, predict: np.ndarray, target: np.ndarray) -> float:
and document here the meaning of that return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For both evaluate
and gradient
we expect them to return a float right so the caller of a concrete sub-class knows what to expect. Hence in the abstract methods here the signature should show the float return typehint and the Returns in the docstring document the meaning of the float. The docstrings here would then be complete meaning no docstring should be needed on the derived classes - which at present all have a copy/paste of the same Returns text when they should all just simply have no docstring i.e inherit the one from the base class.
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def gradient(self, predict, target): | ||
""" gradient """ | ||
def gradient(self, predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar comment on return value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
@woodsp-ibm if you could take a look again at the PR. |
return self.evaluate(predict, target) | ||
|
||
@abstractmethod | ||
def evaluate(self, predict, target): | ||
"""evaluate""" | ||
def evaluate(self, predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def evaluate(self, predict: np.ndarray, target: np.ndarray): | |
def evaluate(self, predict: np.ndarray, target: np.ndarray) -> float: |
The typehint should show it returns a float
Also there should be a Returns: entry in the docstring that states the meaning of the return value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def gradient(self, predict, target): | ||
"""gradient""" | ||
def gradient(self, predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def gradient(self, predict: np.ndarray, target: np.ndarray): | |
def gradient(self, predict: np.ndarray, target: np.ndarray) -> float: |
The typehint should show the return type
And likewise there should be a Returns: entry in the docstring that states the meaning of the return value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
raise NotImplementedError | ||
|
||
@staticmethod | ||
def _validate(predict, target): | ||
def _validate(predict: np.ndarray, target: np.ndarray): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def _validate(predict: np.ndarray, target: np.ndarray): | |
def _validate(predict: np.ndarray, target: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: |
The typehint should have the return type. The docstring has a Returns entry so thats good. Tuple will need importing from typing though for this.
I must admit this method is kinda confusing. If it just needs to validate the shapes why does it need to return them since the caller already has them? Now I see it makes a numpy array of them, but then the typehint says it takes a numpy array and not something like a list where I could see it adjusting the types as needed as well as doing some validation, with the (possibly) adjusted values returned,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
L1Loss: | ||
This class computes the L1 loss: sum |target - predict| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicating the name of the class into the docstring is not necessary; It should be a simple sentence summary, as you have there already, followed by further paragraph(s) of text describing things for more complicated classes that need it = which I do not think is the case here.
L1Loss: | |
This class computes the L1 loss: sum |target - predict| | |
This class computes the L1 loss: sum |target - predict| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
L2Loss: | ||
This class computes the L2 loss: sum (target - predict)^2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L2Loss: | |
This class computes the L2 loss: sum (target - predict)^2 | |
This class computes the L2 loss: sum (target - predict)^2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
""" | ||
|
||
def __call__(self, predict, target): | ||
def __call__(self, predict: Union[int, np.ndarray], target: Union[int, np.ndarray]) -> float: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is now either an integer or an numpy array. The args below mention just the numpy array not a single value. I see the single value is reformed to a numpy array. Does that mean the numpy arrays are arrays of ints too? I.e the predicted and target values are all ints. Maybe the Args docstring can be improved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is now either an integer or an numpy array. The args below mention just the numpy array not a single value. I see the single value is reformed to a numpy array. Does that mean the numpy arrays are arrays of ints too? I.e the predicted and target values are all ints. Maybe the Args docstring can be improved.
No more ints, just numpy arrays.
Args: | ||
predict: a numpy array of predicted values using the model | ||
target: a numpy array of the true values | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to have a Returns here to state what the float return is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to have a Returns here to state what the float return is
Added a Returns section.
Args: | ||
predict: a numpy array of predicted values using the model | ||
target: a numpy array of the true values | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again it would be good to have a Returns statement here for the float return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again it would be good to have a Returns statement here for the float return
Same here, added Returns.
def _validate(predict, target): | ||
def _validate( | ||
predict: Union[int, np.ndarray], target: Union[int, np.ndarray] | ||
) -> Tuple[np.ndarray, np.ndarray]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I pass in an 'int' and an 'int' as predict and target, I will not get back an Tuple of ints rather a Tuple of arrays? I guess its doing a type cast as well as validate that the other methods rely on. Not sure if it would be helpful to expose the duality in the name say _cast_validate
or _to_array_validate
- its a private method so maybe its less important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I pass in an 'int' and an 'int' as predict and target, I will not get back an Tuple of ints rather a Tuple of arrays? I guess its doing a type cast as well as validate that the other methods rely on. Not sure if it would be helpful to expose the duality in the name say
_cast_validate
or_to_array_validate
- its a private method so maybe its less important.
Now only numpy arrays, renamed to _validate_shapes
. I hope it is good enough now.
) | ||
return predict, target | ||
|
||
|
||
class L1Loss(Loss): | ||
"""L1Loss""" | ||
""" | ||
L1Loss: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the class will be in the docs from the class itself, it does not need to be put into the docstring as it will not really add any value. All it needs is the description of what this class is about ie. the L1Loss:
bit can simply be removed. Same in the other classes in this module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name of the class will be in the docs from the class itself, it does not need to be put into the docstring as it will not really add any value. All it needs is the description of what this class is about ie. the
L1Loss:
bit can simply be removed. Same in the other classes in this module.
Agree, docstrings are updated.
This PR revises documentation of the loss functions. Co-authored-by: Manoel Marques <Manoel.Marques@ibm.com> Co-authored-by: Anton Dekusar <62334182+adekusar-drl@users.noreply.github.com> Co-authored-by: Anton Dekusar <adekusar@ie.ibm.com>
Summary
Added docstrings.
Closes #49.