import%20marimo%0A%0A__generated_with%20%3D%20%220.25.0%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20AlexNet%20under%20the%20hood%0A%0A%20%20%20%20**Lecture%203B%20companion.**%20We%20load%20the%20pretrained%20AlexNet%20from%20%60torchvision%60%20and%20look%20inside%3A%0A%20%20%20%20what%20it%20predicts%2C%20what%20its%2064%20first-layer%20kernels%20look%20like%2C%20which%20activation%20maps%20light%20up%0A%20%20%20%20in%20each%20layer%2C%20which%20parts%20of%20an%20image%20matter%20for%20the%20decision%2C%20what%20images%20each%20unit%20%22wants%0A%20%20%20%20to%20see%22%2C%20and%20how%20images%20are%20arranged%20in%20its%204096-dimensional%20embedding%20space.%0A%0A%20%20%20%20Install%20once%20(Python%203.10%2B)%2C%20from%20the%20%60Lecture_3B%60%20folder%3A%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20python3.12%20-m%20venv%20.venv%0A%20%20%20%20.venv%2Fbin%2Fpython%20-m%20pip%20install%20-r%20requirements.txt%0A%20%20%20%20.venv%2Fbin%2Fmarimo%20edit%20AlexNet_under_the_hood.py%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20The%20first%20run%20downloads%20the%20AlexNet%20weights%20(about%20240%20MB)%20into%20%60~%2F.cache%2Ftorch%60.%0A%20%20%20%20Everything%20runs%20on%20a%20laptop%20CPU.%20Test%20images%20are%20the%20public-domain%20%2F%20CC0%20samples%20bundled%20with%0A%20%20%20%20scikit-image%3B%20you%20can%20also%20upload%20your%20own%20photo%20below.%0A%0A%20%20%20%20The%20architecture%20is%20the%20torchvision%20version%20of%20AlexNet%20(64%20kernels%20in%20the%20first%20layer%2C%20no%20local%0A%20%20%20%20response%20normalization)%3B%20the%202012%20paper%20used%2096%20first-layer%20kernels%20split%20over%20two%20GPUs.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20io%0A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20torch%0A%20%20%20%20import%20torchvision%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20from%20PIL%20import%20Image%0A%20%20%20%20import%20skimage.data%20as%20skd%0A%0A%20%20%20%20torch.set_grad_enabled(False)%0A%20%20%20%20plt.rcParams.update(%7B%22figure.dpi%22%3A%20110%2C%20%22font.size%22%3A%2010%7D)%0A%20%20%20%20return%20Image%2C%20io%2C%20np%2C%20plt%2C%20skd%2C%20torch%2C%20torchvision%0A%0A%0A%40app.cell%0Adef%20_(torch%2C%20torchvision)%3A%0A%20%20%20%20WEIGHTS%20%3D%20torchvision.models.AlexNet_Weights.IMAGENET1K_V1%0A%20%20%20%20net%20%3D%20torchvision.models.alexnet(weights%3DWEIGHTS).eval()%0A%20%20%20%20CATS%20%3D%20WEIGHTS.meta%5B%22categories%22%5D%0A%20%20%20%20MEAN%20%3D%20torch.tensor(%5B0.485%2C%200.456%2C%200.406%5D)%5B%3A%2C%20None%2C%20None%5D%0A%20%20%20%20STD%20%3D%20torch.tensor(%5B0.229%2C%200.224%2C%200.225%5D)%5B%3A%2C%20None%2C%20None%5D%0A%20%20%20%20%23%20Position%20in%20net.features%20just%20after%20each%20ReLU.%0A%20%20%20%20AFTER%20%3D%20%7B%22conv1%22%3A%202%2C%20%22conv2%22%3A%205%2C%20%22conv3%22%3A%207%2C%20%22conv4%22%3A%209%2C%20%22conv5%22%3A%2011%7D%0A%20%20%20%20n_params%20%3D%20sum(p.numel()%20for%20p%20in%20net.parameters())%0A%20%20%20%20print(net)%0A%20%20%20%20print(f%22%7Bn_params%3A%2C%7D%20parameters%22)%0A%20%20%20%20return%20AFTER%2C%20CATS%2C%20MEAN%2C%20STD%2C%20net%0A%0A%0A%40app.cell%0Adef%20_(Image%2C%20MEAN%2C%20STD%2C%20np%2C%20torch)%3A%0A%20%20%20%20def%20to_tensor(im)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Short%20side%20to%20256%20pixels%2C%20centre%20crop%20224%20%C3%97%20224%2C%20values%20in%20%5B0%2C%201%5D.%22%22%22%0A%20%20%20%20%20%20%20%20im%20%3D%20im.convert(%22RGB%22)%0A%20%20%20%20%20%20%20%20w%2C%20h%20%3D%20im.size%0A%20%20%20%20%20%20%20%20s%20%3D%20256%20%2F%20min(w%2C%20h)%0A%20%20%20%20%20%20%20%20im%20%3D%20im.resize((round(w%20*%20s)%2C%20round(h%20*%20s))%2C%20Image.BILINEAR)%0A%20%20%20%20%20%20%20%20w%2C%20h%20%3D%20im.size%0A%20%20%20%20%20%20%20%20l%2C%20t%20%3D%20(w%20-%20224)%20%2F%2F%202%2C%20(h%20-%20224)%20%2F%2F%202%0A%20%20%20%20%20%20%20%20im%20%3D%20im.crop((l%2C%20t%2C%20l%20%2B%20224%2C%20t%20%2B%20224))%0A%20%20%20%20%20%20%20%20return%20torch.from_numpy(np.asarray(im%2C%20dtype%3Dnp.float32)%20%2F%20255).permute(2%2C%200%2C%201)%0A%0A%20%20%20%20def%20norm(x01)%3A%0A%20%20%20%20%20%20%20%20%22%22%22ImageNet%20normalization%3B%20adds%20the%20batch%20dimension.%22%22%22%0A%20%20%20%20%20%20%20%20return%20((x01%20-%20MEAN)%20%2F%20STD)%5BNone%5D%0A%0A%20%20%20%20def%20show(x01)%3A%0A%20%20%20%20%20%20%20%20return%20x01.clamp(0%2C%201).permute(1%2C%202%2C%200).numpy()%0A%0A%20%20%20%20return%20norm%2C%20show%2C%20to_tensor%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20Choose%20an%20image%0A%0A%20%20%20%20AlexNet%20maps%20a%20224%20%C3%97%20224%20%C3%97%203%20array%20of%20pixel%20intensities%20to%201000%20probabilities%2C%20one%20per%20ImageNet%20class.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20samples%20%3D%20%5B%22chelsea%22%2C%20%22astronaut%22%2C%20%22camera%22%2C%20%22coffee%22%2C%20%22rocket%22%2C%20%22brick%22%2C%20%22hubble_deep_field%22%5D%0A%20%20%20%20sample%20%3D%20mo.ui.dropdown(samples%2C%20value%3D%22chelsea%22%2C%20label%3D%22Sample%20image%22)%0A%20%20%20%20upload%20%3D%20mo.ui.file(filetypes%3D%5B%22.png%22%2C%20%22.jpg%22%2C%20%22.jpeg%22%2C%20%22.webp%22%5D%2C%20label%3D%22%E2%80%A6or%20upload%20your%20own%22)%0A%20%20%20%20mo.hstack(%5Bsample%2C%20upload%5D%2C%20justify%3D%22start%22%2C%20gap%3D2)%0A%20%20%20%20return%20sample%2C%20samples%2C%20upload%0A%0A%0A%40app.cell%0Adef%20_(CATS%2C%20Image%2C%20io%2C%20net%2C%20norm%2C%20plt%2C%20sample%2C%20show%2C%20skd%2C%20to_tensor%2C%20upload)%3A%0A%20%20%20%20if%20upload.value%3A%0A%20%20%20%20%20%20%20%20image_name%20%3D%20upload.name()%0A%20%20%20%20%20%20%20%20pil%20%3D%20Image.open(io.BytesIO(upload.contents()))%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20image_name%20%3D%20sample.value%0A%20%20%20%20%20%20%20%20pil%20%3D%20Image.fromarray(getattr(skd%2C%20sample.value)())%0A%20%20%20%20x01%20%3D%20to_tensor(pil)%0A%20%20%20%20probs%20%3D%20net(norm(x01)).softmax(1)%5B0%5D%0A%20%20%20%20top%20%3D%20probs.topk(5)%0A%0A%20%20%20%20_fig%2C%20(_a%2C%20_b)%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(9%2C%203.4)%2C%20gridspec_kw%3D%7B%22width_ratios%22%3A%20%5B1%2C%201.4%5D%7D)%0A%20%20%20%20_a.imshow(show(x01))%3B%20_a.set_axis_off()%3B%20_a.set_title(f%22input%3A%20%7Bimage_name%7D%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_labels%20%3D%20%5BCATS%5Bi%5D%20for%20i%20in%20top.indices%5D%5B%3A%3A-1%5D%0A%20%20%20%20_b.barh(_labels%2C%20top.values.numpy()%5B%3A%3A-1%5D%2C%20color%3D%22%23087bb9%22)%0A%20%20%20%20_b.set_xlim(0%2C%201)%3B%20_b.set_xlabel(%22probability%22)%3B%20_b.set_title(%22top-5%20predictions%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_b.spines%5B%5B%22top%22%2C%20%22right%22%5D%5D.set_visible(False)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%20image_name%2C%20x01%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20ImageNet%20has%20no%20*astronaut*%20or%20*rocket*%20class%3A%20the%20network%20must%20choose%20among%20its%201000%20labels%0A%20%20%20%20(the%20rocket%20usually%20becomes%20a%20*mosque*%2C%20the%20astronaut%20a%20*dumbbell*).%20A%20classifier%20always%20answers.%0A%0A%20%20%20%20%23%23%202.%20Layer%201%3A%2064%20kernels%20of%2011%20%C3%97%2011%20%C3%97%203%20weights%0A%0A%20%20%20%20A%20first-layer%20kernel%20has%20depth%203%2C%20like%20the%20image%2C%20so%20we%20can%20draw%20it%20as%20a%20tiny%20RGB%20picture.%0A%20%20%20%20All%20of%20them%20started%20as%20random%20numbers%3B%20the%20patterns%20were%20learned%20from%20data%3A%0A%20%20%20%20edge%20detectors%20at%20many%20angles%2C%20and%20colour%20blobs.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(net%2C%20plt)%3A%0A%20%20%20%20kernels%20%3D%20net.features%5B0%5D.weight.detach()%20%20%20%20%20%20%20%20%23%2064%20%C3%97%203%20%C3%97%2011%20%C3%97%2011%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(8%2C%208%2C%20figsize%3D(6.5%2C%206.5))%0A%20%20%20%20for%20_i%2C%20_ax%20in%20enumerate(_axes.flat)%3A%0A%20%20%20%20%20%20%20%20_k%20%3D%20kernels%5B_i%5D%0A%20%20%20%20%20%20%20%20_ax.imshow(((_k%20-%20_k.min())%20%2F%20(_k.max()%20-%20_k.min())).permute(1%2C%202%2C%200).numpy()%2C%20interpolation%3D%22nearest%22)%0A%20%20%20%20%20%20%20%20_ax.set_title(str(_i)%2C%20fontsize%3D7%2C%20pad%3D1)%3B%20_ax.set_axis_off()%0A%20%20%20%20_fig.tight_layout(pad%3D0.2)%0A%20%20%20%20_fig%0A%20%20%20%20return%20(kernels%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20kernel_idx%20%3D%20mo.ui.slider(0%2C%2063%2C%20value%3D9%2C%20label%3D%22Kernel%22%2C%20show_value%3DTrue%2C%20full_width%3DTrue)%0A%20%20%20%20kernel_idx%0A%20%20%20%20return%20(kernel_idx%2C)%0A%0A%0A%40app.cell%0Adef%20_(kernel_idx%2C%20kernels%2C%20mo%2C%20net%2C%20norm%2C%20plt%2C%20show%2C%20x01)%3A%0A%20%20%20%20_k%20%3D%20kernel_idx.value%0A%20%20%20%20_amap%20%3D%20net.features%5B%3A2%5D(norm(x01))%5B0%2C%20_k%5D%20%20%20%20%20%20%20%20%20%20%20%20%23%20conv1%20%2B%20ReLU%3A%2055%20%C3%97%2055%0A%20%20%20%20_w%20%3D%20kernels%5B_k%5D%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(1%2C%203%2C%20figsize%3D(10%2C%203.4))%0A%20%20%20%20_axes%5B0%5D.imshow(((_w%20-%20_w.min())%20%2F%20(_w.max()%20-%20_w.min())).permute(1%2C%202%2C%200).numpy()%2C%20interpolation%3D%22nearest%22)%0A%20%20%20%20_axes%5B0%5D.set_title(f%22kernel%20%7B_k%7D%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_axes%5B1%5D.imshow(_amap.numpy()%2C%20cmap%3D%22viridis%22)%3B%20_axes%5B1%5D.set_title(%22activation%20map%2055%20%C3%97%2055%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_axes%5B2%5D.imshow(show(x01))%3B%20_axes%5B2%5D.imshow(_amap.numpy()%2C%20cmap%3D%22viridis%22%2C%20alpha%3D0.6%2C%20extent%3D(0%2C%20224%2C%20224%2C%200))%0A%20%20%20%20_axes%5B2%5D.set_title(%22overlay%22%2C%20loc%3D%22left%22)%0A%20%20%20%20for%20_ax%20in%20_axes%3A%20_ax.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20mo.vstack(%5B%0A%20%20%20%20%20%20%20%20_fig%2C%0A%20%20%20%20%20%20%20%20mo.md(f%22The%20map%20is%20the%20dot%20product%20of%20kernel%20%7B_k%7D%20with%20every%2011%20%C3%97%2011%20patch%20(stride%204)%2C%20after%20ReLU.%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Bright%20%3D%20the%20patch%20looks%20like%20the%20kernel.%20Maximum%20here%3A%20**%7Bfloat(_amap.max())%3A.1f%7D**.%22)%2C%0A%20%20%20%20%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20Stack%20and%20repeat%3A%20activation%20maps%20in%20every%20layer%0A%0A%20%20%20%20The%2064%20maps%20of%20layer%201%20are%20stacked%20into%20a%2064-channel%20tensor%2C%20which%20layer%202%20processes%20with%0A%20%20%20%205%20%C3%97%205%20%C3%97%2064%20kernels%2C%20and%20so%20on.%20Deeper%20maps%20are%20coarser%20but%20respond%20to%20larger%2C%20more%20abstract%0A%20%20%20%20patterns.%20Try%20**conv5%2C%20channel%20174**%20on%20%60astronaut%60%20or%20%60camera%60%3A%20it%20fires%20on%20human%20faces%2C%20although%0A%20%20%20%20%22face%22%20is%20not%20an%20ImageNet%20class.%20Cover%20the%20face%20in%20your%20own%20photo%20and%20it%20goes%20quiet.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20layer%20%3D%20mo.ui.dropdown(%5B%22conv1%22%2C%20%22conv2%22%2C%20%22conv3%22%2C%20%22conv4%22%2C%20%22conv5%22%5D%2C%20value%3D%22conv5%22%2C%20label%3D%22Layer%22)%0A%20%20%20%20layer%0A%20%20%20%20return%20(layer%2C)%0A%0A%0A%40app.cell%0Adef%20_(AFTER%2C%20layer%2C%20mo%2C%20net%2C%20norm%2C%20x01)%3A%0A%20%20%20%20maps%20%3D%20net.features%5B%3AAFTER%5Blayer.value%5D%5D(norm(x01))%5B0%5D%0A%20%20%20%20channel%20%3D%20mo.ui.slider(0%2C%20maps.shape%5B0%5D%20-%201%2C%20value%3Dmin(174%2C%20maps.shape%5B0%5D%20-%201)%2C%20label%3D%22Channel%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20show_value%3DTrue%2C%20full_width%3DTrue)%0A%20%20%20%20channel%0A%20%20%20%20return%20channel%2C%20maps%0A%0A%0A%40app.cell%0Adef%20_(channel%2C%20layer%2C%20maps%2C%20mo%2C%20np%2C%20plt%2C%20show%2C%20x01)%3A%0A%20%20%20%20_n%20%3D%20maps.shape%5B0%5D%0A%20%20%20%20_cols%20%3D%20int(np.ceil(np.sqrt(_n)))%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(_cols%2C%20_cols%2C%20figsize%3D(6.5%2C%206.5))%0A%20%20%20%20_vmax%20%3D%20float(maps.max())%20*%200.6%20%2B%201e-6%0A%20%20%20%20for%20_i%2C%20_ax%20in%20enumerate(_axes.flat)%3A%0A%20%20%20%20%20%20%20%20_ax.set_axis_off()%0A%20%20%20%20%20%20%20%20if%20_i%20%3C%20_n%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax.imshow(maps%5B_i%5D.numpy()%2C%20cmap%3D%22viridis%22%2C%20vmin%3D0%2C%20vmax%3D_vmax)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_i%20%3D%3D%20channel.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_ax.set_axis_on()%3B%20_ax.set_xticks(%5B%5D)%3B%20_ax.set_yticks(%5B%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20_s%20in%20_ax.spines.values()%3A%20_s.set_color(%22%23c74842%22)%3B%20_s.set_linewidth(3)%0A%20%20%20%20_fig.suptitle(f%22%7Blayer.value%7D%3A%20%7B_n%7D%20maps%20of%20%7Bmaps.shape%5B1%5D%7D%20%C3%97%20%7Bmaps.shape%5B2%5D%7D%22%2C%20x%3D0.02%2C%20ha%3D%22left%22%2C%20fontsize%3D10)%0A%20%20%20%20_fig.tight_layout(pad%3D0.15%2C%20rect%3D(0%2C%200%2C%201%2C%200.96))%0A%0A%20%20%20%20_m%20%3D%20maps%5Bchannel.value%5D.numpy()%0A%20%20%20%20_g%2C%20_ax2%20%3D%20plt.subplots(figsize%3D(3.6%2C%203.6))%0A%20%20%20%20_ax2.imshow(show(x01))%3B%20_ax2.imshow(_m%2C%20cmap%3D%22viridis%22%2C%20alpha%3D0.65%2C%20extent%3D(0%2C%20224%2C%20224%2C%200)%2C%20vmin%3D0%2C%20vmax%3Dmax(_m.max()%2C%201e-6))%0A%20%20%20%20_ax2.set_title(f%22%7Blayer.value%7D%2C%20channel%20%7Bchannel.value%7D%3A%20max%20%7B_m.max()%3A.1f%7D%22%2C%20loc%3D%22left%22%2C%20fontsize%3D9)%0A%20%20%20%20_ax2.set_axis_off()%3B%20_g.tight_layout()%0A%20%20%20%20mo.hstack(%5B_fig%2C%20_g%5D%2C%20justify%3D%22start%22%2C%20align%3D%22center%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20Occlusion%3A%20which%20pixels%20matter%20for%20the%20decision%3F%0A%0A%20%20%20%20Slide%20a%20grey%20square%20over%20the%20image%20and%20record%20the%20probability%20of%20the%20top%20class%20at%20each%20position%0A%20%20%20%20(Zeiler%20%26%20Fergus%2C%202014).%20Where%20the%20probability%20drops%2C%20the%20network%20relied%20on%20that%20region.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20patch%20%3D%20mo.ui.slider(16%2C%2096%2C%20step%3D8%2C%20value%3D48%2C%20label%3D%22Patch%20size%22%2C%20show_value%3DTrue)%0A%20%20%20%20run_occlusion%20%3D%20mo.ui.run_button(label%3D%22Run%20occlusion%22)%0A%20%20%20%20mo.hstack(%5Bpatch%2C%20run_occlusion%5D%2C%20justify%3D%22start%22%2C%20gap%3D2)%0A%20%20%20%20return%20patch%2C%20run_occlusion%0A%0A%0A%40app.cell%0Adef%20_(CATS%2C%20mo%2C%20net%2C%20norm%2C%20patch%2C%20plt%2C%20run_occlusion%2C%20show%2C%20torch%2C%20x01)%3A%0A%20%20%20%20mo.stop(not%20run_occlusion.value%2C%20mo.md(%22*Press%20the%20button%20(about%205%20s%20on%20a%20laptop).*%22))%0A%20%20%20%20_p%20%3D%20patch.value%0A%20%20%20%20_stride%20%3D%20max(4%2C%20_p%20%2F%2F%204)%0A%20%20%20%20_pos%20%3D%20list(range(0%2C%20224%20-%20_p%20%2B%201%2C%20_stride))%0A%20%20%20%20_base%20%3D%20net(norm(x01)).softmax(1)%5B0%5D%0A%20%20%20%20_cls%20%3D%20int(_base.argmax())%0A%20%20%20%20_batch%20%3D%20%5B%5D%0A%20%20%20%20for%20_r%20in%20_pos%3A%0A%20%20%20%20%20%20%20%20for%20_c%20in%20_pos%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_y%20%3D%20x01.clone()%3B%20_y%5B%3A%2C%20_r%3A_r%20%2B%20_p%2C%20_c%3A_c%20%2B%20_p%5D%20%3D%200.5%0A%20%20%20%20%20%20%20%20%20%20%20%20_batch.append(norm(_y))%0A%20%20%20%20_probs%20%3D%20torch.cat(%5Bnet(torch.cat(_batch%5B_i%3A_i%20%2B%2064%5D)).softmax(1)%5B%3A%2C%20_cls%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20_i%20in%20mo.status.progress_bar(range(0%2C%20len(_batch)%2C%2064)%2C%20title%3D%22occluding%22)%5D)%0A%20%20%20%20_heat%20%3D%20_probs.reshape(len(_pos)%2C%20len(_pos)).numpy()%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(8.5%2C%203.8))%0A%20%20%20%20_axes%5B0%5D.imshow(show(x01))%3B%20_axes%5B0%5D.set_title(%22input%22%2C%20loc%3D%22left%22)%0A%20%20%20%20_im%20%3D%20_axes%5B1%5D.imshow(_heat%2C%20cmap%3D%22magma%22%2C%20extent%3D(_p%20%2F%202%2C%20224%20-%20_p%20%2F%202%2C%20224%20-%20_p%20%2F%202%2C%20_p%20%2F%202))%0A%20%20%20%20_axes%5B1%5D.set_xlim(0%2C%20224)%3B%20_axes%5B1%5D.set_ylim(224%2C%200)%0A%20%20%20%20_axes%5B1%5D.set_title(f%22p(%7BCATS%5B_cls%5D%7D)%20with%20the%20patch%20centred%20here%22%2C%20loc%3D%22left%22)%0A%20%20%20%20for%20_ax%20in%20_axes%3A%20_ax.set_axis_off()%0A%20%20%20%20_fig.colorbar(_im%2C%20ax%3D_axes%5B1%5D%2C%20shrink%3D0.8)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%205.%20Feature%20visualization%3A%20what%20does%20a%20unit%20want%20to%20see%3F%0A%0A%20%20%20%20Start%20from%20noise%20and%20change%20the%20**input%20image**%20by%20gradient%20ascent%20to%20maximize%20one%20channel%0A%20%20%20%20(or%20one%20class%20score%20in%20%60fc8%60).%20The%20weights%20stay%20fixed%3A%20this%20is%20backpropagation%20all%20the%20way%20to%20the%0A%20%20%20%20pixels.%20Random%20shifts%20and%20a%20little%20blurring%20keep%20the%20picture%20from%20turning%20into%20high-frequency%20noise.%0A%20%20%20%20Deeper%20units%20prefer%20textures%2C%20patterns%20and%20object%20parts.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(CATS%2C%20mo)%3A%0A%20%20%20%20vis_layer%20%3D%20mo.ui.dropdown(%5B%22conv1%22%2C%20%22conv2%22%2C%20%22conv3%22%2C%20%22conv4%22%2C%20%22conv5%22%2C%20%22fc8%22%5D%2C%20value%3D%22conv5%22%2C%20label%3D%22Layer%22)%0A%20%20%20%20vis_channel%20%3D%20mo.ui.number(start%3D0%2C%20stop%3D999%2C%20value%3D174%2C%20label%3D%22Channel%20%2F%20class%20index%22)%0A%20%20%20%20vis_steps%20%3D%20mo.ui.slider(32%2C%20512%2C%20step%3D32%2C%20value%3D224%2C%20label%3D%22Steps%22%2C%20show_value%3DTrue)%0A%20%20%20%20run_vis%20%3D%20mo.ui.run_button(label%3D%22Visualize%22)%0A%20%20%20%20mo.vstack(%5B%0A%20%20%20%20%20%20%20%20mo.hstack(%5Bvis_layer%2C%20vis_channel%2C%20vis_steps%2C%20run_vis%5D%2C%20justify%3D%22start%22%2C%20gap%3D2)%2C%0A%20%20%20%20%20%20%20%20mo.md(f%22Some%20%60fc8%60%20classes%3A%201%20%3D%20%7BCATS%5B1%5D%7D%2C%20207%20%3D%20%7BCATS%5B207%5D%7D%2C%20285%20%3D%20%7BCATS%5B285%5D%7D%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22409%20%3D%20%7BCATS%5B409%5D%7D%2C%20947%20%3D%20%7BCATS%5B947%5D%7D.%22)%2C%0A%20%20%20%20%5D)%0A%20%20%20%20return%20run_vis%2C%20vis_channel%2C%20vis_layer%2C%20vis_steps%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20AFTER%2C%0A%20%20%20%20MEAN%2C%0A%20%20%20%20STD%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20net%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20run_vis%2C%0A%20%20%20%20torch%2C%0A%20%20%20%20torchvision%2C%0A%20%20%20%20vis_channel%2C%0A%20%20%20%20vis_layer%2C%0A%20%20%20%20vis_steps%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20run_vis.value%2C%20mo.md(%22*Press%20Visualize%20(a%20few%20seconds%20per%20100%20steps).*%22))%0A%20%20%20%20_layer%2C%20_ch%20%3D%20vis_layer.value%2C%20int(vis_channel.value)%0A%20%20%20%20_limit%20%3D%20%7B%22conv1%22%3A%2064%2C%20%22conv2%22%3A%20192%2C%20%22conv3%22%3A%20384%2C%20%22conv4%22%3A%20256%2C%20%22conv5%22%3A%20256%2C%20%22fc8%22%3A%201000%7D%5B_layer%5D%0A%20%20%20%20mo.stop(_ch%20%3E%3D%20_limit%2C%20mo.md(f%22**%7B_layer%7D**%20has%20only%20%7B_limit%7D%20channels.%22))%0A%20%20%20%20with%20torch.enable_grad()%3A%0A%20%20%20%20%20%20%20%20_g%20%3D%20torch.Generator().manual_seed(0)%0A%20%20%20%20%20%20%20%20_x%20%3D%20(torch.randn(1%2C%203%2C%20240%2C%20240%2C%20generator%3D_g)%20*%200.1).requires_grad_(True)%0A%20%20%20%20%20%20%20%20_opt%20%3D%20torch.optim.Adam(%5B_x%5D%2C%20lr%3D0.05)%0A%20%20%20%20%20%20%20%20_blur%20%3D%20torchvision.transforms.GaussianBlur(3%2C%20sigma%3D0.6)%0A%20%20%20%20%20%20%20%20for%20_s%20in%20mo.status.progress_bar(range(vis_steps.value)%2C%20title%3D%22gradient%20ascent%20on%20the%20input%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_dx%2C%20_dy%20%3D%20torch.randint(0%2C%2016%2C%20(2%2C)%2C%20generator%3D_g).tolist()%0A%20%20%20%20%20%20%20%20%20%20%20%20_crop%20%3D%20_x%5B%3A%2C%20%3A%2C%20_dy%3A_dy%20%2B%20224%2C%20_dx%3A_dx%20%2B%20224%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_layer%20%3D%3D%20%22fc8%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_out%20%3D%20net(_crop)%5B0%2C%20_ch%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_a%20%3D%20net.features%5B%3AAFTER%5B_layer%5D%5D(_crop)%5B0%2C%20_ch%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_h%2C%20_w%20%3D%20_a.shape%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_out%20%3D%20_a.mean()%20if%20_layer%20in%20(%22conv1%22%2C%20%22conv2%22)%20else%20_a%5B_h%20%2F%2F%202%20-%202%3A_h%20%2F%2F%202%20%2B%203%2C%20_w%20%2F%2F%202%20-%202%3A_w%20%2F%2F%202%20%2B%203%5D.mean()%0A%20%20%20%20%20%20%20%20%20%20%20%20_loss%20%3D%20-_out%20%2B%201e-3%20*%20(_x%20**%202).mean()%0A%20%20%20%20%20%20%20%20%20%20%20%20_opt.zero_grad()%3B%20_loss.backward()%3B%20_opt.step()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_s%20%25%208%20%3D%3D%200%20and%20_s%20%3C%20vis_steps.value%20-%2016%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_x.data%20%3D%20_blur(_x.data)%0A%20%20%20%20_img%20%3D%20_x.detach()%5B0%2C%20%3A%2C%208%3A232%2C%208%3A232%5D%20*%20STD%20%2B%20MEAN%0A%20%20%20%20_lo%2C%20_hi%20%3D%20torch.quantile(_img%2C%200.01)%2C%20torch.quantile(_img%2C%200.99)%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(4.2%2C%204.2))%0A%20%20%20%20_ax.imshow(((_img%20-%20_lo)%20%2F%20(_hi%20-%20_lo)).clamp(0%2C%201).permute(1%2C%202%2C%200).numpy())%0A%20%20%20%20_ax.set_title(f%22%7B_layer%7D%2C%20%7B'class'%20if%20_layer%20%3D%3D%20'fc8'%20else%20'channel'%7D%20%7B_ch%7D%22%2C%20loc%3D%22left%22)%3B%20_ax.set_axis_off()%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%206.%20The%20embedding%20space%0A%0A%20%20%20%20Stop%20one%20layer%20before%20the%20classifier%20and%20keep%20the%204096%20numbers%20of%20%60fc7%60.%20Every%20image%20becomes%20a%20point%0A%20%20%20%20in%20a%204096-dimensional%20space.%20Flipped%20and%20cropped%20copies%20of%20an%20image%20have%20very%20different%20pixels%20but%0A%20%20%20%20land%20close%20together%3B%20similar%20concepts%20cluster.%20The%20AlexNet%20paper%20found%20that%20nearest%20neighbours%20in%0A%20%20%20%20this%20space%20show%20the%20same%20kind%20of%20object.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Image%2C%0A%20%20%20%20image_name%2C%0A%20%20%20%20net%2C%0A%20%20%20%20norm%2C%0A%20%20%20%20np%2C%0A%20%20%20%20plt%2C%0A%20%20%20%20samples%2C%0A%20%20%20%20skd%2C%0A%20%20%20%20to_tensor%2C%0A%20%20%20%20torch%2C%0A%20%20%20%20torchvision%2C%0A%20%20%20%20x01%2C%0A)%3A%0A%20%20%20%20def%20embed(xs)%3A%0A%20%20%20%20%20%20%20%20_f%20%3D%20net.avgpool(net.features(torch.cat(%5Bnorm(_x)%20for%20_x%20in%20xs%5D))).flatten(1)%0A%20%20%20%20%20%20%20%20return%20net.classifier%5B%3A6%5D(_f)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20fc7%20after%20ReLU%3A%204096%20numbers%0A%0A%20%20%20%20_names%2C%20_xs%20%3D%20%5B%5D%2C%20%5B%5D%0A%20%20%20%20for%20_n%20in%20samples%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20to_tensor(Image.fromarray(getattr(skd%2C%20_n)()))%0A%20%20%20%20%20%20%20%20_crop%20%3D%20torchvision.transforms.functional.resized_crop(_x%2C%2030%2C%2020%2C%20160%2C%20160%2C%20%5B224%2C%20224%5D%2C%20antialias%3DTrue)%0A%20%20%20%20%20%20%20%20_xs%20%2B%3D%20%5B_x%2C%20torch.flip(_x%2C%20(2%2C))%2C%20_crop%5D%0A%20%20%20%20%20%20%20%20_names%20%2B%3D%20%5B_n%2C%20_n%20%2B%20%22%20(flip)%22%2C%20_n%20%2B%20%22%20(crop)%22%5D%0A%20%20%20%20_xs.append(x01)%3B%20_names.append(f%22YOUR%20IMAGE%3A%20%7Bimage_name%7D%22)%0A%20%20%20%20_X%20%3D%20torch.stack(_xs)%0A%0A%20%20%20%20def%20_cos(v)%3A%0A%20%20%20%20%20%20%20%20v%20%3D%20v%20-%20v.mean(0%2C%20keepdim%3DTrue)%0A%20%20%20%20%20%20%20%20v%20%3D%20v%20%2F%20v.norm(dim%3D1%2C%20keepdim%3DTrue)%0A%20%20%20%20%20%20%20%20return%20(v%20%40%20v.T).numpy()%0A%0A%20%20%20%20_pix%2C%20_emb%20%3D%20_cos(_X.flatten(1))%2C%20_cos(embed(_xs))%0A%20%20%20%20_fig%2C%20_axes%20%3D%20plt.subplots(1%2C%202%2C%20figsize%3D(12%2C%205.6))%0A%20%20%20%20for%20_ax%2C%20_M%2C%20_t%20in%20%5B(_axes%5B0%5D%2C%20_pix%2C%20%22raw%20pixels%22)%2C%20(_axes%5B1%5D%2C%20_emb%2C%20%22fc7%20embedding%22)%5D%3A%0A%20%20%20%20%20%20%20%20_ax.imshow(_M%2C%20cmap%3D%22RdBu_r%22%2C%20vmin%3D-1%2C%20vmax%3D1)%0A%20%20%20%20%20%20%20%20_ax.set_title(f%22cosine%20similarity%3A%20%7B_t%7D%22%2C%20loc%3D%22left%22)%0A%20%20%20%20%20%20%20%20_ax.set_xticks(range(len(_names))%2C%20_names%2C%20rotation%3D90%2C%20fontsize%3D6)%0A%20%20%20%20%20%20%20%20_ax.set_yticks(range(len(_names))%2C%20_names%2C%20fontsize%3D6)%0A%20%20%20%20_fig.tight_layout()%0A%20%20%20%20_order%20%3D%20%5Bi%20for%20i%20in%20np.argsort(-_emb%5B-1%5D)%20if%20i%20!%3D%20len(_names)%20-%201%5D%5B%3A3%5D%0A%20%20%20%20_near%20%3D%20%22%2C%20%22.join(f%22%7B_names%5Bi%5D%7D%20(%7B_emb%5B-1%2C%20i%5D%3A.2f%7D)%22%20for%20i%20in%20_order)%0A%20%20%20%20print(f%22Nearest%20neighbours%20of%20your%20image%20in%20the%20embedding%3A%20%7B_near%7D%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Exercises%0A%0A%20%20%20%201.%20Find%20a%20first-layer%20kernel%20that%20responds%20to%20a%20colour%20rather%20than%20an%20edge.%20Which%20images%20light%20up%20its%20map%3F%0A%20%20%20%202.%20Photograph%20a%20printed%20first-layer%20kernel%20(or%20draw%20its%20stripes)%20and%20upload%20the%20photo.%20Does%20its%20map%20light%20up%3F%0A%20%20%20%20%20%20%20What%20happens%20when%20you%20rotate%20the%20paper%20by%2090%C2%B0%3F%0A%20%20%20%203.%20Pick%20a%20conv5%20channel%20and%20find%2C%20among%20your%20own%20photos%2C%20the%20one%20that%20activates%20it%20most.%20Can%20you%20name%20the%20concept%3F%0A%20%20%20%204.%20Occlude%20the%20face%20in%20%60astronaut%60%20using%20the%20occlusion%20experiment.%20Does%20the%20prediction%20depend%20on%20the%20face%3F%0A%20%20%20%205.%20Why%20is%20it%20easy%20to%20visualize%20layer-1%20kernels%20as%20images%2C%20but%20not%20layer-2%20kernels%20(5%20%C3%97%205%20%C3%97%2064)%3F%0A%20%20%20%206.%20AlexNet%20has%20about%2061%20million%20parameters.%20Count%20how%20many%20belong%20to%20the%20convolutional%20layers%20and%20how%20many%0A%20%20%20%20%20%20%20to%20the%20three%20dense%20layers.%20Where%20is%20most%20of%20the%20memory%2C%20and%20where%20most%20of%20the%20computation%3F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
e5880e73c145db881f8ad3ccc70645c9