Create rule S6908: "tf.function" should not be recursive (#3607)
* Create rule S6908 * Create rule S6908: "tf.function" should not be recursive. --------- Co-authored-by: joke1196 <joke1196@users.noreply.github.com> Co-authored-by: David Kunzmann <david.kunzmann@sonarsource.com>
This commit is contained in:
parent
9489f1c4a9
commit
15d9064b86
2
rules/S6908/metadata.json
Normal file
2
rules/S6908/metadata.json
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
23
rules/S6908/python/metadata.json
Normal file
23
rules/S6908/python/metadata.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"title": "\"tensorflow.function\" should not be recursive",
|
||||
"type": "CODE_SMELL",
|
||||
"status": "ready",
|
||||
"remediation": {
|
||||
"func": "Constant\/Issue",
|
||||
"constantCost": "5min"
|
||||
},
|
||||
"tags": [
|
||||
],
|
||||
"defaultSeverity": "Major",
|
||||
"ruleSpecification": "RSPEC-6908",
|
||||
"sqKey": "S6908",
|
||||
"scope": "All",
|
||||
"defaultQualityProfiles": ["Sonar way"],
|
||||
"quickfix": "unknown",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"RELIABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "CONVENTIONAL"
|
||||
}
|
||||
}
|
53
rules/S6908/python/rule.adoc
Normal file
53
rules/S6908/python/rule.adoc
Normal file
@ -0,0 +1,53 @@
|
||||
This rule raises an issue when a `tensorflow.function` is recursive.
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
When defining a `tensorflow.function` it is generally a bad practice to make this function recursive. TensorFlow does not
|
||||
support recursive `tensorflow.function` and will in the majority of cases throw an exception. However it is possible as
|
||||
well that the execution of such function succeeds, but with multiple tracings which has strong performance implications.
|
||||
When executing `tensorflow.function`, the code is split into two distinct stages.
|
||||
The first stage call `tracing` creates a new `tensorflow.Graph`, runs the Python code normally,
|
||||
but defers the execution of TensorFlow operations (i.e. adding two Tensors). These operations are added to the graph without being ran.
|
||||
The second stage which is much faster than the first, runs everything that was deferred previously.
|
||||
Depending on the input of the `tensorflow.function` the first stage may not be needed, see: https://www.tensorflow.org/guide/function#rules_of_tracing[Rules of tracing].
|
||||
Skipping this first stage is what provides the user with TensorFlow's high performance.
|
||||
|
||||
Having a recursive `tensorflow.function` prevents the user from benefiting of TensorFlow's capabilities.
|
||||
|
||||
== How to fix it
|
||||
|
||||
To fix this issue, refactor the `tensorflow.function` so that is it not recursive.
|
||||
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,python,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
import tensorflow as tf
|
||||
|
||||
@tf.function
|
||||
def factorial(n):
|
||||
if n == 1:
|
||||
return 1
|
||||
else:
|
||||
return (n * factorial(n-1)) # Noncompliant: the function is recursive
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,python,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
import tensorflow as tf
|
||||
|
||||
@tf.function
|
||||
def factorial(n):
|
||||
return tf.exp(tf.lgamma(n + 1)) # Compliant
|
||||
----
|
||||
|
||||
|
||||
== Resources
|
||||
=== Documentation
|
||||
|
||||
* TensorFlow Documentation - https://www.tensorflow.org/guide/function#recursive_tffunctions_are_not_supported[Recursive tf.functions are not supported]
|
||||
* TensorFlow Documentation - https://www.tensorflow.org/guide/function#rules_of_tracing[Rules of tracing]
|
Loading…
x
Reference in New Issue
Block a user