# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ## MNIST CNN

# %reload_ext autoreload
# %autoreload 2
# %matplotlib inline

from fastai.vision.all import *
matplotlib.rc('image', cmap='Greys')

# ### Data

# path = untar_data(URLs.MNIST_SAMPLE)
path = untar_data(URLs.MNIST)

path

# +
# # !ls /home/ext-share/.fastai/data/mnist_sample

# +
# # !ls /home/ext-share/.fastai/data/mnist_png/
# -

# # !cp -r /home/ext-share/.fastai/data/mnist_png/train /home/ext-share/.fastai/data/mnist_png/train


im3 = Image.open(path/'train'/'3'/'12.png')
# im3 = Image.open(path/'training'/'3'/'12.png')
show_image(im3);

# +
im3_t = tensor(im3)

df = pd.DataFrame(im3_t[:28,:28])
df.style.set_properties(**{'font-size':'6pt'}).background_gradient('Greys')

# +
# # GrandparentSplitter??

# +
# datablock

# GrandparentSplitter require something...  

mnist = DataBlock((ImageBlock(cls=PILImageBW),
                   CategoryBlock), 
                   get_items=get_image_files, 
                   splitter=RandomSplitter(valid_pct=0.2, seed=42),
#                    splitter=GrandparentSplitter(),
                   get_y=parent_label)

dls = mnist.dataloaders(path)
xb,yb = first(dls.valid)
xb.shape
# -

len(dls.train), len(dls.valid)

# +
# il.items[0]

# +
# 28*28 784
# (784) > (1, 28, 28)

# +
# 以前やった時は(64, 784) だった
# -



dls.show_batch()



# ### Basic CNN with batchnorm

# +
# convolutionはnn.Conv2d使うだけ

# stride 2
def conv_stride2(ni,nf):
    return nn.Conv2d(ni, nf, kernel_size=3, stride=2, padding=1)


# -

model = nn.Sequential(
    
    conv_stride2(1, 8), # 14
    nn.BatchNorm2d(8),
    nn.ReLU(),
    
    conv_stride2(8, 16), # 7
    nn.BatchNorm2d(16),
    nn.ReLU(),
    
    conv_stride2(16, 32), # 4
    nn.BatchNorm2d(32),
    nn.ReLU(),
    
    conv_stride2(32, 16), # 2
    nn.BatchNorm2d(16),
    nn.ReLU(),
    
    conv_stride2(16, 10), # 1
    nn.BatchNorm2d(10),
    
    Flatten()     # remove (1,1) grid
)

model

learn = Learner(dls, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)

model.cuda()

xb = xb.cuda()

model(xb).shape

learn.lr_find(end_lr=100)



learn.fit_one_cycle(3, max_lr=0.1)





# ### Refactor

# +
# def conv_stride2(ni,nf):

def conv_stride2_and_bn_relu(ni,nf):
    return nn.Sequential(
        conv_stride2(ni, nf),
        nn.BatchNorm2d(nf),
        nn.ReLU(),
    )


# -

model = nn.Sequential(
    
    conv_stride2_and_bn_relu(1, 8),
    
    conv_stride2_and_bn_relu(8, 16),
    
    conv_stride2_and_bn_relu(16, 32),
    
    conv_stride2_and_bn_relu(32, 16),
    
    conv_stride2(16, 10), # 1
    nn.BatchNorm2d(10),
    
    Flatten()     # remove (1,1) grid
)

model





# stride 1
def conv_stride1(ni,nf):
    return nn.Conv2d(ni, nf, kernel_size=3, stride=1, padding=1)


def conv_stride1_and_bn_relu(ni,nf):
    return nn.Sequential(
        conv_stride1(ni, nf),
        nn.BatchNorm2d(nf),
        nn.ReLU(),
    )


learn = Learner(dls, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)

learn.summary()

learn.fit_one_cycle(3, max_lr=0.1)



# +
# stride 1を使えば延々と長くできる

model = nn.Sequential(
    
    conv_stride2_and_bn_relu(1, 8),
    
    conv_stride1_and_bn_relu(8, 8),
    
    conv_stride2_and_bn_relu(8, 16),
    
    conv_stride1_and_bn_relu(16, 16),
    
    conv_stride2_and_bn_relu(16, 32),
    
    conv_stride1_and_bn_relu(32, 32),
    
    conv_stride2_and_bn_relu(32, 16),
    
    conv_stride1_and_bn_relu(16, 16),
    
    conv_stride2(16, 10), # 1
    nn.BatchNorm2d(10),
    
    Flatten()     # remove (1,1) grid
)
# -

learn = Learner(dls, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)

learn.summary()

learn.fit_one_cycle(1, max_lr=0.1)





# ### Resnet-ish

class ResBlock(nn.Module):
    def __init__(self, nf):
        super().__init__()
        self.conv1 = conv_stride1_and_bn_relu(nf,nf)
        self.conv2 = conv_stride1_and_bn_relu(nf,nf)
        
    def forward(self, x):
        return x + self.conv1(self.conv2(x))



model = nn.Sequential(
    
    conv_stride2(1, 8),
    ResBlock(8),
    
    conv_stride2(8, 16),
    ResBlock(16),
    
    conv_stride2(16, 32),
    ResBlock(32),
    
    conv_stride2(32, 16),
    ResBlock(16),
    
    conv2(16, 10),
    Flatten()
)


def conv_and_res(ni,nf):
    return nn.Sequential(conv_stride2(ni, nf), ResBlock(nf))


model = nn.Sequential(
    conv_and_res(1, 8),
    conv_and_res(8, 16),
    conv_and_res(16, 32),
    conv_and_res(32, 16),
    conv2(16, 10),
    Flatten()
)

# +
# model
# -

learn = Learner(dls, model, loss_func = nn.CrossEntropyLoss(), metrics=accuracy)

learn.lr_find()

learn.fit_one_cycle(1, max_lr=0.05)

print(learn.summary())

# ## fin





# fastaiのソースコード
class MergeLayer(Module):
    "Merge a shortcut with the result of the module by adding them or concatenating them if `dense=True`."
    def __init__(self, dense:bool=False): self.dense=dense
    def forward(self, x):
        if self.dense:
            return torch.cat([x,x.orig], dim=1) 
        else:
            return (x + x.orig)











StarcoderdataJupyterScriptsDedupFiltered