class _A:
def __init__(self, a): self.a = a
@contextmanager
def a_changed(self, v): return replacing_yield(self, 'a', v)
= _A(42)
a with a.a_changed(32):
32)
test_eq(a.a, 42) test_eq(a.a,
Learner, Metrics, Callbacks
您可能想直接跳转到 Learner
的定义。
Utils function
replacing_yield
replacing_yield (o, attr, val)
临时替换属性的上下文管理器
mk_metric
mk_metric (m)
将 m
转换为 AvgMetric
,除非它已经是 Metric
有关更多信息,请参阅下面的 Metric
类。
save_model
save_model (file, model, opt, with_opt=True, pickle_protocol=2, **torch_save_kwargs)
将 model
保存到 file
,同时保存 opt
(如果可用,并且 with_opt
为 True)
file
可以是一个 Path
对象、一个字符串或一个打开的文件对象。pickle_protocol
和 torch_save_kwargs
会传递给 torch.save
load_model
load_model (file, model, opt, with_opt=True, device=None, strict=True, **torch_load_kwargs)
从 file
加载 model
,同时加载 opt
(如果可用,并且 with_opt
为 True)
file
可以是一个 Path
对象、一个字符串或一个打开的文件对象。如果传递了 device
,模型会加载到该设备上,否则加载到 CPU 上。
如果 strict
为 True
,文件必须完全包含 model
中每个参数键的权重;如果 strict
为 False
,则只加载保存的模型中存在的键到 model
中。
您可以通过 torch_load_kwargs
将其他 kwargs 传递给 torch.load
。
自 PyTorch 2.5 和 fastai 2.7.19 起,load_model
使用 PyTorch 的安全序列化进行模型加载。
SkipToEpoch
SkipToEpoch (epoch:int)
跳过训练直到 epoch
Learner
Learner (dls:fastai.data.core.DataLoaders, model:Callable, loss_func:Optional[Callable]=None, opt_func:fastai.optimizer.Opt imizer|fastai.optimizer.OptimWrapper=<function Adam>, lr:float|slice=0.001, splitter:Callable=<function trainable_params>, cbs:fastai.callback.core.Callback|collections .abc.MutableSequence|None=None, metrics:Union[Callable,collectio ns.abc.MutableSequence,NoneType]=None, path:str|pathlib.Path|None=None, model_dir:str|pathlib.Path='models', wd:float|int|None=None, wd_bn_bias:bool=False, train_bn:bool=True, moms:tuple=(0.95, 0.85, 0.95), default_cbs:bool=True)
将 model
、一些 dls
和 loss_func
组合在一起以处理训练
类型 | 默认 | 详情 | |
---|---|---|---|
dls | DataLoaders | 包含 fastai 或 PyTorch DataLoader 的 DataLoaders |
|
model | 可调用 | 用于训练或推理的 PyTorch 模型 | |
loss_func | 可选 | None | 损失函数。默认为 dls 中的损失函数 |
opt_func | fastai.optimizer.Optimizer | fastai.optimizer.OptimWrapper | Adam | 用于训练的优化函数 |
lr | float | slice | 0.001 | 默认学习率 |
splitter | 可调用 | trainable_params | 将模型分割成参数组。默认为一个参数组 |
cbs | fastai.callback.core.Callback | collections.abc.MutableSequence | None | None | 要添加到 Learner 的 Callback |
metrics | Union | None | 要在验证集上计算的 Metric |
path | str | pathlib.Path | None | None | 保存、加载和导出模型的父目录。默认为 dls 的 path |
model_dir | str | pathlib.Path | models | 保存和加载模型的子目录 |
wd | float | int | None | None | 默认权重衰减 |
wd_bn_bias | bool | False | 对归一化和偏置参数应用权重衰减 |
train_bn | bool | True | 训练冻结的归一化层 |
moms | tuple | (0.95, 0.85, 0.95) | 调度器的默认动量 |
default_cbs | bool | True | 包含默认的 Callback |
调用 Learner.fit
时,将使用 opt_func
创建优化器,lr
作为默认学习率。splitter
是一个函数,它接受 self.model
并返回一个参数组列表(如果没有不同的参数组,则只返回一个参数组)。默认是 trainable_params
,它返回模型的所有可训练参数。
cbs
是一个或一个列表的 Callback
,用于传递给 Learner
。Callback
用于训练循环的每次调整。每个 Callback
都注册为 Learner
的属性(使用驼峰命名法)。创建时,defaults.callbacks
(TrainEvalCallback
、Recorder
和 ProgressCallback
)中的所有回调都会与 Learner
关联。
metrics
是一个可选的度量列表,可以是函数或 Metric
(见下文)。
path
和 model_dir
用于保存和/或加载模型。通常 path
会从 dls
推断,但您可以覆盖它或将 Path
对象传递给 model_dir
。请确保您可以在 path/model_dir
中写入!
wd
是训练模型时使用的默认权重衰减;moms
是 Learner.fit_one_cycle
中使用的默认动量。wd_bn_bias
控制是否对 BatchNorm
层和偏置应用权重衰减。
最后,train_bn
控制是否即使根据 splitter
应该冻结 BatchNorm
层,它们也会被训练。我们的经验性实验表明,对于迁移学习中的这些层来说,这是最好的行为。
PyTorch 互操作
Learner
的大多数参数可以使用常规的 PyTorch 功能,尽管使用纯 fastai 对象体验会更顺畅,并且您将能够使用库的全部功能。预期是即使您没有端到端使用 fastai,训练循环也能顺利工作。您可能会失去的是解释对象或显示功能。下面的列表解释了如何对所有参数使用纯 PyTorch 对象以及您可能会失去什么。
最重要的是 opt_func
。如果您不使用 fastai 优化器,您需要编写一个函数,将您的 PyTorch 优化器包装在一个 OptimWrapper
中。有关更多详情,请参阅优化器模块。这是为了确保库的调度器/冻结 API 与您的代码一起工作。
dls
是一个DataLoaders
对象,您可以从标准的 PyTorch dataloaders 创建它。通过这样做,您将失去所有显示功能,如show_batch
/show_results
。您可以查看数据块 API 或中级数据 API 教程来学习如何使用 fastai 收集数据!model
是一个标准的 PyTorch 模型。您可以使用任何您喜欢的模型,只需确保它接受您的DataLoaders
中输入数量并返回与目标数量相同的输出。loss_func
可以是您喜欢的任何损失函数。如果您想使用Learn.predict
或Learn.get_preds
,它需要是 fastai 的损失函数之一,否则您将必须实现特殊方法(有关更多详情,请参阅BaseLoss
文档之后)。
训练循环
现在让我们看看 Learner
类实现的主要功能:训练循环。
Learner.fit
Learner.fit (n_epoch, lr=None, wd=None, cbs=None, reset_opt=False, start_epoch=0)
使用 cbs
训练 self.model
共 n_epoch
个周期。可选地 reset_opt
。
如果提供了 lr
和 wd
,则使用它们,否则使用 Learner
的 lr
和 wd
属性给出的默认值。
所有示例都使用 synth_learner
,这是一个训练线性回归模型的简单 Learner
。
#Training a few epochs should make the model better
= synth_learner(lr=0.1)
learn
learn(_before_epoch)= learn.model.cpu()
learn.model = learn.dls.one_batch()
xb,yb = learn.loss_func(learn.model(xb), yb)
init_loss 10)
learn.fit(= learn.dls.one_batch()
xb,yb = learn.loss_func(learn.model(xb), yb)
final_loss assert final_loss < init_loss, (final_loss,init_loss)
Learner.one_batch
Learner.one_batch (i, b)
在批次 (xb,yb)
上训练或评估 self.model
这是一个由 Learner.fit
调用的内部方法。如果传递了 i
,则是该迭代在该周期中的索引。在训练模式下,它对批次执行完整的训练步骤(计算预测、损失、梯度,更新模型参数并清零梯度)。在验证模式下,它停止在损失计算处。训练或验证由 TrainEvalCallback
通过 training
属性内部控制。
不返回任何内容,但 Learner
的 x
、y
、pred
、loss
属性会设置适当的值
= learn.dls.one_batch()
b 0, b)
learn.one_batch(0])
test_eq(learn.x, b[1])
test_eq(learn.y, b[= learn.model(learn.x)
out
test_eq(learn.pred, out)1])) test_eq(learn.loss, learn.loss_func(out, b[
Learner.all_batches
Learner.all_batches ()
在 self.dl
的所有批次上训练或评估 self.model
Learner.create_opt
Learner.create_opt ()
使用默认超参数创建优化器
此方法在内部调用以创建优化器,然后通过您传递给 Learner.fit
或您的特定调度器(请参阅 callback.schedule
)来调整超参数。
= synth_learner(n_train=5, cbs=VerboseCallback())
learn assert learn.opt is None
learn.create_opt()assert learn.opt is not None
0]['lr'], learn.lr) test_eq(learn.opt.hypers[
after_create
= synth_learner(n_train=5, cbs=VerboseCallback(), opt_func=partial(OptimWrapper, opt=torch.optim.Adam))
learn assert learn.opt is None
learn.create_opt()assert learn.opt is not None
0]['lr'], learn.lr) test_eq(learn.opt.hypers[
after_create
= 1
wrapper_lr = synth_learner(n_train=5, cbs=VerboseCallback(), opt_func=partial(OptimWrapper, opt=torch.optim.Adam, lr=wrapper_lr))
learn assert learn.opt is None
learn.create_opt()assert learn.opt is not None
0]['lr'], wrapper_lr) test_eq(learn.opt.hypers[
after_create
Callback 处理
我们这里只描述与 Callback
相关的基本功能。要了解有关 Callback
以及如何编写它们的更多信息,请查看 callback.core 模块文档。
首先看看 Callback
如何成为 Learner
的属性
#Test init with callbacks
class TstCallback(Callback):
def batch_begin(self): self.learn.a = self.a + 1
= synth_learner()
tst_learn len(tst_learn.cbs), 1)
test_eq(assert hasattr(tst_learn, ('train_eval'))
= synth_learner(cbs=TstCallback())
tst_learn len(tst_learn.cbs), 2)
test_eq(assert hasattr(tst_learn, ('tst'))
Learner.__call__
Learner.__call__ (event_name)
调用 self.cbs
中所有 Callback
的 event_name
这是内部调用 Callback
的方式。例如,VerboseCallback
只打印事件名称(对调试很有用)
= synth_learner(cbs=VerboseCallback())
learn 'after_fit') learn(
after_create
after_fit
Learner.add_cb
Learner.add_cb (cb)
将 cb
添加到 Callback
列表中并注册 self
为它们的 Learner
= synth_learner()
learn
learn.add_cb(TestTrainEvalCallback())len(learn.cbs), 2)
test_eq(assert isinstance(learn.cbs[1], TestTrainEvalCallback)
test_eq(learn.train_eval.learn, learn)
Learner.add_cbs
Learner.add_cbs (cbs)
将 cbs
添加到 Callback
列表中并注册 self
为它们的 Learner
learn.add_cbs([TestTrainEvalCallback(), TestTrainEvalCallback()])len(learn.cbs), 4) test_eq(
Learner.added_cbs
Learner.added_cbs (cbs)
= synth_learner()
learn len(learn.cbs), 1)
test_eq(with learn.added_cbs(TestTrainEvalCallback()):
len(learn.cbs), 2) test_eq(
Learner.ordered_cbs
Learner.ordered_cbs (event)
训练循环中 event
的 Callback
列表,按顺序排列
顺序是指使用 Callback
的内部顺序(有关其工作原理的更多信息,请参阅 callback.core
)。
= synth_learner()
learn
learn.add_cb(TestTrainEvalCallback())'before_fit') learn.ordered_cbs(
[TrainEvalCallback, TestTrainEvalCallback]
Learner.remove_cb
Learner.remove_cb (cb)
从 Callback
列表中删除 cb
并取消注册 self
为它们的 Learner
= synth_learner()
learn
learn.add_cb(TestTrainEvalCallback())= learn.cbs[1]
cb 1])
learn.remove_cb(learn.cbs[len(learn.cbs), 1)
test_eq(assert cb.learn is None
assert not getattr(learn,'test_train_eval',None)
cb
可以是要删除的 Callback
类(在这种情况下,会删除该回调的所有实例)。
= synth_learner()
learn
learn.add_cbs([TestTrainEvalCallback(), TestTrainEvalCallback()])
learn.remove_cb(TestTrainEvalCallback)len(learn.cbs), 1)
test_eq(assert not getattr(learn,'test_train_eval',None)
Learner.remove_cbs
Learner.remove_cbs (cbs)
从 Callback
列表中删除 cbs
并取消注册 self
为它们的 Learner
cbs
的元素可以是回调类型,也可以是 Learner
的实际回调。
= synth_learner()
learn for _ in range(3)])
learn.add_cbs([TestTrainEvalCallback() = learn.cbs[1]
cb 1:])
learn.remove_cbs(learn.cbs[len(learn.cbs), 1) test_eq(
Learner.removed_cbs
Learner.removed_cbs (cbs)
cbs
的元素可以是回调类型,也可以是 Learner
的实际回调。
= synth_learner()
learn
learn.add_cb(TestTrainEvalCallback())with learn.removed_cbs(learn.cbs[1]):
len(learn.cbs), 1)
test_eq(len(learn.cbs), 2) test_eq(
Learner.show_training_loop
Learner.show_training_loop ()
显示训练循环中的每个步骤
在每一步中,回调按顺序显示,这有助于调试。
= synth_learner()
learn learn.show_training_loop()
Start Fit
- before_fit : [TrainEvalCallback]
Start Epoch Loop
- before_epoch : []
Start Train
- before_train : [TrainEvalCallback]
Start Batch Loop
- before_batch : []
- after_pred : []
- after_loss : []
- before_backward: []
- before_step : []
- after_step : []
- after_cancel_batch: []
- after_batch : [TrainEvalCallback]
End Batch Loop
End Train
- after_cancel_train: []
- after_train : []
Start Valid
- before_validate: [TrainEvalCallback]
Start Batch Loop
- **CBs same as train batch**: []
End Batch Loop
End Valid
- after_cancel_validate: []
- after_validate : []
End Epoch Loop
- after_cancel_epoch: []
- after_epoch : []
End Fit
- after_cancel_fit: []
- after_fit : []
before_batch_cb
before_batch_cb (f)
创建 before_batch
事件的 Callback 的快捷方式,它接受并返回 xb,yb
为了更改传递给模型的数据,您通常会希望连接到 before_batch
事件,如下所示
class TstCallback(Callback):
def before_batch(self):
self.learn.xb = self.xb + 1000
self.learn.yb = self.yb - 1000
由于这种情况非常常见,我们提供了 before_batch_cb
装饰器以使其更容易。
@before_batch_cb
def cb(self, xb, yb): return xb+1000,yb-1000
序列化
Learner.save
Learner.save (file, with_opt=True, pickle_protocol=2)
将模型和优化器状态(如果 with_opt
为 True)保存到 self.path/self.model_dir/file
file
可以是一个 Path
、一个 string
或一个缓冲区。pickle_protocol
会传递给 torch.save
。
Learner.load
Learner.load (file, device=None, with_opt=True, strict=True)
使用 device
从 self.path/self.model_dir/file
加载模型和优化器状态(如果 with_opt
为 True)
file
可以是一个 Path
、一个 string
或一个缓冲区。使用 device
将模型/优化器状态加载到与其保存时不同的设备上。
自 PyTorch 2.5 和 fastai 2.7.19 起,Learner.load
使用 PyTorch 的安全序列化进行模型加载。
with tempfile.TemporaryDirectory() as d:
= synth_learner(path=d)
learn 1)
learn.fit(
#Test save created a file
'tmp')
learn.save(assert (Path(d)/'models/tmp.pth').exists()
#Test load did load the model
= synth_learner(path=d)
learn1 = learn1.load('tmp')
learn1
test_eq(learn.a, learn1.a)
test_eq(learn.b, learn1.b) test_eq(learn.opt.state_dict(), learn1.opt.state_dict())
Learner.export
Learner.export (fname='export.pkl', pickle_module=<module 'cloudpickle' from '/home/runner/.local/lib/python3.12/site- packages/cloudpickle/__init__.py'>, pickle_protocol=2)
导出 self
的内容,但不包含 items 和优化器状态,用于推理
使用 pickle_protocol
将 Learner
保存到 self.path/fname
。请注意,Python 中的序列化保存的是函数名,而不是代码本身。因此,您用于模型、数据转换、损失函数等的任何自定义代码都应该放在一个模块中,您在导出前在训练环境中导入它,并在加载前在部署环境中导入它。
load_learner
load_learner (fname, cpu=True, pickle_module=<module 'pickle' from '/usr/lib/python3.12/pickle.py'>)
加载 fname
中的 Learner
对象,默认将其放在 cpu
上
load_learner
使用 Python 不安全的 pickle
模块。恶意构造的 pickle 数据在加载时可以执行任意代码。切勿对不受信任或可能受损的来源使用 load_learner
。仅加载您完全信任的文件。”
如果您只需要加载模型权重和优化器状态,请改用安全的 Learner.load
。
load_learner
要求您的所有自定义代码与导出 Learner
时完全位于同一位置(主脚本或您从中导入的模块)。
Learner.to_detach
Learner.to_detach (b, cpu=True, gather=True)
如果 self.dl
提供 .to_detach
函数,则调用 to_detach
,否则调用全局 to_detach
fastai 提供 to_detach
,它默认分离 tensor 梯度,并在分布式数据并行 (DDP) 模式下运行时从所有 ranks 收集 (调用 maybe_gather
) tensors。
在 DDP 模式下运行时,所有 ranks 需要具有相同的批次大小,DistributedDL
负责根据需要填充批次;然而,当收集所有 tensors(例如用于计算指标、推理等)时,我们需要丢弃填充项。DistributedDL
提供了一个方法 to_detach
,可以适当地移除填充。
调用 learner 的 to_detach
方法会尝试在 learner 最后使用的 DataLoader
dl
中查找 to_detach
方法,如果找到则使用该方法,否则将使用普通的 to_detach
。
Metric
Metric ()
定义度量的蓝图
度量可以是简单的平均值(如准确率),但有时它们的计算稍微复杂一些,不能跨批次平均(如精确率或召回率),这就是为什么我们需要一个特殊的类来处理它们。对于可以计算为批次平均值的简单函数,我们可以使用 AvgMetric
类,否则您需要实现以下方法。
如果您的 Metric
状态依赖于 tensors,请不要忘记将其存储在 CPU 上,以避免任何潜在的内存泄漏。
Metric.reset
Metric.reset ()
重置内部状态以准备新计算
Metric.accumulate
Metric.accumulate (learn)
使用 learn
更新新结果的状态
Metric.value
Metric.value ()
Metric.name
Metric.name ()
AvgMetric
AvgMetric (func)
考虑潜在不同的批次大小来平均 func
的值
= synth_learner()
learn = AvgMetric(lambda x,y: (x-y).abs().mean())
tst = torch.randn(100),torch.randn(100)
t,u
tst.reset()for i in range(0,100,25):
= t[i:i+25],(u[i:i+25],)
learn.pred,learn.yb
tst.accumulate(learn)-u).abs().mean()) test_close(tst.value, (t
AvgLoss
AvgLoss ()
考虑潜在不同的批次大小来平均损失
= AvgLoss()
tst = torch.randn(100)
t
tst.reset()for i in range(0,100,25):
= t[i:i+25],t[i:i+25].mean()
learn.yb,learn.loss
tst.accumulate(learn) test_close(tst.value, t.mean())
AvgSmoothLoss
AvgSmoothLoss (beta=0.98)
损失的平滑平均值(使用 beta
进行指数加权)
= AvgSmoothLoss()
tst = torch.randn(100)
t
tst.reset()= tensor(0.)
val for i in range(4):
= t[i*25:(i+1)*25].mean()
learn.loss
tst.accumulate(learn)= val*0.98 + t[i*25:(i+1)*25].mean()*(1-0.98)
val /(1-0.98**(i+1)), tst.value) test_close(val
ValueMetric
ValueMetric (func, metric_name=None)
用于包含预先计算的度量值(例如在 Callback
中计算并由 func
返回)
def metric_value_fn(): return 5e-3
= ValueMetric(metric_value_fn, 'custom_value_metric')
vm 5e-3)
test_eq(vm.value, 'custom_value_metric')
test_eq(vm.name,
= ValueMetric(metric_value_fn)
vm 'metric_value_fn') test_eq(vm.name,
Recorder –
Recorder
Recorder (add_time=True, train_metrics=False, valid_metrics=True, beta=0.98)
在训练期间记录统计信息(学习率、损失和度量)的 Callback
默认情况下,度量仅在验证集上计算,尽管可以通过调整 train_metrics
和 valid_metrics
来更改。beta
是用于计算损失的指数加权平均值(它为 Learner
提供 smooth_loss
属性)的权重。
Learner
的 logger
属性决定了这些度量的处理方式。默认情况下,它只打印它们
#Test printed output
def tst_metric(out, targ): return F.mse_loss(out, targ)
= synth_learner(n_train=5, metrics=tst_metric, default_cbs=False, cbs=[TrainEvalCallback, Recorder])
learn # pat = r"[tensor\(\d.\d*\), tensor\(\d.\d*\), tensor\(\d.\d*\), 'dd:dd']"
= r"\[\d, \d+.\d+, \d+.\d+, \d+.\d+, '\d\d:\d\d'\]"
pat lambda: learn.fit(1), pat, regex=True) test_stdout(
内部
Recorder.before_fit
Recorder.before_fit ()
准备训练状态
Recorder.before_epoch
Recorder.before_epoch ()
如果 self.add_time=True
,则设置计时器
Recorder.before_validate
Recorder.before_validate ()
重置损失和度量状态
Recorder.after_batch
Recorder.after_batch ()
更新所有度量并在训练中记录学习率和平滑损失
Recorder.after_epoch
Recorder.after_epoch ()
存储并记录损失/度量值
绘图工具
Recorder.plot_loss
Recorder.plot_loss (skip_start=5, with_valid=True, log=False, show_epochs=False, ax=None)
从 skip_start
开始绘制损失。可选地,log=True
用于对数轴,show_epochs=True
用于指示周期,以及要绘制在的 matplotlib 轴 ax
。
CastToTensor
CastToTensor (after_create=None, before_fit=None, before_epoch=None, before_train=None, before_batch=None, after_pred=None, after_loss=None, before_backward=None, after_cancel_backward=None, after_backward=None, before_step=None, after_cancel_step=None, after_step=None, after_cancel_batch=None, after_batch=None, after_cancel_train=None, after_train=None, before_validate=None, after_cancel_validate=None, after_validate=None, after_cancel_epoch=None, after_epoch=None, after_cancel_fit=None, after_fit=None)
将子类化的 Tensor 转换为 Tensor
PyTorch 中的一个 bug 的变通方案,其中子类化的 tensors(如 TensorBase
)在传递给模型时训练速度比 Tensor
慢约 20%。默认添加到 Learner
。
CastToTensor 的顺序紧接在 MixedPrecision
之前,因此使用 fastai 的 tensor 子类的回调仍然可以使用它们。
如果输入不是子类化的 tensor 或 tensors 的元组,您可能需要在 Learner
执行正向传播之前,通过您自己的回调或在 dataloader 中将 Learner.xb
和 Learner.yb
中的输入转换为 Tensor
。
如果 CastToTensor 变通方案干扰了自定义代码,可以将其移除
= Learner(...)
learn learn.remove_cb(CastToTensor)
如果移除了 CastToTensor,您应该验证您的输入类型为 Tensor
,或者通过自定义回调或 dataloader 实现转换为 Tensor
的操作。
推理函数
Learner.validate
Learner.validate (ds_idx=1, dl=None, cbs=None)
使用潜在的新 cbs
对 dl
进行验证。
#Test result
= synth_learner(n_train=5, metrics=tst_metric)
learn = learn.validate()
res 0], res[1])
test_eq(res[= learn.dls.valid_ds.tensors
x,y 0], F.mse_loss(learn.model(x), y), 1e-3) test_close(res[
Learner.get_preds
Learner.get_preds (ds_idx:int=1, dl=None, with_input:bool=False, with_decoded:bool=False, with_loss:bool=False, act=None, inner:bool=False, reorder:bool=True, cbs:Callback|MutableSequence|None=None, save_preds:Path=None, save_targs:Path=None, with_preds:bool=True, with_targs:bool=True, concat_dim:int=0, pickle_protocol:int=2)
获取 ds_idx
-th dbunchset 或 dl
上的预测和目标,可选地包含 with_input
和 with_loss
类型 | 默认 | 详情 | |
---|---|---|---|
ds_idx | int | 1 | 如果 dl 为 None,用于预测的 DataLoader 。0:训练。1:验证 |
dl | NoneType | None | 如果为 None,用于预测的 DataLoader ,默认为 ds_idx=1 |
with_input | bool | False | 返回包含输入的预测 |
with_decoded | bool | False | 返回解码后的预测 |
with_loss | bool | False | 返回包含每个 item 损失的预测 |
act | NoneType | None | 对预测应用激活函数,默认为 self.loss_func 的激活函数 |
inner | bool | False | 如果为 False,则创建进度条、显示日志、使用临时 cbs |
reorder | bool | True | 如果适用,根据数据集索引重新排序预测 |
cbs | Callback | MutableSequence | None | None | 预测期间应用的临时 Callback |
save_preds | Path | None | 保存预测的路径 |
save_targs | Path | None | 保存目标的路径 |
with_preds | bool | True | 是否返回预测 |
with_targs | bool | True | 是否返回目标 |
concat_dim | int | 0 | 连接返回 tensors 的维度 |
pickle_protocol | int | 2 | 用于保存预测和目标的 Pickle 协议 |
返回值 | tuple |
with_decoded
还会使用损失函数的 decodes
函数(如果存在)返回解码后的预测。例如,fastai 的 CrossEntropyFlat
在其 decodes 中取预测的 argmax。
根据 Learner
的 loss_func
属性,将自动选择一个激活函数,以便预测具有意义。例如,如果损失函数是交叉熵的一种情况,将应用 softmax;如果损失函数是带有 logits 的二元交叉熵,将应用 sigmoid。如果您想确保应用某个特定的激活函数,可以使用 act
参数传递它。
当您的预测过大无法全部放入内存时,应该使用 save_preds
和 save_targs
。提供一个 Path
对象,指向将保存预测和目标的文件夹。
concat_dim
是批次维度,所有 tensors 将在该维度上连接。
inner
是一个内部属性,它告诉 get_preds
它是在另一个训练循环内部被调用的,以避免递归错误。
如果您想在自定义损失函数上使用 with_loss=True
选项,请确保您已经实现了一个支持 'none' 的 reduction
属性。
#Test result
= synth_learner(n_train=5, metrics=tst_metric)
learn = learn.get_preds()
preds,targs = learn.dls.valid_ds.tensors
x,y
test_eq(targs, y)
test_close(preds, learn.model(x))
= learn.get_preds(act = torch.sigmoid)
preds,targs
test_eq(targs, y) test_close(preds, torch.sigmoid(learn.model(x)))
Learner.predict
Learner.predict (item, rm_type_tfms=None, with_input=False)
对 item
进行预测,完全解码,损失函数解码和概率
它返回一个包含三个元素的元组,逆序如下: - 模型的预测,可能经过损失函数的激活函数(如果存在) - 解码后的预测,使用其潜在的 decodes
方法 - 完全解码后的预测,使用构建 Datasets
/DataLoaders
使用的转换
rm_type_tfms
是一个已弃用的参数,不应使用,并将在未来版本中移除。with_input
将解码后的输入添加到结果中。
class _FakeLossFunc(Module):
= 'none'
reduction def forward(self, x, y): return F.mse_loss(x,y)
def activation(self, x): return x+1
def decodes(self, x): return 2*x
class _Add1(Transform):
def encodes(self, x): return x+1
def decodes(self, x): return x-1
= synth_learner(n_train=5)
learn = TfmdDL(Datasets(torch.arange(50), tfms = [L(), [_Add1()]]))
dl = DataLoaders(dl, dl)
learn.dls = _FakeLossFunc()
learn.loss_func
= tensor([2.])
inp = learn.model(inp).detach()+1 #applying model + activation
out = 2*out #decodes from loss function
dec = dec-1 #decodes from _Add1
full_dec
test_eq(learn.predict(inp), [full_dec,dec,out])=True), [inp,full_dec,dec,out]) test_eq(learn.predict(inp, with_input
Learner.show_results
Learner.show_results (ds_idx=1, dl=None, max_n=9, shuffle=True, **kwargs)
显示 ds_idx
-th 数据集或 dl
上的一些预测
将显示 max_n
个样本(除非 ds_idx
或 dl
的批次大小小于 max_n
,在这种情况下,它将显示尽可能多的样本),并打乱数据,除非您将该标志设置为 false
。kwargs
取决于应用。
我们无法在我们的合成 Learner
上显示示例,但请查看所有初学者教程,它们将向您展示此方法在不同应用中的工作原理。
本节的最后几个函数用于内部推理,但对您来说可能不太有用。
Learner.no_logging
Learner.no_logging ()
= synth_learner(n_train=5, metrics=tst_metric)
learn with learn.no_logging():
lambda: learn.fit(1), '')
test_stdout(print) test_eq(learn.logger,
Learner.loss_not_reduced
Learner.loss_not_reduced ()
这要求您的损失函数要么有一个 reduction
属性,要么有一个 reduction
参数(就像所有 fastai 和 PyTorch 损失函数一样)。
迁移学习
Learner.unfreeze
Learner.unfreeze ()
解冻整个模型
Learner.freeze
Learner.freeze ()
冻结到最后一个参数组
Learner.freeze_to
Learner.freeze_to (n)
冻结直到 n
的参数组
TTA
Learner.tta
Learner.tta (ds_idx=1, dl=None, n=4, item_tfms=None, batch_tfms=None, beta=0.25, use_max=False)
使用测试时间增强返回 ds_idx
数据集或 dl
上的预测
实际上,我们使用训练集的变换获取预测 n
次并求平均值。最终预测是该平均值乘以 (1-beta)
+ 使用数据集变换获得的预测乘以 beta
。将 beta
设置为 None
以获得预测和 tta 结果的元组。您也可以通过设置 use_max=True
来使用所有预测的最大值而不是平均值。
如果您想使用新的变换,可以使用 item_tfms
和 batch_tfms
进行传递。