From e6101c5898b00e1af24ed2cba65bc04890a5085c Mon Sep 17 00:00:00 2001 From: whitekirin Date: Fri, 7 Nov 2025 21:03:13 +0800 Subject: [PATCH] My Xception model is finished, it is not using timm --- draw_tools/Grad_cam.py | 34 +- .../__pycache__/Grad_cam.cpython-313.pyc | Bin 8655 -> 10238 bytes .../Models/Xception_Model_Modification.py | 503 +++++++++++++----- ...ception_Model_Modification.cpython-313.pyc | Bin 10176 -> 11884 bytes .../__pycache__/pytorch_Model.cpython-313.pyc | Bin 2216 -> 2124 bytes experiments/Models/pytorch_Model.py | 9 +- .../Training/Xception_Identification_Test.py | 63 ++- ...eption_Identification_Test.cpython-313.pyc | Bin 25035 -> 25037 bytes .../Stomach_Config.cpython-313.pyc | Bin 4816 -> 4816 bytes 9 files changed, 438 insertions(+), 171 deletions(-) diff --git a/draw_tools/Grad_cam.py b/draw_tools/Grad_cam.py index fc57df0..f22288f 100644 --- a/draw_tools/Grad_cam.py +++ b/draw_tools/Grad_cam.py @@ -11,13 +11,15 @@ from Load_process.file_processing import Process_File class GradCAM: def __init__(self, model, target_layer): self.model = model - self.target_layer = target_layer + # 若為 DataParallel,取出真正的 backbone + self.backbone = model.module if isinstance(model, nn.DataParallel) else model + self.target_layer = self._resolve_target_layer(target_layer) self.activations = None self.gradients = None self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.model.to(self.device) # Ensure model is on the correct device - # Register hooks + # Register hooks on resolved module self.target_layer.register_forward_hook(self.save_activations) # Use full backward hook if available to avoid deprecation issues if hasattr(self.target_layer, "register_full_backward_hook"): @@ -25,6 +27,34 @@ class GradCAM: else: self.target_layer.register_backward_hook(self.save_gradients) + def _resolve_target_layer(self, target): + # 支援 nn.Module / nn.Parameter / 字串路徑 + if isinstance(target, nn.Module): + return target + if isinstance(target, torch.nn.Parameter): + # 先在 backbone 參數中找到該 Parameter 的名稱 + for name, param in self.backbone.named_parameters(): + if param is target: + # 去掉 .weight / .bias,取得父模組名稱 + module_name = name.rsplit('.', 1)[0] + # 先嘗試用 named_modules 快速匹配 + for mod_name, mod in self.backbone.named_modules(): + if mod_name == module_name: + return mod + # 回退為屬性遍歷 + obj = self.backbone + for attr in module_name.split('.'): + obj = getattr(obj, attr) + return obj + raise AttributeError("Target parameter not found in model parameters.") + if isinstance(target, str): + # 允許使用字串路徑指定層,例如 'conv4.pointwise' + obj = self.backbone + for attr in target.split('.'): + obj = getattr(obj, attr) + return obj + raise TypeError("target_layer must be nn.Module, nn.Parameter, or str") + def Processing_Main(self, Test_Dataloader, File_Path): File = Process_File() for batch_idx, (images, labels, File_Name, File_Classes) in enumerate(Test_Dataloader): diff --git a/draw_tools/__pycache__/Grad_cam.cpython-313.pyc b/draw_tools/__pycache__/Grad_cam.cpython-313.pyc index f7bb8dccdba28c235754703254708300e561c68f..0e0ee4e18b4b360be25694dd7016ff6617317a7c 100644 GIT binary patch delta 2735 zcmbVNU2Gf25#Bu>e~+YT@<{QYM^RRFk|kSiq&RM6*^&GcMY0@Ga_OptLP=+vF?p1i zWD&bb zdI1xA+Ro;Vv@7k<=R#T_&hu8;O}~m;V%Ir@-bNWu9_;APq^U8QpfNEK=wTZ0v>6|i zbs{u@=@C&BNAU!nKzZ|)1WlkZ7kw`3>*IQ`vBsp`)5P%7dNn45zSE?a}9rRLE zq@Qt3{>Sazv$eNX-y1c#AFCz*kCs47roE$n&0HwXDtXP3E9KNuIjhbn8mFq7b1+-Z zp3ahNKF_2Urc}u*nr%8eb8)(;Dw=ghSKFofzpSkS9Jxm6^n=Ojmqk!b6eip>-!a0_}w)j~%jQF_-S`oE<9 z0aK^1h<<8yMWa4+avq@yGclLSbPuChHX0F_1~;~g)xjs?G}o|@HUW!N-q`(1QKS!@ zwhm^&vt{8-X8ceF88(1{mJ%l+cw3NwB*QDOS|@mVi4*73xWPbXf|XjeP5Si|Fvz^v zaH?8In0bA>b;s0XQ$sV&H>@c5kqiVI8VyU^&C$(5Lu2$+(Feic|1%ht@JPc&+Po8l zY&oUjuDeh-!jg%u>>JlPBh4{>6_m0%7E+1Y`kBVCW}#W+(b z*;&%BqAvvh;<@Y7E4k%dO=znMZFOI0VdRd!s;pdCzEF$rug3S+gzl=)y_ra@yuAGK zd@a#eP4wMP^e+jEeBBrPQU7Lh>-!xyJ3g3M?cQkaSc*EL%`lKMPypq^^IK6KBF+E3uW+fXF2(z)EZI8c{5YEpMq>RwIVmU^%8cj9|) z%xuK>ziYZ@LdhpLBk{L}?uC$a<_P{r82OUx$*~P@dfk~e!kwuJ%~hd!(;IlFbE$J- zpdO5`IG3F_(zk>1B7Y|kyEd~CXnPBch1xfLfrX(v?xywNsSWq&x^0xCXjde(cGH~U zIMPc0X?x(7-1Z@s==1hYd}!?r`)-U=^oHZC2kv^A*UL#*{~_uW zLKX=&Mrel+i=1J@5(wC>7fG)4E%&|GzrcTP3o@rS93lFWFyPICI<)k*AzBq$4J$GF zFCl`@(vUNOQ)^E-dpJugsQ1yb``8|!Eja-I|4wp}fo8v=kmA&NMglSfi_g+OxqH|F z#9i%4cIhB;7T}u{z^f^$2FcP`HE&LWM3ruiH(ry8{Uuy zx`A8-fHV-1{=&Q8IR6~|n>U6pQNi~qi|BX0-*A@8pwdd01MM!thMKvOQ_Ba*D|9_@ zAhc~+v(71`z&cRR3b{%nO(C!D2ac|pbA{}Ag&d{Fo0<(z!&GgG;@8%G*d*WsDW)S^ zjHAF^U~oYXj$PP@_yC?~AY;-G9~b>~u(u@%%g}}7+W>Iykr==;0CNDtG#HBQ1^Y(I z;Xg(I*v|x&IvIQ)-RC^!A$-3jY(9cI-&VMkhhemi9 z9RoNH@F?Sq!x>xysW1#U0&t3c8gEJJeFPcPc%Y@mpUdSHG6o81fN^R`#D#Cb&>$$? zm*@;iY_2&;Mb)`HHIprnRkn0}}DH1ZKzzz;+ol+t-b2_b|CdUrlyLhB(}I4*}lK@HXs!AbN2I>l^+9 D>y~re delta 1448 zcmY*ZZ)jUp6o2>Se_oR2@A79!)1+zIR9l<6KdsJ8JG#O^HjR~tWATx`WzQuq<-DX= zVJL_)ag5D_F#RTjfgfaZ88W{JBBQ7X5g;6QxbTpzN$y;y;UzLO=roE zi>xr8kR|CosTORJ2eE2nEjE;^(yG+rjKLB+8)a zIDtQ>qIlgM!yjcozMGEVm3Y*?Dm@#;kSl_>WsmY=eCTu)FQj95)Rq*)g>gYl4T*Tw z<`4&;$Z@u#{mVA%9Heo9A;vQJP4I@xsIM@?!ScMSK}VRvBcz-|TWl}SU@ET^z;+3q%aFTww)=F*G$p1GTGF@PpVLe*2kSU$YgueTy3XTuFv;;=4|3+WMN_ z2GT;FL-Vn7b9c^fE>}wO7Ihm`4kf?H9H?ZxtnVZ;dqg>QBDXa*<}Kff+A~dEHI`aE zD7i#w;Tf`_x6jKc1MFNl^PNAM_0IQ0fh}4VSp;jsE3{ zgDft378OZZ?rsMfr)CWU-o`(R6Tvm|L=O#UlK2SCPL@~?Ym@s5B3E()ZxTG{k>x%x g_-m-Zhj@Lmyt~EN)UOiZ_Hmn=#qLMLtj2`Fzh(DIWdHyG diff --git a/experiments/Models/Xception_Model_Modification.py b/experiments/Models/Xception_Model_Modification.py index af15832..9873b03 100644 --- a/experiments/Models/Xception_Model_Modification.py +++ b/experiments/Models/Xception_Model_Modification.py @@ -1,152 +1,379 @@ +""" +Ported to pytorch thanks to [tstandley](https://github.com/tstandley/Xception-PyTorch) + +@author: tstandley +Adapted by cadene + +Creates an Xception Model as defined in: + +Francois Chollet +Xception: Deep Learning with Depthwise Separable Convolutions +https://arxiv.org/pdf/1610.02357.pdf + +This weights ported from the Keras implementation. Achieves the following performance on the validation set: + +Loss:0.9173 Prec@1:78.892 Prec@5:94.292 + +REMEMBER to set your image size to 3x299x299 for both test and validation + +normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5], + std=[0.5, 0.5, 0.5]) + +The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299 +""" import torch.nn as nn import torch.nn.functional as F -import torch - from utils.Stomach_Config import Model_Config +from einops import rearrange + +from timm.layers import create_classifier + class SeparableConv2d(nn.Module): - def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True): - super(SeparableConv2d, self).__init__() - self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, stride=stride, - padding=padding, groups=in_channels, bias=bias) - self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, - padding=0, bias=bias) - + def __init__( + self, + in_channels: int, + out_channels: int, + kernel_size: int = 1, + stride: int = 1, + padding: int = 0, + dilation: int = 1, + device=None, + dtype=None, + ): + dd = {'device': device, 'dtype': dtype} + super().__init__() + + self.conv1 = nn.Conv2d( + in_channels, + in_channels, + kernel_size, + stride, + padding, + dilation, + groups=in_channels, + bias=False, + **dd, + ) + self.pointwise = nn.Conv2d(in_channels, out_channels, 1, 1, 0, 1, 1, bias=False, **dd) + def forward(self, x): - x = self.depthwise(x) + x = self.conv1(x) x = self.pointwise(x) return x -class EntryFlow(nn.Module): - def __init__(self, in_channels=3): - super(EntryFlow, self).__init__() - self.conv1 = nn.Conv2d(in_channels, 32, 3, stride=2, padding=1, bias=False, dilation = 2) - self.bn1 = nn.BatchNorm2d(32) - self.conv2 = nn.Conv2d(32, 64, 3, padding=1, bias=False, dilation = 2) - self.bn2 = nn.BatchNorm2d(64) - - self.conv3_residual = nn.Sequential( - SeparableConv2d(64, 128, 3, padding=1), - nn.BatchNorm2d(128), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(128, 128, 3, padding=1), - nn.BatchNorm2d(128), - nn.MaxPool2d(3, stride=2, padding=1) - ) - self.conv3_shortcut = nn.Conv2d(64, 128, 1, stride=2, bias=False) - self.bn3 = nn.BatchNorm2d(128) - - self.conv4_residual = nn.Sequential( - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(128, 256, 3, padding=1), - nn.BatchNorm2d(256), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(256, 256, 3, padding=1), - nn.BatchNorm2d(256), - nn.MaxPool2d(3, stride=2, padding=1) - ) - self.conv4_shortcut = nn.Conv2d(128, 256, 1, stride=2, bias=False) - self.bn4 = nn.BatchNorm2d(256) - - self.conv5_residual = nn.Sequential( - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(256, 728, 3, padding=1), - nn.BatchNorm2d(728), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(728, 728, 3, padding=1), - nn.BatchNorm2d(728), - nn.MaxPool2d(3, stride=2, padding=1) - ) - self.conv5_shortcut = nn.Conv2d(256, 728, 1, stride=2, bias=False) - self.bn5 = nn.BatchNorm2d(728) - - def forward(self, x): - x = F.relu(self.bn1(self.conv1(x))) - x = F.relu(self.bn2(self.conv2(x))) - - residual = self.conv3_residual(x) - shortcut = self.conv3_shortcut(x) - x = F.relu(self.bn3(residual + shortcut)) - - residual = self.conv4_residual(x) - shortcut = self.conv4_shortcut(x) - x = F.relu(self.bn4(residual + shortcut)) - - residual = self.conv5_residual(x) - shortcut = self.conv5_shortcut(x) - x = F.relu(self.bn5(residual + shortcut)) + +class Block(nn.Module): + def __init__( + self, + in_channels: int, + out_channels: int, + reps: int, + strides: int = 1, + start_with_relu: bool = True, + grow_first: bool = True, + device=None, + dtype=None, + ): + dd = {'device': device, 'dtype': dtype} + super().__init__() + + if out_channels != in_channels or strides != 1: + self.skip = nn.Conv2d(in_channels, out_channels, 1, stride=strides, bias=False, **dd) + self.skipbn = nn.BatchNorm2d(out_channels, **dd) + else: + self.skip = None + + rep = [] + for i in range(reps): + if grow_first: + inc = in_channels if i == 0 else out_channels + outc = out_channels + else: + inc = in_channels + outc = in_channels if i < (reps - 1) else out_channels + rep.append(nn.ReLU(inplace=True)) + rep.append(SeparableConv2d(inc, outc, 3, stride=1, padding=1, **dd)) + rep.append(nn.BatchNorm2d(outc, **dd)) + + if not start_with_relu: + rep = rep[1:] + else: + rep[0] = nn.ReLU(inplace=False) + + if strides != 1: + rep.append(nn.MaxPool2d(3, strides, 1)) + self.rep = nn.Sequential(*rep) + + def forward(self, inp): + x = self.rep(inp) + + if self.skip is not None: + skip = self.skip(inp) + skip = self.skipbn(skip) + else: + skip = inp + + x += skip return x -class MiddleFlow(nn.Module): - def __init__(self): - super(MiddleFlow, self).__init__() - self.conv_residual = nn.Sequential( - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(728, 728, 3, padding=1), - nn.BatchNorm2d(728), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(728, 728, 3, padding=1), - nn.BatchNorm2d(728), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(728, 728, 3, padding=1), - nn.BatchNorm2d(728) - ) - - def forward(self, x): - return self.conv_residual(x) + x - -class ExitFlow(nn.Module): - def __init__(self): - super(ExitFlow, self).__init__() - self.conv1_residual = nn.Sequential( - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(728, 1024, 3, padding=1), - nn.BatchNorm2d(1024), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(1024, 1024, 3, padding=1), - nn.BatchNorm2d(1024), - nn.MaxPool2d(3, stride=2, padding=1) - ) - self.conv1_shortcut = nn.Conv2d(728, 1024, 1, stride=2, bias=False) - self.bn1 = nn.BatchNorm2d(1024) - - self.conv2 = nn.Sequential( - SeparableConv2d(1024, 1536, 3, padding=1), - nn.BatchNorm2d(1536), - nn.ReLU(inplace=False), # 修改這裡 - SeparableConv2d(1536, 2048, 3, padding=1), - nn.BatchNorm2d(2048), - nn.ReLU(inplace=False) # 修改這裡 - ) - self.avgpool = nn.AdaptiveAvgPool1d(Model_Config["GPA Output Nodes"]) - self.Hidden = nn.Linear(Model_Config["GPA Output Nodes"], Model_Config["Linear Hidden Nodes"]) - self.fc = nn.Linear(Model_Config["Linear Hidden Nodes"], Model_Config["Output Linear Nodes"]) - self.dropout = nn.Dropout(Model_Config["Dropout Rate"]) - - def forward(self, x): - residual = self.conv1_residual(x) - shortcut = self.conv1_shortcut(x) - x = F.relu(self.bn1(residual + shortcut)) - - x = self.conv2(x) - x = x.view(x.size(0), -1) - x = self.avgpool(x) - x = F.relu(self.Hidden(x)) - x = self.dropout(x) - x = self.fc(x) - return x class Xception(nn.Module): - def __init__(self): - super(Xception, self).__init__() - self.entry_flow = EntryFlow(in_channels=3) # 默认输入通道为3 - self.middle_flow = nn.Sequential(*[MiddleFlow() for _ in range(8)]) - self.exit_flow = ExitFlow() - - def forward(self, x): - # 正常的前向傳播 - x = self.entry_flow(x) - x = self.middle_flow(x) - x = self.exit_flow(x) + """ + Xception optimized for the ImageNet dataset, as specified in + https://arxiv.org/pdf/1610.02357.pdf + """ + + def __init__( + self, + num_classes: int = 1000, + in_chans: int = 3, + drop_rate: float = 0., + global_pool: str = 'avg', + device=None, + dtype=None, + ): + """ Constructor + Args: + num_classes: number of classes + """ + super().__init__() + dd = {'device': device, 'dtype': dtype} + self.drop_rate = drop_rate + self.global_pool = global_pool + self.num_classes = num_classes + self.num_features = self.head_hidden_size = 2048 + + self.conv1 = nn.Conv2d(in_chans, 32, 3, 2, 0, bias=False, **dd) + self.bn1 = nn.BatchNorm2d(32, **dd) + self.act1 = nn.ReLU(inplace=True) + + self.conv2 = nn.Conv2d(32, 64, 3, bias=False, **dd) + self.bn2 = nn.BatchNorm2d(64, **dd) + self.act2 = nn.ReLU(inplace=True) + + self.block1 = Block(64, 128, 2, 2, start_with_relu=False, **dd) + self.block2 = Block(128, 256, 2, 2, **dd) + self.block3 = Block(256, 728, 2, 2, **dd) + + self.block4 = Block(728, 728, 3, 1, **dd) + self.block5 = Block(728, 728, 3, 1, **dd) + self.block6 = Block(728, 728, 3, 1, **dd) + self.block7 = Block(728, 728, 3, 1, **dd) + + self.block8 = Block(728, 728, 3, 1, **dd) + self.block9 = Block(728, 728, 3, 1, **dd) + self.block10 = Block(728, 728, 3, 1, **dd) + self.block11 = Block(728, 728, 3, 1, **dd) + + self.block12 = Block(728, 1024, 2, 2, grow_first=False, **dd) + + self.conv3 = SeparableConv2d(1024, 1536, 3, 1, 1, **dd) + self.bn3 = nn.BatchNorm2d(1536, **dd) + self.act3 = nn.ReLU(inplace=True) + + self.conv4 = SeparableConv2d(1536, self.num_features, 3, 1, 1, **dd) + self.bn4 = nn.BatchNorm2d(self.num_features, **dd) + self.act4 = nn.ReLU(inplace=True) + self.feature_info = [ + dict(num_chs=64, reduction=2, module='act2'), + dict(num_chs=128, reduction=4, module='block2.rep.0'), + dict(num_chs=256, reduction=8, module='block3.rep.0'), + dict(num_chs=728, reduction=16, module='block12.rep.0'), + dict(num_chs=2048, reduction=32, module='act4'), + ] + + self.global_pool, self.fc = create_classifier(self.num_features, self.num_classes, pool_type=global_pool, **dd) + self.hidden_layer = nn.Linear(2048, Model_Config["Linear Hidden Nodes"]) # 隱藏層,輸入大小取決於 Xception 的輸出大小 + self.output_layer = nn.Linear(Model_Config["Linear Hidden Nodes"], Model_Config["Output Linear Nodes"]) # 輸出層,依據分類數目設定 - return x \ No newline at end of file + # 激活函數與 dropout + self.relu = nn.ReLU() + self.dropout = nn.Dropout(Model_Config["Dropout Rate"]) + + # #------- init weights -------- + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def reset_classifier(self, num_classes: int, global_pool: str = 'avg'): + self.num_classes = num_classes + self.global_pool, self.fc = create_classifier(self.num_features, self.num_classes, pool_type=global_pool) + + def forward_features(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.act1(x) + + x = self.conv2(x) + x = self.bn2(x) + x = self.act2(x) + + x = self.block1(x) + x = self.block2(x) + x = self.block3(x) + x = self.block4(x) + x = self.block5(x) + x = self.block6(x) + x = self.block7(x) + x = self.block8(x) + x = self.block9(x) + x = self.block10(x) + x = self.block11(x) + x = self.block12(x) + + x = self.conv3(x) + x = self.bn3(x) + x = self.act3(x) + + x = self.conv4(x) + x = self.bn4(x) + x = self.act4(x) + return x + + def forward_head(self, x): + x = self.global_pool(x) + return x + + def forward(self, x): + x = self.forward_features(x) + x = self.forward_head(x) + + x = self.dropout(x) # Dropout + x = self.hidden_layer(x) + x = self.relu(x) # 隱藏層 + ReLU + x = self.output_layer(x) # 輸出層 + return x + +# class Residual(nn.Module): +# def __init__(self, fn): +# super().__init__() +# self.fn = fn + +# def forward(self, x, **kwargs): +# return self.fn(x, **kwargs) + x + +# class PreNorm(nn.Module): +# def __init__(self, dim, fn): +# super().__init__() +# self.norm = nn.LayerNorm(dim) +# self.fn = fn + +# def forward(self, x, **kwargs): +# return self.fn(self.norm(x), **kwargs) + +# class FeedForward(nn.Module): +# def __init__(self, dim, hidden_dim, dropout=0.0): +# super().__init__() +# self.net = nn.Sequential( +# nn.Linear(dim, hidden_dim), +# nn.GELU(), +# nn.Dropout(dropout), +# nn.Linear(hidden_dim, dim), +# nn.Dropout(dropout) +# ) + +# def forward(self, x): +# return self.net(x) + +# class Attention(nn.Module): +# def __init__(self, dim, heads=8, dim_head=64, dropout=0.0): +# super().__init__() +# inner_dim = dim_head * heads +# self.heads = heads +# self.scale = dim_head ** -0.5 + +# self.to_qkv = nn.Linear(dim, inner_dim * 3, bias=False) +# self.to_out = nn.Sequential( +# nn.Linear(inner_dim, dim), +# nn.Dropout(dropout) +# ) + +# def forward(self, x, mask=None): +# b, n, _, h = *x.shape, self.heads +# qkv = self.to_qkv(x).chunk(3, dim=-1) +# q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h=h), qkv) + +# dots = torch.einsum('bhid,bhjd->bhij', q, k) * self.scale + +# if mask is not None: +# mask = F.pad(mask.flatten(1), (1, 0), value=True) +# assert mask.shape[-1] == dots.shape[-1], 'mask has incorrect dimensions' +# mask = mask[:, None, :] * mask[:, :, None] +# dots.masked_fill_(~mask, float('-inf')) +# del mask + +# attn = dots.softmax(dim=-1) + +# out = torch.einsum('bhij,bhjd->bhid', attn, v) +# out = rearrange(out, 'b h n d -> b n (h d)') +# out = self.to_out(out) +# return out + +# class Transformer(nn.Module): +# def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout): +# super().__init__() +# self.layers = nn.ModuleList([]) +# for _ in range(depth): +# self.layers.append(nn.ModuleList([ +# Residual(PreNorm(dim, Attention(dim, heads=heads, dim_head=dim_head, dropout=dropout))), +# Residual(PreNorm(dim, FeedForward(dim, mlp_dim, dropout=dropout))) +# ])) + +# def forward(self, x, mask=None): +# for attn, ff in self.layers: +# x = attn(x, mask=mask) +# x = ff(x) +# return x + +# class ViT(nn.Module): +# def __init__(self, *, image_size, patch_size, num_classes, dim, depth, heads, mlp_dim, pool='cls', channels=3, dim_head=64, dropout=0., emb_dropout=0.): +# super().__init__() +# image_height, image_width = image_size if isinstance(image_size, tuple) else (image_size, image_size) +# patch_height, patch_width = patch_size if isinstance(patch_size, tuple) else (patch_size, patch_size) + +# assert image_height % patch_height == 0 and image_width % patch_width == 0, 'Image dimensions must be divisible by the patch size.' + +# num_patches = (image_height // patch_height) * (image_width // patch_width) +# patch_dim = channels * patch_height * patch_width +# assert pool in {'cls', 'mean'}, 'pool type must be either cls (class token) or mean (mean pooling)' + +# self.to_patch_embedding = nn.Sequential( +# nn.Conv2d(channels, dim, kernel_size=(patch_height, patch_width), stride=(patch_height, patch_width)), +# nn.Flatten(2), +# nn.LayerNorm(dim), +# ) + +# self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, dim)) +# self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) +# self.dropout = nn.Dropout(emb_dropout) + +# self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout) + +# self.pool = pool +# self.to_latent = nn.Identity() + +# self.mlp_head = nn.Sequential( +# nn.LayerNorm(dim), +# nn.Linear(dim, num_classes) +# ) + +# def forward(self, img, mask=None): +# x = self.to_patch_embedding(img) +# x = x.permute(0, 2, 1) +# b, n, _ = x.shape + +# cls_tokens = self.cls_token.expand(b, -1, -1) +# x = torch.cat((cls_tokens, x), dim=1) +# x += self.pos_embedding[:, :(n + 1)] +# x = self.dropout(x) + +# x = self.transformer(x, mask) + +# x = x.mean(dim=1) if self.pool == 'mean' else x[:, 0] + +# x = self.to_latent(x) +# return self.mlp_head(x) diff --git a/experiments/Models/__pycache__/Xception_Model_Modification.cpython-313.pyc b/experiments/Models/__pycache__/Xception_Model_Modification.cpython-313.pyc index b2a6649f7f545fdd4f9a2cd569046b0fcb4bbc2c..ca963917a49b59746d1a5504d0501f0cea07d4c5 100644 GIT binary patch literal 11884 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 literal 10176 zcmdrSTWnLwb*`V+$xWQZguEa)Aq$w-l8~?)SOVb@*bofFc*TlP*Rh@CQpZl_I=m`X z{Im*>6_3>_F1r$ux*s5|s(kWSTJgb0KjNASbepQHcKeaPZIcz-ulAg|&s@yL%_6PZ ziE=!1=ggclXJ*dp-i5NV5&~u4?;WC4L&)E-p%tfES>QQBJ|Q6z;*ODCj&gpbZtLYF zo1gUBsY89@q)x!H9dq@%soPI#NizxA>q*El!1Y&X(;B}WcBM`|4ATjiu4OPw7^WLA z`DHLm8Kws?OP0YD7-lJ83d>-Y4Re9Ad1N{m;AG)=I-W>I4yIE>;&9AZ79r}o$U+-D z{SnA+fKV<(s4c`%d&n6k?Oe!KPtNn_IqETV$cm+TEC#-cPjm`uR* z7uw?UZkQ>CKr6U!NN3?Q0A1WC$lAtM&mLy(D$Sx^E#dtz? zk458gF*Pi^hG}|YOp+agVpN)k;|8(<5O7drlX?)~f~kN{-Lg}f7)wx!{K6`;I&kuGCQV}_1Bpw( zt2mlSWuyUiWTb&JG2l*2ry|M`0w@lNu_!*;K6aUUab2~RBd}dtC$b>*0QmMQnd8fD zrn8wGzwH_S_FP@V{knT~(|evaya?=g+WrqaSAU9|blfceO7Cf!Jso}#*gUfeJKvdf zd{n*wGm)5nWT1h^iXE+9sC+`gq#t+0Qo>w^`ZUD>hIZslSW7Ut7V?k_KD5y)z@R<= zP+tWlFflZ4=q8T{QgA{S3@zR>Y{$jNRoHI|IV5@5IW zd9*q*I8VUD&A$MGff|ZBgKkBDI)LJprg&OqXAJz=R=M;*G!q*Mrs-%~T(%FUT9uAA zthdP}p~UzE_)B6msrYz~{zP9`_8gC1I+;!@+rS%{X)ln0( zt8)CtXMA9;x@PLbyB}tM`ryC}_o(Udsi)!D$d7Z?QSjAD=6uytU3a^toAbW6pv`N@ zbh>SNe5UEqTTi=l)xkoTUp4ygkKP-d6B@DyrtQArYRd|-QU zaHjH6>*J1G-9S8%>gkdj&SKUM!Gn`q!4H_CJ+ArfsH*f~Fi5_yK ztLK6k#c-rMipC7z!BL%orPVAPHE7R`UlT?#9ASK9DX--S;yAhnkON+s>yaHak({7= zp-uN7*oUAC!9fIv5FAE;;VM0X;3$Ik5nyylj{$h-P}J)>sLQ;r(|Ju%OAhG3m|Ib| zenhJ@)U6s9B5i2_07S(?*{z=IJ-6GZ-o5i~_R#&_U-nLqe|kLc+ng7+OmfR~f9b1v z?%R;_ZI~X<`vQ~v3rlX?Izg{$zwXhu? zSuNd0^9{Z^88BZFu^of>x8;hVGB0U|1TmK{%#s zFbH~-0N1r7=+i?dV*(g!*L2SR6O|6tDu6SpJG$VEx`REm16EIWBWOl|LZj^f0v^Rr z4C4dCPu!2qZUku1=z9RllpuGsl(OOD_4 zjNd%BcHRAR_s$jX85QTJERVI|D`^C;>W_RqyE02mKOSdxr11(apMVQBpX$4Mi3F>XUL~{eb2p3Id9W+Q{LM$J)ZM!n&mesS9$<23hM>7 zeF*SsYU!+RY=X1oZz_?iGv=0K!3s22Fcm&6QH3WGSYSt;PfV-j2h_yZ~h%s{z9 z?jn?eW5r6r!SY-yr-BO9Qb0*LLp*TqflQE*Z_ph-lj71NU1JJValn%cX5d04EEA+V zho+H*m7^{PP$Ysjr)iX~T(mySJed@+BUDE^|>essPp z1=f$Zot01-Dou?d$WY&1(;TRVE#=iYOmmjAIZ@FPRW?CR7b0xkWhR)bmipA?syblBV9;zUl_)`NNb#;&Xe8I3&Ug3mR$;KvP=yHWW3tlm;!U+R%}#Bgb!e#&4R_@($Kme-$Py zazeY7U1-k>eygQDG~M!mn`zAn9agL*If#O>{^^<4N2eZ#bB)KA#QH6H-$s^$fHcdw zyI|WJvahFNw$#gGK`vx9SnZo7kP4}-e_pfY4>eo9=$q|4mfPBwuQ?7q!rbcGDez=Er zo4RuM%I8}j{4Cepm9Nr0}9zXR4v59^#Z}YX-(YO<=3QZ9WxJ__SAkE zEnT-1!ekf)0(&zzVF;ZA_8@z)J^ybg0f7#}WEAfe4I(&!fJM{nemgFRiHq>Y8eW;x z1a=K0IFDci0rR(Tjh5KBLchAIi}y3Yk$wdLTs%uKYi)l=a0@S6d$0B09=~xM-?c)7 zeXZwq>(s70yRuCmcV-9kLX+|iw(lC`4sV<=$Ju-C?8%OQ+?5xaEhzZT_QYV$zm%Bz)!!troD9`duvCgaTr-j{D76>cA>@B@BUf+9%$Imt9y6DFhUtM z1aI7f%;G{$0msav;|50_y*^42Ab0E?fm{N)etJ1F1TUqPR|Wf_OLo#|YB)i|ST7xA z82|+Zw@mgV!1-rwH9IeJk=NzsE45A0ZP`tjLc*Z%6?4a}8_n@4dJ8 zN%iCLC$;&_y}zq{)cwWoU%&U;+T7;e*#>5GYUk>jKCQ>^DE{?NJK1uKlh7ym&8qIL zeBqET3Ef4g>|(yDD4g-tbGxWywQQZ8UI4oE5`xPJ8Uef-9#-grQZ>h2MB54AD)|zw z>WOP7vfX*1k=^3w!kV10CVL8AEGW0y_!Q$y<0h+=8Bs>Q;Du!e0s-C{BZhQ1TV4t- zysrS1`-(_`a+zn})@)Cu*nyFKT66o*L@I{g(ZEZg5~I%atL$W0@~Vl9n3T4M)X#Me zvJbcv*U1H+;=orRO6FlJkYdM=GJS%S9}{E`F8Xt5V)!Wy0r=X^aonFt z^ct(KtGcPX}0}!aK=gs^yk@pwV2gb>qjCqsiGm0q%@quJeK^|kY08AuEXfi*O z%H;Qq+|gh&K;lTUVlZ_GT8SZ)5urAijTIX0t!Hk2ANtUKDnITnvEO8RGPelU57^o z$Sh_A5)MEMKCnv*@UuEFepg~=75u;eB#PuGOLIsu@=P}4&=Un2UL*@7ZgJS;=BJeA eq}mnfO|ImS5td{WoKQ5qa$@CI1|YKtq!0kjutJdcGcPX}0}xDq&XKu$BJVFIDW=JsjCnlKd>~N}2ojilkV%BmbaDZstXK{w zM38|2Nr4DZf&Aoii~^$ESY#zYvaGDEK&i=`OwyvfxYSIJU{Vl;TZ?4A9LNC*rciyM z3^@W=j8Fn9(q|N!{1NDbm&}uSnKK!MCzmtZ2r}j6-Qw^}NzE(CEUCQ3l$JdC2y?nP z(=C?b)SR?iobmC=If=!^@$tn>AQuL(_%iZLp2wohxPS5?7Gv={vhwqzXGPDB?O^HW z@8rM2A@zlgK|yIUC#$URlAH_1t{2tZ&hT6a&ARB3eOV@FvN3BidSvN2<1aVJZ zz$$OasKTJh=%>k6#1AyTNCZSkg9tGYAqgVHfrKVgkqnT!#aID$hk`p@z;J^{px?jKe}>~_9=Q%iAn!Vl!bKj11%j7(l!5%oyV>j&6@V&XR)K8++XuD^ zWJ{6cWNCJ5HXaaDd2$T9j=3z5S