Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion fastai/adaptive_softmax.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ class AdaptiveLoss(nn.Module):
def __init__(self, cutoff):
super().__init__()
self.cutoff = cutoff
self.criterions = nn.ModuleList([nn.CrossEntropyLoss(size_average=False) for i in self.cutoff])
self.criterions = nn.ModuleList(
[nn.CrossEntropyLoss(size_average=False) for _ in self.cutoff]
)
Comment on lines -58 to +60
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function AdaptiveLoss.__init__ refactored with the following changes:


def remap_target(self, target):
new_target = [target.clone()]
Expand Down
5 changes: 1 addition & 4 deletions fastai/column_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,7 @@ def forward(self, x_cat, x_cont):
x = d(x)
x = self.outp(x)
if not self.is_reg:
if self.is_multi:
x = F.sigmoid(x)
else:
x = F.log_softmax(x)
x = F.sigmoid(x) if self.is_multi else F.log_softmax(x)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function MixedInputModel.forward refactored with the following changes:

elif self.y_range:
x = F.sigmoid(x)
x = x*(self.y_range[1] - self.y_range[0])
Expand Down
9 changes: 3 additions & 6 deletions fastai/conv_learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ def __init__(self, f, c, is_multi, is_reg, ps=None, xtra_fc=None, xtra_cut=0, cu
if ps is None: ps = [0.25]*len(xtra_fc) + [0.5]
self.ps,self.xtra_fc = ps,xtra_fc

if f in model_meta: cut,self.lr_cut = model_meta[f]
else: cut,self.lr_cut = 0,0
cut,self.lr_cut = model_meta[f] if f in model_meta else (0, 0)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ConvnetBuilder.__init__ refactored with the following changes:

cut-=xtra_cut
layers = cut_model(f(pretrained), cut)
self.nf = model_features[f] if f in model_features else (num_features(layers)*2)
Expand All @@ -45,8 +44,7 @@ def __init__(self, f, c, is_multi, is_reg, ps=None, xtra_fc=None, xtra_cut=0, cu
n_fc = len(self.xtra_fc)+1
if not isinstance(self.ps, list): self.ps = [self.ps]*n_fc

if custom_head: fc_layers = [custom_head]
else: fc_layers = self.get_fc_layers()
fc_layers = [custom_head] if custom_head else self.get_fc_layers()
self.n_fc = len(fc_layers)
self.fc_model = to_gpu(nn.Sequential(*fc_layers))
if not custom_head: apply_init(self.fc_model, kaiming_normal)
Expand Down Expand Up @@ -180,8 +178,7 @@ def save_fc1(self):
if len(self.activations[1])!=len(self.data.val_ds):
predict_to_bcolz(m, self.data.val_dl, val_act)
if self.data.test_dl and (len(self.activations[2])!=len(self.data.test_ds)):
if self.data.test_dl: predict_to_bcolz(m, self.data.test_dl, test_act)

predict_to_bcolz(m, self.data.test_dl, test_act)
Comment on lines -183 to +181
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ConvLearner.save_fc1 refactored with the following changes:

self.fc_data = ImageClassifierData.from_arrays(self.data.path,
(act, self.data.trn_y), (val_act, self.data.val_y), self.data.bs, classes=self.data.classes,
test = test_act if self.data.test_dl else None, num_workers=8)
Expand Down
5 changes: 2 additions & 3 deletions fastai/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ def listify(x, y):
return x

def datafy(x):
if is_listy(x): return [o.data for o in x]
else: return x.data
return [o.data for o in x] if is_listy(x) else x.data
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function datafy refactored with the following changes:


conv_dict = {np.dtype('int8'): torch.LongTensor, np.dtype('int16'): torch.LongTensor,
np.dtype('int32'): torch.LongTensor, np.dtype('int64'): torch.LongTensor,
Expand Down Expand Up @@ -186,7 +185,7 @@ def chunk_iter(iterable, chunk_size):
while True:
chunk = []
try:
for _ in range(chunk_size): chunk.append(next(iterable))
chunk.extend(next(iterable) for _ in range(chunk_size))
Comment on lines -189 to +188
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function chunk_iter refactored with the following changes:

yield chunk
except StopIteration:
if chunk: yield chunk
Expand Down
2 changes: 1 addition & 1 deletion fastai/dataloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def np_collate(self, batch):
return {key: self.np_collate([d[key] for d in batch]) for key in b}
elif isinstance(b, collections.Sequence):
return [self.np_collate(samples) for samples in zip(*batch)]
raise TypeError(("batch must contain numbers, dicts or lists; found {}".format(type(b))))
raise TypeError(f"batch must contain numbers, dicts or lists; found {type(b)}")
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function DataLoader.np_collate refactored with the following changes:


def get_batch(self, indices):
res = self.np_collate([self.dataset[i] for i in indices])
Expand Down
64 changes: 39 additions & 25 deletions fastai/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ def read_dir(path, folder):
if any(fnames):
return [os.path.relpath(f,path) for f in fnames]
elif any(directories):
raise FileNotFoundError("{} has subdirectories but contains no files. Is your directory structure is correct?".format(full_path))
raise FileNotFoundError(
f"{full_path} has subdirectories but contains no files. Is your directory structure is correct?"
)
else:
raise FileNotFoundError("{} folder doesn't exist or is empty".format(full_path))
raise FileNotFoundError(f"{full_path} folder doesn't exist or is empty")
Comment on lines -97 to +101
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function read_dir refactored with the following changes:


def read_dirs(path, folder):
'''
Expand Down Expand Up @@ -172,16 +174,24 @@ def csv_source(folder, csv_file, skip_header=True, suffix='', continuous=False,
return dict_source(folder, fnames, csv_labels, suffix, continuous)

def dict_source(folder, fnames, csv_labels, suffix='', continuous=False):
all_labels = sorted(list(set(p for o in csv_labels.values() for p in ([] if type(o) == float else o))))
all_labels = sorted(
list(
{
p
for o in csv_labels.values()
for p in ([] if type(o) == float else o)
}
)
)
Comment on lines -175 to +185
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function dict_source refactored with the following changes:

full_names = [os.path.join(folder,str(fn)+suffix) for fn in fnames]
if continuous:
label_arr = np.array([np.array(csv_labels[i]).astype(np.float32)
for i in fnames])
else:
label2idx = {v:k for k,v in enumerate(all_labels)}
label_arr = nhot_labels(label2idx, csv_labels, fnames, len(all_labels))
is_single = np.all(label_arr.sum(axis=1)==1)
if is_single: label_arr = np.argmax(label_arr, axis=1)
if is_single := np.all(label_arr.sum(axis=1) == 1):
label_arr = np.argmax(label_arr, axis=1)
return full_names, label_arr, all_labels

class BaseDataset(Dataset):
Expand Down Expand Up @@ -263,19 +273,20 @@ def open_image(fn):
"""
flags = cv2.IMREAD_UNCHANGED+cv2.IMREAD_ANYDEPTH+cv2.IMREAD_ANYCOLOR
if not os.path.exists(fn) and not str(fn).startswith("http"):
raise OSError('No such file or directory: {}'.format(fn))
raise OSError(f'No such file or directory: {fn}')
elif os.path.isdir(fn) and not str(fn).startswith("http"):
raise OSError('Is a directory: {}'.format(fn))
raise OSError(f'Is a directory: {fn}')
elif isdicom(fn):
slice = pydicom.read_file(fn)
if slice.PhotometricInterpretation.startswith('MONOCHROME'):
# Make a fake RGB image
im = np.stack([slice.pixel_array]*3,-1)
return im / ((1 << slice.BitsStored)-1)
else:
if not slice.PhotometricInterpretation.startswith('MONOCHROME'):
# No support for RGB yet, as it involves various color spaces.
# It shouldn't be too difficult to add though, if needed.
raise OSError('Unsupported DICOM image with PhotometricInterpretation=={}'.format(slice.PhotometricInterpretation))
raise OSError(
f'Unsupported DICOM image with PhotometricInterpretation=={slice.PhotometricInterpretation}'
)
# Make a fake RGB image
im = np.stack([slice.pixel_array]*3,-1)
return im / ((1 << slice.BitsStored)-1)
Comment on lines -266 to +289
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function open_image refactored with the following changes:

else:
#res = np.array(Image.open(fn), dtype=np.float32)/255
#if len(res.shape)==2: res = np.repeat(res[...,None],3,2)
Expand All @@ -290,7 +301,7 @@ def open_image(fn):
if im is None: raise OSError(f'File not recognized by opencv: {fn}')
return cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
except Exception as e:
raise OSError('Error handling image at: {}'.format(fn)) from e
raise OSError(f'Error handling image at: {fn}') from e

class FilesDataset(BaseDataset):
def __init__(self, fnames, transform, path):
Expand Down Expand Up @@ -437,12 +448,10 @@ def resize(self, targ_sz, new_path='tmp', resume=True, fn=None):
operation was aborted)
fn (function): optional custom resizing function
"""
new_ds = []
dls = [self.trn_dl,self.val_dl,self.fix_dl,self.aug_dl]
if self.test_dl: dls += [self.test_dl, self.test_aug_dl]
else: dls += [None,None]
dls += [self.test_dl, self.test_aug_dl] if self.test_dl else [None,None]
t = tqdm_notebook(dls)
for dl in t: new_ds.append(self.resized(dl, targ_sz, new_path, resume, fn))
new_ds = [self.resized(dl, targ_sz, new_path, resume, fn) for dl in t]
Comment on lines -440 to +454
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ImageData.resize refactored with the following changes:

t.close()
return self.__class__(new_ds[0].path, new_ds, self.bs, self.num_workers, self.classes)

Expand All @@ -458,11 +467,10 @@ def get_ds(fn, trn, val, tfms, test=None, **kwargs):
if isinstance(test, tuple):
test_lbls = test[1]
test = test[0]
elif len(trn[1].shape) == 1:
test_lbls = np.zeros((len(test),1))
else:
if len(trn[1].shape) == 1:
test_lbls = np.zeros((len(test),1))
else:
test_lbls = np.zeros((len(test),trn[1].shape[1]))
test_lbls = np.zeros((len(test),trn[1].shape[1]))
Comment on lines +470 to +473
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ImageData.get_ds refactored with the following changes:

res += [
fn(test, test_lbls, tfms[1], **kwargs), # test
fn(test, test_lbls, tfms[0], **kwargs) # test_aug
Expand Down Expand Up @@ -510,7 +518,9 @@ def from_paths(cls, path, bs=64, tfms=(None,None), trn_name='train', val_name='v
Returns:
ImageClassifierData
"""
assert not(tfms[0] is None or tfms[1] is None), "please provide transformations for your train and validation sets"
assert (
tfms[0] is not None and tfms[1] is not None
), "please provide transformations for your train and validation sets"
Comment on lines -513 to +523
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ImageClassifierData.from_paths refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

trn,val = [folder_source(path, o) for o in (trn_name, val_name)]
if test_name:
test = folder_source(path, test_name) if test_with_labels else read_dir(path, test_name)
Expand Down Expand Up @@ -546,7 +556,9 @@ def from_csv(cls, path, folder, csv_fname, bs=64, tfms=(None,None),
Returns:
ImageClassifierData
"""
assert not (tfms[0] is None or tfms[1] is None), "please provide transformations for your train and validation sets"
assert (
tfms[0] is not None and tfms[1] is not None
), "please provide transformations for your train and validation sets"
Comment on lines -549 to +561
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ImageClassifierData.from_csv refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

assert not (os.path.isabs(folder)), "folder needs to be a relative path"
fnames,y,classes = csv_source(folder, csv_fname, skip_header, suffix, continuous=continuous, cat_separator=cat_separator)
return cls.from_names_and_array(path, fnames, y, classes, val_idxs, test_name,
Expand All @@ -571,7 +583,9 @@ def from_path_and_array(cls, path, folder, y, classes=None, val_idxs=None, test_
Returns:
ImageClassifierData
"""
assert not (tfms[0] is None or tfms[1] is None), "please provide transformations for your train and validation sets"
assert (
tfms[0] is not None and tfms[1] is not None
), "please provide transformations for your train and validation sets"
Comment on lines -574 to +588
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ImageClassifierData.from_path_and_array refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

assert not (os.path.isabs(folder)), "folder needs to be a relative path"
fnames = np.core.defchararray.add(f'{folder}/', sorted(os.listdir(f'{path}{folder}')))
return cls.from_names_and_array(path, fnames, y, classes, val_idxs, test_name,
Expand Down
7 changes: 3 additions & 4 deletions fastai/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ def in_ipynb():
def clear_tqdm():
inst = getattr(tq.tqdm, '_instances', None)
if not inst: return
try:
for i in range(len(inst)): inst.pop().close()
except Exception:
pass
with contextlib.suppress(Exception):
for _ in range(len(inst)):
inst.pop().close()
Comment on lines -43 to +45
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function clear_tqdm refactored with the following changes:


if in_notebook():
def tqdm(*args, **kwargs):
Expand Down
18 changes: 10 additions & 8 deletions fastai/layer_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,18 @@ def set_wds(self, wds):
self.wds=wds

def set_mom(self,momentum):
if 'betas' in self.opt.param_groups[0]:
for pg in self.opt.param_groups: pg['betas'] = (momentum, pg['betas'][1])
else:
for pg in self.opt.param_groups: pg['momentum'] = momentum
for pg in self.opt.param_groups:
if 'betas' in self.opt.param_groups[0]:
pg['betas'] = (momentum, pg['betas'][1])
else:
pg['momentum'] = momentum
Comment on lines -51 to +55
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function LayerOptimizer.set_mom refactored with the following changes:


def set_beta(self,beta):
if 'betas' in self.opt.param_groups[0]:
for pg in self.opt.param_groups: pg['betas'] = (pg['betas'][0],beta)
elif 'alpha' in self.opt.param_groups[0]:
for pg in self.opt.param_groups: pg['alpha'] = beta
for pg in self.opt.param_groups:
if 'betas' in self.opt.param_groups[0]:
pg['betas'] = (pg['betas'][0],beta)
elif 'alpha' in self.opt.param_groups[0]:
pg['alpha'] = beta
Comment on lines -57 to +62
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function LayerOptimizer.set_beta refactored with the following changes:


def set_opt_fn(self, opt_fn):
if type(self.opt) != type(opt_fn(self.opt_params())):
Expand Down
17 changes: 12 additions & 5 deletions fastai/learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,18 @@ def unfreeze_groups(self, groups):

def unfreeze(self): self.freeze_to(0)

def get_model_path(self, name): return os.path.join(self.models_path,name)+'.h5'
def get_model_path(self, name):
return f'{os.path.join(self.models_path, name)}.h5'
Comment on lines -98 to +99
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Learner.get_model_path refactored with the following changes:


def save(self, name):
save_model(self.model, self.get_model_path(name))
if hasattr(self, 'swa_model'): save_model(self.swa_model, self.get_model_path(name)[:-3]+'-swa.h5')
if hasattr(self, 'swa_model'):
save_model(self.swa_model, f'{self.get_model_path(name)[:-3]}-swa.h5')
Comment on lines -102 to +104
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Learner.save refactored with the following changes:


def load(self, name):
load_model(self.model, self.get_model_path(name))
if hasattr(self, 'swa_model'): load_model(self.swa_model, self.get_model_path(name)[:-3]+'-swa.h5')
if hasattr(self, 'swa_model'):
load_model(self.swa_model, f'{self.get_model_path(name)[:-3]}-swa.h5')
Comment on lines -106 to +109
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Learner.load refactored with the following changes:


def set_data(self, data): self.data_ = data

Expand Down Expand Up @@ -385,7 +388,8 @@ def predict_array(self, arr):
Returns:
a numpy array containing the predictions from the model
"""
if not isinstance(arr, np.ndarray): raise OSError(f'Not valid numpy array')
if not isinstance(arr, np.ndarray):
raise OSError('Not valid numpy array')
Comment on lines -388 to +392
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Learner.predict_array refactored with the following changes:

self.model.eval()
return to_np(self.model(to_gpu(V(T(arr)))))

Expand All @@ -411,7 +415,10 @@ def TTA(self, n_aug=4, is_test=False):
dl2 = self.data.test_aug_dl if is_test else self.data.aug_dl
preds1,targs = predict_with_targs(self.model, dl1)
preds1 = [preds1]*math.ceil(n_aug/4)
preds2 = [predict_with_targs(self.model, dl2)[0] for i in tqdm(range(n_aug), leave=False)]
preds2 = [
predict_with_targs(self.model, dl2)[0]
for _ in tqdm(range(n_aug), leave=False)
]
Comment on lines -414 to +421
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function Learner.TTA refactored with the following changes:

return np.stack(preds1+preds2), targs

def fit_opt_sched(self, phases, cycle_save_name=None, best_save_name=None, stop_div=False, data_list=None, callbacks=None,
Expand Down
4 changes: 3 additions & 1 deletion fastai/lm_rnn.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ def __init__(self, ntoken, emb_sz, n_hid, n_layers, pad_token, bidir=False,

self.emb_sz,self.n_hid,self.n_layers,self.dropoute = emb_sz,n_hid,n_layers,dropoute
self.dropouti = LockedDropout(dropouti)
self.dropouths = nn.ModuleList([LockedDropout(dropouth) for l in range(n_layers)])
self.dropouths = nn.ModuleList(
[LockedDropout(dropouth) for _ in range(n_layers)]
)
Comment on lines -82 to +84
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function RNN_Encoder.__init__ refactored with the following changes:


def forward(self, input):
""" Invoked during the forward propagation of the RNN_Encoder module.
Expand Down
Loading