! [ -e /content ] && pip install -Uqq fastai # 在Colab上升级fastai
视觉小部件
from __future__ import annotations
from fastai.torch_basics import *
from fastai.data.all import *
from fastai.vision.core import *
from fastcore.parallel import *
from ipywidgets import HBox,VBox,widgets,Button,Checkbox,Dropdown,Layout,Box,Output,Label,FileUpload
from nbdev.showdoc import *
= ['HBox','VBox','widgets','Button','Checkbox','Dropdown','Layout','Box','Output','Label','FileUpload'] _all_
用于图像的ipywidgets
@patch
def __getitem__(self:Box, i): return self.children[i]
def widget(im, *args, **layout) -> Output:
"Convert anything that can be `display`ed by `IPython` into a widget"
= Output(layout=merge(*args, layout))
o with o: display(im)
return o
show_doc(widget)
widget
widget (im, *args, **layout)
Convert anything that can be display
ed by IPython
into a widget
= Image.open('images/puppy.jpg').to_thumb(256,512)
im 'Puppy'),
VBox([widgets.HTML(="192px")]) widget(im, max_width
def _update_children(
dict # 一个存储有关已更改小部件信息的字典
change:
):"Sets a value to the `layout` attribute on widget initialization and change"
for o in change['owner'].children:
if not o.layout.flex: o.layout.flex = '0 0 auto'
def carousel(
tuple|MutableSequence=(), # 用于在轮播图中展示的`Box`对象
children:**layout
-> Box: # An `ipywidget`'s carousel
) "A horizontally scrolling carousel"
= dict(overflow='scroll hidden', flex_flow='row', display='flex')
def_layout = Box([], layout=merge(def_layout, layout))
res ='children')
res.observe(_update_children, names= children
res.children return res
show_doc(carousel)
carousel
carousel (children:Union[tuple,list]=(), **layout)
A horizontally scrolling carousel
Type | Default | Details | |
---|---|---|---|
children | tuple | list | () | Box objects to display in a carousel |
layout | |||
Returns | Box | An ipywidget ’s carousel |
= [VBox([widget(im, max_width='192px'), Button(description='click')])
ts for o in range(3)]
='450px') carousel(ts, width
def _open_thumb(
|str, # 图像的路径
fn:Pathint, # 缩略图高度
h:int # 缩略图宽度
w:-> Image: # 显示的`PIL`图像
) "Opens an image path and returns the thumbnail of the image"
return Image.open(fn).to_thumb(h, w).convert('RGBA')
class ImagesCleaner:
"A widget that displays all images in `fns` along with a `Dropdown`"
def __init__(self,
tuple=(), # `Dropdown` 菜单的选项
opts:int=128, # 缩略图高度
height:int=256, # 缩略图宽度
width:int=30 # 显示的最大图片数量
max_n:
):= ('<Keep>', '<Delete>')+tuple(opts)
opts 'opts,height,width,max_n')
store_attr(self.widget = carousel(width='100%')
def set_fns(self,
list # 包含每个图像的路径
fns:
):"Sets a `thumbnail` and a `Dropdown` menu for each `VBox`"
self.fns = L(fns)[:self.max_n]
= parallel(_open_thumb, self.fns, h=self.height, w=self.width, progress=False,
ims =min(len(self.fns)//10,defaults.cpus))
n_workersself.widget.children = [VBox([widget(im, height=f'{self.height}px'), Dropdown(
=self.opts, layout={'width': 'max-content'})]) for im in ims]
options
def _ipython_display_(self): display(self.widget)
def values(self) -> list:
"Current values of `Dropdown` for each `VBox`"
return L(self.widget.children).itemgot(1).attrgot('value')
def delete(self) -> list:
"Indices of items to delete"
return self.values().argwhere(eq('<Delete>'))
def change(self) -> list:
"Tuples of the form (index of item to change, new class)"
= self.values().argwhere(not_(in_(['<Delete>','<Keep>'])))
idxs return idxs.zipwith(self.values()[idxs])
show_doc(ImagesCleaner)
ImagesCleaner
ImagesCleaner (opts:'tuple'=(), height:'int'=128, width:'int'=256, max_n:'int'=30)
A widget that displays all images in fns
along with a Dropdown
Type | Default | Details | |
---|---|---|---|
opts | tuple | () | Options for the Dropdown menu |
height | int | 128 | Thumbnail Height |
width | int | 256 | Thumbnail Width |
max_n | int | 30 | Max number of images to display |
= get_image_files('images')
fns = ImagesCleaner(('A','B'))
w
w.set_fns(fns) w
w.delete(),w.change()
((#0) [], (#0) [])
def _get_iw_info(
learn,int=0 # `learn.dls`中的索引
ds_idx:-> list:
) "For every image in `dls` `zip` it's `Path`, target and loss"
= learn.dls[ds_idx].new(shuffle=False, drop_last=False)
dl = learn.get_preds(dl=dl, with_input=False, with_loss=True, with_decoded=True)
probs,targs,preds,losses = [dl.vocab[t] for t in targs]
targs return L([dl.dataset.items,targs,losses]).zip()
@delegates(ImagesCleaner)
class ImageClassifierCleaner(GetAttr):
"A widget that provides an `ImagesCleaner` for a CNN `Learner`"
def __init__(self, learn, **kwargs):
= learn.dls.vocab
vocab self.default = self.iw = ImagesCleaner(vocab, **kwargs)
self.dd_cats = Dropdown(options=vocab)
self.dd_ds = Dropdown(options=('Train','Valid'))
self.iwis = _get_iw_info(learn,0),_get_iw_info(learn,1)
self.dd_ds.observe(self.on_change_ds, 'value')
self.dd_cats.observe(self.on_change_ds, 'value')
self.on_change_ds()
self.widget = VBox([self.dd_cats, self.dd_ds, self.iw.widget])
def _ipython_display_(self): display(self.widget)
def on_change_ds(self,change=None):
"Toggle between training validation set view"
= L(o for o in self.iwis[self.dd_ds.index] if o[1]==self.dd_cats.value)
info self.iw.set_fns(info.sorted(2, reverse=True).itemgot(0))
show_doc(ImageClassifierCleaner)
ImageClassifierCleaner
ImageClassifierCleaner (learn, opts:'tuple'=(), height:'int'=128, width:'int'=256, max_n:'int'=30)
A widget that provides an ImagesCleaner
for a CNN Learner
导出 -
import nbdev; nbdev.nbdev_export()