{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Adding progress bars to Learner" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", "\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#export\n", "from exp.nb_09b import *\n", "import time\n", "from fastprogress import master_bar, progress_bar\n", "from fastprogress.fastprogress import format_time" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One thing has been missing all this time, and as fun as it is to stare at a blank screen waiting for the results, it's nicer to have some tool to track progress." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imagenette data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "path = datasets.untar_data(datasets.URLs.IMAGENETTE_160)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tfms = [make_rgb, ResizeFixed(128), to_byte_tensor, to_float_tensor]\n", "bs = 64\n", "\n", "il = ImageList.from_files(path, tfms=tfms)\n", "sd = SplitData.split_by_func(il, partial(grandparent_splitter, valid_name='val'))\n", "ll = label_by_func(sd, parent_labeler, proc_y=CategoryProcessor())\n", "data = ll.to_databunch(bs, c_in=3, c_out=10, num_workers=4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "nfs = [32]*4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We rewrite the `AvgStatsCallback` to add a line with the names of the things measured and keep track of the time per epoch." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# export \n", "class AvgStatsCallback(Callback):\n", " def __init__(self, metrics):\n", " self.train_stats,self.valid_stats = AvgStats(metrics,True),AvgStats(metrics,False)\n", " \n", " def begin_fit(self):\n", " met_names = ['loss'] + [m.__name__ for m in self.train_stats.metrics]\n", " names = ['epoch'] + [f'train_{n}' for n in met_names] + [\n", " f'valid_{n}' for n in met_names] + ['time']\n", " self.logger(names)\n", " \n", " def begin_epoch(self):\n", " self.train_stats.reset()\n", " self.valid_stats.reset()\n", " self.start_time = time.time()\n", " \n", " def after_loss(self):\n", " stats = self.train_stats if self.in_train else self.valid_stats\n", " with torch.no_grad(): stats.accumulate(self.run)\n", " \n", " def after_epoch(self):\n", " stats = [str(self.epoch)] \n", " for o in [self.train_stats, self.valid_stats]:\n", " stats += [f'{v:.6f}' for v in o.avg_stats] \n", " stats += [format_time(time.time() - self.start_time)]\n", " self.logger(stats)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then we add the progress bars... with a Callback of course! `master_bar` handles the count over the epochs while its child `progress_bar` is looping over all the batches. We just create one at the beginning or each epoch/validation phase, and update it at the end of each batch. By changing the logger of the `Learner` to the `write` function of the master bar, everything is automatically written there.\n", "\n", "Note: this requires fastprogress v0.1.21 or later. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# export \n", "class ProgressCallback(Callback):\n", " _order=-1\n", " def begin_fit(self):\n", " self.mbar = master_bar(range(self.epochs))\n", " self.mbar.on_iter_begin()\n", " self.run.logger = partial(self.mbar.write, table=True)\n", " \n", " def after_fit(self): self.mbar.on_iter_end()\n", " def after_batch(self): self.pb.update(self.iter)\n", " def begin_epoch (self): self.set_pb()\n", " def begin_validate(self): self.set_pb()\n", " \n", " def set_pb(self):\n", " self.pb = progress_bar(self.dl, parent=self.mbar, auto_update=False)\n", " self.mbar.update(self.epoch)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By making the progress bar a callback, you can easily choose if you want to have them shown or not." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cbfs = [partial(AvgStatsCallback,accuracy),\n", " CudaCallback,\n", " ProgressCallback,\n", " partial(BatchTransformXCallback, norm_imagenette)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "learn = get_learner(nfs, data, 0.4, conv_layer, cb_funcs=cbfs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
epochtrain_losstrain_accuracyvalid_lossvalid_accuracytime
01.8643630.3397701.5300680.48000000:06
11.4615380.5071351.5074290.48200000:06
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "learn.fit(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Export" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Converted 09c_add_progress_bar.ipynb to exp/nb_09c.py\r\n" ] } ], "source": [ "!./notebook2script.py 09c_add_progress_bar.ipynb" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 2 }