|
1202 | 1202 | "correct_a = leaky_function(tf.constant(1))\n",
|
1203 | 1203 | "\n",
|
1204 | 1204 | "print(correct_a.numpy()) # Good - value obtained from function's returns\n",
|
1205 |
| - "with assert_raises(AttributeError):\n", |
| 1205 | + "try:\n", |
1206 | 1206 | " x.numpy() # Bad - tensor leaked from inside the function, cannot be used here\n",
|
1207 |
| - "print(x)" |
| 1207 | + "except AttributeError as expected:\n", |
| 1208 | + " print(expected)" |
1208 | 1209 | ]
|
1209 | 1210 | },
|
1210 | 1211 | {
|
|
1233 | 1234 | "correct_a = leaky_function(tf.constant(1))\n",
|
1234 | 1235 | "\n",
|
1235 | 1236 | "print(correct_a.numpy()) # Good - value obtained from function's returns\n",
|
1236 |
| - "with assert_raises(AttributeError):\n", |
| 1237 | + "try:\n", |
1237 | 1238 | " x.numpy() # Bad - tensor leaked from inside the function, cannot be used here\n",
|
1238 |
| - "print(x)\n", |
| 1239 | + "except AttributeError as expected:\n", |
| 1240 | + " print(expected)\n", |
1239 | 1241 | "\n",
|
1240 | 1242 | "@tf.function\n",
|
1241 | 1243 | "def captures_leaked_tensor(b):\n",
|
|
1280 | 1282 | " external_object.field = a # Bad - leaks tensor"
|
1281 | 1283 | ]
|
1282 | 1284 | },
|
| 1285 | + { |
| 1286 | + "cell_type": "markdown", |
| 1287 | + "metadata": { |
| 1288 | + "id": "g-XVQcD-wf5K" |
| 1289 | + }, |
| 1290 | + "source": [ |
| 1291 | + "### Recursive tf.functions are not supported\n", |
| 1292 | + "\n", |
| 1293 | + "Recursive `Function`s are not supported and could cause infinite loops. For example," |
| 1294 | + ] |
| 1295 | + }, |
| 1296 | + { |
| 1297 | + "cell_type": "code", |
| 1298 | + "execution_count": null, |
| 1299 | + "metadata": { |
| 1300 | + "id": "QSN-T1m5EFcR" |
| 1301 | + }, |
| 1302 | + "outputs": [], |
| 1303 | + "source": [ |
| 1304 | + "@tf.function\n", |
| 1305 | + "def recursive_fn(n):\n", |
| 1306 | + " if n > 0:\n", |
| 1307 | + " return recursive_fn(n - 1)\n", |
| 1308 | + " else:\n", |
| 1309 | + " return 1\n", |
| 1310 | + "\n", |
| 1311 | + "with assert_raises(Exception):\n", |
| 1312 | + " recursive_fn(tf.constant(5)) # Bad - maximum recursion error." |
| 1313 | + ] |
| 1314 | + }, |
| 1315 | + { |
| 1316 | + "cell_type": "markdown", |
| 1317 | + "metadata": { |
| 1318 | + "id": "LyRyooKGUxNV" |
| 1319 | + }, |
| 1320 | + "source": [ |
| 1321 | + "Even if a recursive `Function` seems to work, the python function will be traced multiple times and could have performance implication. For example," |
| 1322 | + ] |
| 1323 | + }, |
| 1324 | + { |
| 1325 | + "cell_type": "code", |
| 1326 | + "execution_count": null, |
| 1327 | + "metadata": { |
| 1328 | + "id": "7FlmTqfMUwmT" |
| 1329 | + }, |
| 1330 | + "outputs": [], |
| 1331 | + "source": [ |
| 1332 | + "@tf.function\n", |
| 1333 | + "def recursive_fn(n):\n", |
| 1334 | + " if n > 0:\n", |
| 1335 | + " print('tracing')\n", |
| 1336 | + " return recursive_fn(n - 1)\n", |
| 1337 | + " else:\n", |
| 1338 | + " return 1\n", |
| 1339 | + "\n", |
| 1340 | + "recursive_fn(5) # Warning - multiple tracings" |
| 1341 | + ] |
| 1342 | + }, |
1283 | 1343 | {
|
1284 | 1344 | "cell_type": "markdown",
|
1285 | 1345 | "metadata": {
|
|
0 commit comments