This is the current list of functions
- Profiling Utilities
@profile_call(fname=None)
- a function or method decorator to record execution timesprint_prof_data(fname=None)
- prints out profile data for functionfname
or all functions iffname
is Noneclear_prof_data(fname=None)
- clears out profile data for functionfname
or all functions iffname
is Noneget_prof_data(fname)
- get exec times forfname
start_record(fname)
- start recording time forfname
(alternative to decorator if function cannot decorated)end_record(fname)
- stop recording and add elapsed time forfname
save_prof_data(file_name)
- save profile data tofile_name
load_prof_data(file_name)
- load profile data fromfile_name
- Profiling Callback
MyProfileCallback
- a fastaiCallback
that provides a hierarchical view of model training time executionLearner.to_my_profile
- method added to a fastaiLearner
ifmy_timesaver_utils.profiling_callback
is imported. Call it to add aMyProfileCallback
to theLearner
instance.Learner.my_profile
-MyProfileCallback
instance attached to the fastaiLearner
object ifto_my_profile
method is called.print_stats
-MyProfileCallback
method to show a hierarchical view of the training lifecycle execution stats (execution counts, avg time, max time)get_stats
-MyProfileCallback
method to get the execution stats as a listclear_stats
-MyProfileCallback
method to reset the execution statsreset
-MyProfileCallback
attribute to set so each call toLearner.fit
resets the execution counts before starting the training.
- Enhanced Image Classifier Cleaner
class EnhancedImageClassifierCleaner
- a drop-in replacement for thefastai.vision.widgets.ImageClassifierCleaner
which addsApply
andReset
buttons to allow the user to apply or revert changes to actual dataset.(In the fastai, the application of the changes is done in a separate step, making it more cumbersome to apply across a lot of categories -- doubling it since it segregates the validation and training datasets as well)
pip install git+https://github.com/butchland/my_timesaver_utils.git
Decorate method or function you want to profile
import time
@profile_call
def test_func(t=2.0):
time.sleep(1)
Call your method or function
for i in range(10):
test_func(i)
You can also add an optional funcname if you want to replace the name its stored in the profile data
@profile_call('wachacha')
def test_func2():
time.sleep(1.0)
for i in range(3):
test_func2()
Print your profile data
print_prof_data('test_func')
Print your profile data for the test_func2 (aka wachacha)
print_prof_data('wachacha')
Get your profile data (e.g. good for graphing)
times = get_prof_data('test_func'); times
If you can't add a decorator, you can start and end the recording manually and it will be added to the profile data
for i in range(10):
start_record('my_sleep')
time.sleep(1.)
end_record('my_sleep')
As an alternative, the decorator can be invoked this way
sleep = profile_call(time.sleep)
for i in range(5):
sleep(i)
You can also pass in an optional function name to replace the func name used in the profile data
sleep2 = profile_call(time.sleep, 'maluman')
for i in range(3): sleep2(1)
If you call print_prof_data
without any arguments, it will print all the timings for all the functions
print_prof_data()
You can also get the profile data for the manually recorded calls as well.
times2 = get_prof_data('sleep');times2
You can also save the profile data to a file
save_file = 'my_profile_data.pickle'
save_prof_data(save_file)
Calling clear_prof_data
for a function will clear out the data for that function
clear_prof_data('sleep')
print_prof_data()
Calling the clear_prof_data
with no arguments will clear out all the previously recorded timings.
clear_prof_data()
print_prof_data()
You can reload the profile data from a previously saved file
load_prof_data(save_file)
print_prof_data()
from fastai.vision.all import *
Import the whole my_timesaver_utils
package
from my_timesaver_utils.all import *
or as an alternative, just import the profiling_callback
package
from my_timesaver_utils.profiling_callback import *
Setup your path, data, datablock, dataloaders and learner as usual.
path = untar_data(URLs.MNIST_TINY)
Path.BASE_PATH = path
datablock = DataBlock(
blocks=(ImageBlock,CategoryBlock),
get_items=get_image_files,
get_y=parent_label,
splitter=GrandparentSplitter(),
item_tfms=Resize(28),
batch_tfms=[]
)
dls = datablock.dataloaders(path)
learner = cnn_learner(dls,resnet18,metrics=accuracy)
Importing the profiling callback adds a method to_my_profile
to the learner
object
learner.to_my_profile()
Calling the to_my_profile
method on the learner
object adds a callback called MyProfileCallback
which can be accessed through the learner
attribute my_profile
.
learner.summary()
learner.my_profile
Call the print_stats
method on the my_profile
attribute of the Learner
object displays a hierarchical list of the training lifecycle events -- in this case with no data yet as the fit
method has not been called.
learner.my_profile.print_stats()
learner.fit(1)
The print_stats
method now prints the execution counts, max time and avg time (in secs) for each part of the training lifecycle.
learner.my_profile.print_stats()
The stats can also be collected as a list of tuples where each tuple consists of the lifecycle event name, the level, and the elapsed times.
fit_stats = learner.my_profile.get_stats();fit_stats
The print_stats
can also print just the stats for one lifecycle event
learner.my_profile.print_stats('train_batch')
The get_stats
can also just collect the stats for one lifecycle event
train_batch_stats = learner.my_profile.get_stats('train_batch'); train_batch_stats
Call the clear_stats
to clear the stats. You can also pass a lifecycle event to clear a single event
learner.my_profile.clear_stats()
learner.my_profile.print_stats()
learner.my_profile.print_stats('train')
learner.fine_tune(1)
learner.my_profile.print_stats()
My Profile Reset Attribute
Setting the reset
attribute to true on the my_profile
attribute will cause the stats to be reset each time the fit
method of the Learner
is called. So only the accumulated stats for the last call to fit
(e.g fine_tune
calls fit
twice, but setting the reset
attribute to true will show only the stats for the second fit
call.
The default value of reset
is False
.
learner.my_profile.reset = True
learner.fine_tune(1)
learner.my_profile.print_stats()
learner.my_profile.reset
Enhanced Image Classifier Cleaner
Import the utils -- You can either import all the utilities
from my_timesaver_utils.all import *
Or you can import only the enhanced image classifier cleaner package
from my_timesaver_utils.enhanced_imageclassifiercleaner import *
Prerequisites
In order to use the EnhancedImageClassifierCleaner
(just like the fastai ImageClassifierCleaner
), we will need to have an existing fastai Learner
object.
Usage
Just create an instance of EnhancedImageClassifierCleaner
object.
cleaner = EnhancedImageClassifierCleaner(learner)
cleaner # on a separate line, this will display the widget
If you updated your dataset, you can refresh your dataloader by running
newdls = datablock.dataloaders(path)
learner.dls = newdls # assume learner was previously created or loaded
cleaner = EnhancedImageClassifierCleaner(learner)
This will then display the updated images from your dataset.
cleaner = EnhancedImageClassifierCleaner(learner)
cleaner
Custom Valid/Train folder structures and labeled categories
The default folder structure for the Enhanced Image Classifier Cleaner
assumes that you are using RandomSplitter
or GrandparentSplitter
as
your splitter
and parent_label
as the get_y
parameter in your datablock.
If you have a custom valid/train splitter and your image files are not segregated by categories within them, you will need to create a custom file mover in order to update your image labels (aka categories).
The default implementation of the file_mover
is shown below:
export
import shutil
def parent_move_file(fn, newcat):
new_path = fn.parent.parent/newcat
if new_path.is_dir():
shutil.move(str(fn), new_path)
new_file = new_path/fn.name
return new_file
return fn
The default implementation will work with either a RandomSplitter
or GrandparentSplitter
and if parent_label
is used to get the labels.
Otherwise, you will need to modify the file_mover argument with a custom one and pass it as follows
cleaner = EnhancedImageClassifierCleaner(learner, file_mover=custom_file_mover)