From 617327819dd19d631d3a19be96d567658648b9b2 Mon Sep 17 00:00:00 2001 From: HGKim-andb <60685870+HGKim-andb@users.noreply.github.com> Date: Fri, 2 May 2025 21:58:36 +0900 Subject: [PATCH 1/2] Add files via upload --- src/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 129 bytes src/__pycache__/config.cpython-310.pyc | Bin 0 -> 1075 bytes src/__pycache__/config0.cpython-310.pyc | Bin 0 -> 1034 bytes src/__pycache__/config1.cpython-310.pyc | Bin 0 -> 1018 bytes src/__pycache__/config2.cpython-310.pyc | Bin 0 -> 1019 bytes src/__pycache__/dataset.cpython-310.pyc | Bin 0 -> 3246 bytes src/__pycache__/metric.cpython-310.pyc | Bin 0 -> 2152 bytes src/__pycache__/network.cpython-310.pyc | Bin 0 -> 7731 bytes src/__pycache__/util.cpython-310.pyc | Bin 0 -> 803 bytes src/config.py | 15 +- src/metric.py | 49 ++++- src/network.py | 230 ++++++++++++++++++++++- 12 files changed, 273 insertions(+), 21 deletions(-) create mode 100644 src/__pycache__/__init__.cpython-310.pyc create mode 100644 src/__pycache__/config.cpython-310.pyc create mode 100644 src/__pycache__/config0.cpython-310.pyc create mode 100644 src/__pycache__/config1.cpython-310.pyc create mode 100644 src/__pycache__/config2.cpython-310.pyc create mode 100644 src/__pycache__/dataset.cpython-310.pyc create mode 100644 src/__pycache__/metric.cpython-310.pyc create mode 100644 src/__pycache__/network.cpython-310.pyc create mode 100644 src/__pycache__/util.cpython-310.pyc diff --git a/src/__pycache__/__init__.cpython-310.pyc b/src/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..543bf3bdec065923488ebd0223269dc0bed5fcf0 GIT binary patch literal 129 zcmd1j<>g`k0;xid3=sVoL?8o3AjbiSi&=m~3PUi1CZpd2KczG$)efY)mywk+6UK`s<)wx)kj&TF~!rmp? z6&JX0L2w1q3JRwRaph2MNQhRX9Jrv45JKf-2?-&PkPt}xUaNxNn(v?Q_y3%~Uo0vJ zWckk0_19&Deon~$B@5&doajpchM3Sn6fuzsOrj!_sl+l=W?7bFc{an88#2wXSyo`h zKx8F0cSE9CHcxYGf#z9(&ag$Quw!(VEzv@N*z(5$ErMPFU1G=S99yOHz{|iF*a^DG z9;3&6^zzb2%k1%60$pKG(BteRUG?V<5j*9JfT#ToJ5xr7=w^nN{W9=u%E5lNjM%wD z`KI&?qGcvHsPbeCbD&my7cfQw02~xs09?kb-3|V}{o8lOo~2gA;Qmn}zo@}eZ>>D| z_Rn9{;Mup=9= zdtdyh1{V%@KK%5vAJpL03(EJO3?4w{;0^h!ck2iD)!>_3@Sq>Q5_Q|14wr(#2zp6o50lif2r$V#y%dueE$ z7p~w|W78uoS9h;YvIp%R+pERvNvv4ia{##nc6m265r|7;q#{D>IOL4o`r2}fW^_aNn@w^pJkze zUF;CovrW?lH+MTNcg3_{AhyFxx`DR{{B^Obn=L+<^2<%#@+{ljd}NrmXq%Sv$Y9}y zr%eq?8e$OK;xp;paT{DQ%m!(CEo=}zi#3fvSJ*Xeo@fwG?C+Ps*) z9#nmvXfDtBz1Q}`eh-%655r}6GhRwP9K1`shHlfvl;%YbPkWe5WPgh{WbvuhYXu)Q0lFV-YwoPl}a@vz#x z!5`oXED;1w5#q{)3zrB`!i7te7D5P4b428XKuUS6D0ItT*Y~-~)m7zDrJ@pC_g`7L zJS=qvt8*rn4rs?`2h6$Qn?AEGZBM9)@7#37qGfx!fsT%EQ->O; zxY{0T?{}UnOKs{=mwCQpSsuE1duh7smh&caTv62xy36pbM?Kv##X`!jb#&Xe9c$;A zFu$T>+3qvJrfpxF3u+o-FlvfoYP()rsD{;M9p9t|6D6u?3~xm}%MtlDJJ2;OwPHI= z(_KvKyPhK|Y43h<&^8juHUhC{c8?; zOQ@-qq`gO?CWg)7pN+&{l kOnj0Iu0S$MM#3$ZrA2ver(7!FMy?>@Sx!(|m(EL10ZbSnCjbBd literal 0 HcmV?d00001 diff --git a/src/__pycache__/config1.cpython-310.pyc b/src/__pycache__/config1.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5aef073479b2cdcaef6e87037b63dd3ce78c3891 GIT binary patch literal 1018 zcmYjP&5zqe6d&99S|{1fX8W-z&=2*rhisbVz#b^+tTWv;#IdoxTXim0+BbEB@c-tkhLArJ@T}wzT*DcCg$f8L1HuWYTmg-%kl`9+c?NQjhXSm8sPQc5P=r#bLK#*O z=U|QJp~4GLckwOiK2Zr-C}=GlR8sTy+u^?t|N7Co<+MU%P=0G|X)+Vvn+T~6rm`>`55*{+ z4Q0`q4dT8Ri%G{_oJY^aWmMq@?^(|{@Mz!o*aJk+2_Bs!Z)w#KYcp+84nHL&V2oD^Z18W z`27R+#ozxuYK1$;^-CB2dDN0c5Ti(pMBLnIN-dns=J^+Q>hW|Y=9S(|>|WX3txtN* zdeol_S-L^H?Y)3?ebc`=&mH$haI3M{!3ySTeNQU&W%<*5LTKAfwslUb<46{}hgM*8 zsOK?H>U-2T4g$~QOs*f%PQZ?sdo$<;%(0CFsVBZm(~}k3@l6XI-N2zPwUF_Q1J*w5 zJZ09~)TbWv1J|~Fbn_3=bT@4GHRgJ9)wJk7!(E^HrrnimDZbt@oxpMJy(h%7MAvq_ zCxk=Wfw3g?G{j=GD_2t6^V?Fl>^AEJU1~8|q=vz;D(c&=%(vN*Y2a1Mj>`=pkD^n?sw8XnMPGdpx?+51ZSQd$REIa1677cqRG2QSxvF flF>2>4z;9I)TNzbrGNvmmP>ZEQlgbj<)ZRGdwd@p literal 0 HcmV?d00001 diff --git a/src/__pycache__/config2.cpython-310.pyc b/src/__pycache__/config2.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f19e7392e2f7f152dce73104eea24429c5bb20c GIT binary patch literal 1019 zcmYjP&5zqe6d%X=S|{1feze^b=m$ORAx)DW*aIbvfG8I(h!H{vPCgS0TrkVdVpr=RkuJl!FXZU=?{D z)_4J`ya?-j1&UmQ4PHWC4hU?1tndoXTR5-6DZU1$c@@qC3SWn9z5zA9Daie;k50ka zM+!d;&+#+xJl_^;Cj?#)8N_oU2j^?#ggnggny4YqryTVQH3An;vJcgl2(N+SlARZ0 z+ym*w-yjZ1hLBi6FSZe+>h5=fe;)twgL&I-2dJR^+TKxRHhM4>GBcdX;%G7w<7hsT zC38NE25uy#T_-+=k?|#j;QjX!`xdii$+1aoG#H97nv6v#b3uPJ>MvHHAN4~Kg^jqF zAvz}*ow-)*1{upjI;#QKCsqaapzU+TiNCfqAlkJ?9nMo*1y+hO2yVP}= zE44l9=?A`Ra3)%(>DKEqXydWO}LYbn3cHEiE@ti7kgvPH+T-KT<0 zJHEaYv^2$Jv?o_m-}O3DGp!Em`aNngS)#hmuq*0Wjx2Q8k)h*OE4IUQ!^N_`>p8NL zo*q_xmFb==i1C|)*<_4IFQQp;p>j2iaOn~AJBA}SQf`?0e%IRfZ#e9Asij&{_A!}V z!L%j(eW`H|pIIZEHs~Q+UYkvujc|6Sac45VI|y2rrw?TD<V{(Mx$O zpjFz4gFd^RMljgLsb_zMX+zutg=rq4nx|9Z8O$6OdW7n%*weq%Kr^WMq~ck$K#NZ_ z&!!f&p?0W4U8r4JqGhN{Uuvf2mEjl_b-5EJ2if9nCUJv;$$ZD-c?mG7+1FMhe;@X zpF3dQ(3L4z)XN&rh;n?t8wEo6{xj{{t1E*vW-DT}(z?HXGJfaWlQqxQ?h-IQ`{5sLD63G!KS4-sNKW)j8WKD`(T2rS{gjA5 zOH0}m{Eq%UHjV&wL>DE6PFez4sPm|~XM3>cr1Y7m%^*h`5#~0nTbU%pzmVnp#nMa#VRp@iZ z5(tL*5McRCSA`7fst`!Y#n^1hfR8^MNI4QWS5^iGd&|Kd!|*i4FPp(=IZ3%3us{HE znn4_l(b*)U(K(zI<4LHj=!_D)$zAmox7^$`)8f)*54+s9QLS7s$(I+(h*+X5mY+ctIg8WBtYPvp z8rt|zJc%-38vYja@wpeGh9>0^XQO~KAKiT!dc-9VOZtNDk{Vess^kjj`tvK#s|E9$ z@h{Ft^6W&fp&1D^L-RjC0c;Q`x-^F7DQX4Kil_}O&}=9UCC7mG6Bp2^os^)b45f0a z_Y0>4kX@B?!`jI_^eq71FHrr|n2;m=5bgmWb@3^XtbAjl1A+@r&9BTuL%u05P7GQ^ z9?I{Dyfo2)jU1TcGR(0AxGn%Ql#n*9Q9u!d5Op4e$@s#94%VMLb)KdGm5|@8f4kt+ zC-tlKv{x5FJc^irKJq?bG}>c)0nW*hemV_PSz@r)>p>9RQJDA;x|AQNQnDBO`zikm z<05CCw|Ei$psdw29;JeL)g8DVX}kl#lVO_hw_(()Zfv&htOK4pt^9(-(v7`ivC+)CAq+B^| zcou>PSXR0DoSW;dwsLZPx3k7AJn0n_cnSDVQPffV41_Y#Vfon&hZsdC0zg0 zt(`xv@9gI1&r$2yvgc=RSJspRlo5;mtH`ZoHW_Y_G8lgkW)--I37m`QEs`oJez#;@ zA`3*U-7%~d*|c$)oEYDG9Ea?@?%f{of(!hoMzk%ED7A)2gU`Q0y__Zg`uwm z7%Nlq0;f9Qv;sIaWHrO7ImPLmtN~8p)uh%Gr}KbQ8)nFn?i`!==(m;eIEcpc5B?NH zKY}H{2D{?dQG9@628ag#5PN=w0-w5Piy7efud(AdC~lxYnDO7DxQXJw#+UyNP5wi8 z`A0aAJ*d;L79p&#W&V2{_!z}2R8)o0nQ)?sKuAHrFp$re%$I@8!ub98-Sflvid!hwK&Z+z|LU?Rf)wo~W*{@yIKE*VQzeACsDiNJJePFawCC-` zS}hxEEO-t)<8hWW4kk&%4v4-^oWR)c^nh literal 0 HcmV?d00001 diff --git a/src/__pycache__/metric.cpython-310.pyc b/src/__pycache__/metric.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f5f2d20ca4be002e082a46da617b5eb7fe0ccc7 GIT binary patch literal 2152 zcmZuy&2Jk;6rYdX_1bY9r!h%MOJ(%}7Bo(TL?cvCBcMn~wJIt&SVF7S&N#NSYr8XR z)I^&LiPTg72j`f70mPmE05KdmaLSz%C*GU&S3*XbH#2YM&ByQk-kag-YKcI3@bh}N z3BA8@uv{D%JcX+FK?ovfOcL6r6#Fb@ZT2-0TsY@MIFg?6Hixk*JQ#a+> zO&ZjA&tCPe_}SjeXsG1XZ(tuW+-h2|??UBJ_4goBaz-Zff>4stj07wreJ*I~Ox%oK*wfx} zm_w~|tJb}#6$EbKwG2x~hU;;1$xK1WPB@NJQxQF#21<%?B!kXt!#X3VgNA2ZJswGA z{2=HJdT9`tmBBa(qBzuAYEuk_2y_~z(zxkRMP1{bNHx?AW*jZ!j;g>@E~zO7xk(UQ zl7AmIyTe2_^{9F9-Bbx9PBl96gEYR^K>d{TUNw?|AojHa( zvl~T-*{l?xgLYp))#o5m(x({}fY@7h%2SKu8U2#{@bRgWvCKJQr*6h=>j9ch=D6ft zlDV1pluX$cjze#v6|W_-hUN8n01d749>iZu9&60eAj6sV*SSmqvK^S(%a40{ks#1w93V z_7NhibPEW(MedPPgnFiBb1fGPVCOYbBiPRMPRb_${sje+^48%mzyAKmU)i6ZU14A} z+#HuVBsqRgBEtd9S#-D@0UhDhQBU`V1LHw2jALN&-c1Aw(J&c}Q~40Kw)}D!vgQ7;?lz2#=LCOKY2nHz!_MWC3Cfu9aS#p6akcP3sU2_^^ zKpH??fj?4kRvBk7x)m~T8VIQz=%Ko#)|JX)GbgNFya#JFhDC|mG_bLF&Fy&rpM-9k z)AV{C$ao)U*k?yfuYUu7!x{aFLKcAWgkKQI3}B48;4xt&$VYC*CLZPk(75)wPD^dU z5$Z08lie2(j=d-a?&*3s5cND7bv+sDwB8MWl=ZYL>lz4D*WGX=A*?a{)HVpnvZ%@t zYoZoE7~?{!mGP9}>OSh<1JPc`;D)mn@vp4W^+>lg`~=opj#pTXmwAP6T8_`Cuyad< zqwkPu7P=aAFplvnf|g->4?hyxYH)k1aXaxaOzn*o`e}*fmf#o&&!B1y<(f_5^W zrariCw}_5MFtLlqd32Pi?^de{wGG#l?U$2(8d~A@Iiz@dyJqPsb3PgWNglhO<3sJf LW#ZE+uYLF*o{hu) literal 0 HcmV?d00001 diff --git a/src/__pycache__/network.cpython-310.pyc b/src/__pycache__/network.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f205a10b059a1c9bbfe68d33ff5c489b84d1b4e5 GIT binary patch literal 7731 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 P@qa{z29)x&)!}~tp{S_H literal 0 HcmV?d00001 diff --git a/src/config.py b/src/config.py index 6355fcc..1f55d32 100644 --- a/src/config.py +++ b/src/config.py @@ -2,11 +2,12 @@ # Training Hyperparameters NUM_CLASSES = 200 -BATCH_SIZE = 512 +BATCH_SIZE = 256 VAL_EVERY_N_EPOCH = 1 -NUM_EPOCHS = 40 -OPTIMIZER_PARAMS = {'type': 'SGD', 'lr': 0.005, 'momentum': 0.9} +NUM_EPOCHS = 80 +# OPTIMIZER_PARAMS = {'type': 'SGD', 'lr': 0.001, 'momentum': 0.5} +OPTIMIZER_PARAMS = {'type': 'Adam', 'lr': 0.001, 'betas': (0.9, 0.999), 'eps': 1e-8} SCHEDULER_PARAMS = {'type': 'MultiStepLR', 'milestones': [30, 35], 'gamma': 0.2} # Dataaset @@ -14,7 +15,7 @@ NUM_WORKERS = 8 # Augmentation -IMAGE_ROTATION = 20 +IMAGE_ROTATION = 30 IMAGE_FLIP_PROB = 0.5 IMAGE_NUM_CROPS = 64 IMAGE_PAD_CROPS = 4 @@ -22,15 +23,15 @@ IMAGE_STD = [0.2302, 0.2265, 0.2262] # Network -MODEL_NAME = 'resnet18' +MODEL_NAME = 'MyNetworksmall' # Compute related ACCELERATOR = 'gpu' -DEVICES = [0] +DEVICES = [0,1,2] PRECISION_STR = '32-true' # Logging -WANDB_PROJECT = 'aue8088-pa1' +WANDB_PROJECT = 'aue8088-pa1-mynetwork1' WANDB_ENTITY = os.environ.get('WANDB_ENTITY') WANDB_SAVE_DIR = 'wandb/' WANDB_IMG_LOG_FREQ = 50 diff --git a/src/metric.py b/src/metric.py index 42c2bcb..f4f629e 100644 --- a/src/metric.py +++ b/src/metric.py @@ -3,7 +3,47 @@ # [TODO] Implement this! class MyF1Score(Metric): - pass + def __init__(self, num_classes=200): + super().__init__() + self.num_classes = num_classes + + # 클래스별 카운터 초기화 + self.add_state("tp", default=torch.zeros(num_classes), dist_reduce_fx="sum") + self.add_state("fp", default=torch.zeros(num_classes), dist_reduce_fx="sum") + self.add_state("fn", default=torch.zeros(num_classes), dist_reduce_fx="sum") + + def update(self, preds, target): + # 예측값에서 최대 점수 클래스 선택 (벡터화된 연산) + pred_classes = torch.argmax(preds, dim=1) + + # 각 클래스별로 TP, FP, FN 계산 (벡터화) + for c in range(self.num_classes): + # 마스크 생성 + target_mask = (target == c) + pred_mask = (pred_classes == c) + + # True Positives + self.tp[c] += (target_mask & pred_mask).sum() + + # False Positives + self.fp[c] += (~target_mask & pred_mask).sum() + + # False Negatives + self.fn[c] += (target_mask & ~pred_mask).sum() + + def compute(self): + # 0으로 나누기 방지를 위한 작은 값 + eps = 1e-10 + + # 클래스별 정밀도, 재현율 계산 + precision = self.tp / (self.tp + self.fp + eps) + recall = self.tp / (self.tp + self.fn + eps) + + # F1 점수 계산 + f1 = 2 * (precision * recall) / (precision + recall + eps) + + # 클래스별 점수 평균 + return torch.mean(f1) class MyAccuracy(Metric): def __init__(self): @@ -13,13 +53,13 @@ def __init__(self): def update(self, preds, target): # [TODO] The preds (B x C tensor), so take argmax to get index with highest confidence - + predicted_classes = torch.argmax(preds, dim=1) # [TODO] check if preds and target have equal shape - + assert predicted_classes.shape == target.shape, "Predictions and targets must have the same shape" # [TODO] Cound the number of correct prediction - + correct = (predicted_classes == target).sum() # Accumulate to self.correct self.correct += correct @@ -29,3 +69,4 @@ def update(self, preds, target): def compute(self): return self.correct.float() / self.total.float() + diff --git a/src/network.py b/src/network.py index cfe28a5..ee25dda 100644 --- a/src/network.py +++ b/src/network.py @@ -12,21 +12,211 @@ import torch # Custom packages -from src.metric import MyAccuracy +from src.metric import MyAccuracy, MyF1Score import src.config as cfg from src.util import show_setting # [TODO: Optional] Rewrite this class if you want -class MyNetwork(AlexNet): - def __init__(self): +class MyNetwork(nn.Module): + def __init__(self, num_classes=200, dropout=0.5): super().__init__() + + self.features = nn.Sequential( + nn.Conv2d(3, 64, kernel_size=5, stride=1, padding=2), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(64, 192, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(192), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(192, 384, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(384), + nn.ReLU(inplace=True), + + nn.Conv2d(384, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + + nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + ) + + self.avgpool = nn.AdaptiveAvgPool2d((6, 6)) + + self.classifier = nn.Sequential( + nn.Dropout(p=dropout), + nn.Linear(256 * 6 * 6, 1024), + nn.BatchNorm1d(1024), + nn.ReLU(inplace=True), + nn.Dropout(p=dropout), + nn.Linear(1024, 1024), + nn.BatchNorm1d(1024), + nn.ReLU(inplace=True), + nn.Linear(1024, num_classes), + ) - # [TODO] Modify feature extractor part in AlexNet + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.features(x) + x = self.avgpool(x) + x = torch.flatten(x, 1) + x = self.classifier(x) + return x +class MyNetworkSmall(nn.Module): + def __init__(self, num_classes=200, dropout=0.5): + super().__init__() + + self.features = nn.Sequential( + nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(32), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + ) + + self.avgpool = nn.AdaptiveAvgPool2d((4, 4)) + + self.classifier = nn.Sequential( + nn.Dropout(p=dropout), + nn.Linear(128 * 4 * 4, 512), + nn.BatchNorm1d(512), + nn.ReLU(inplace=True), + nn.Linear(512, num_classes), + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.features(x) + x = self.avgpool(x) + x = torch.flatten(x, 1) + x = self.classifier(x) + return x + + +#test +class MyNetworkWide(nn.Module): + def __init__(self, num_classes=200, dropout=0.5): + super().__init__() + + self.features = nn.Sequential( + nn.Conv2d(3, 128, kernel_size=5, stride=1, padding=2), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + + nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + + nn.Conv2d(512, 384, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(384), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + ) + + self.avgpool = nn.AdaptiveAvgPool2d((6, 6)) + + self.classifier = nn.Sequential( + nn.Dropout(p=dropout), + nn.Linear(384 * 6 * 6, 2048), + nn.BatchNorm1d(2048), + nn.ReLU(inplace=True), + nn.Dropout(p=dropout), + nn.Linear(2048, 2048), + nn.BatchNorm1d(2048), + nn.ReLU(inplace=True), + nn.Linear(2048, num_classes), + ) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.features(x) + x = self.avgpool(x) + x = torch.flatten(x, 1) + x = self.classifier(x) + return x + +class MyNetworkDeep(nn.Module): + def __init__(self, num_classes=200, dropout=0.5): + super().__init__() + + self.features = nn.Sequential( + nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.Conv2d(64, 64, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(64), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + + nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1), + nn.BatchNorm2d(512), + nn.ReLU(inplace=True), + nn.MaxPool2d(kernel_size=2, stride=2), + ) + + self.avgpool = nn.AdaptiveAvgPool2d((4, 4)) + + self.classifier = nn.Sequential( + nn.Dropout(p=dropout), + nn.Linear(512 * 4 * 4, 1024), + nn.BatchNorm1d(1024), + nn.ReLU(inplace=True), + nn.Dropout(p=dropout), + nn.Linear(1024, 1024), + nn.BatchNorm1d(1024), + nn.ReLU(inplace=True), + nn.Linear(1024, num_classes), + ) def forward(self, x: torch.Tensor) -> torch.Tensor: - # [TODO: Optional] Modify this as well if you want x = self.features(x) x = self.avgpool(x) x = torch.flatten(x, 1) @@ -45,7 +235,13 @@ def __init__(self, # Network if model_name == 'MyNetwork': - self.model = MyNetwork() + self.model = MyNetwork(num_classes=num_classes) + elif model_name == 'MyNetworkSmall': + self.model = MyNetworkSmall(num_classes=num_classes) + elif model_name == 'MyNetworkWide': + self.model = MyNetworkWide(num_classes=num_classes) + elif model_name == 'MyNetworkDeep': + self.model = MyNetworkDeep(num_classes=num_classes) else: models_list = models.list_models() assert model_name in models_list, f'Unknown model name: {model_name}. Choose one from {", ".join(models_list)}' @@ -56,6 +252,7 @@ def __init__(self, # Metric self.accuracy = MyAccuracy() + self.f1_score = MyF1Score(num_classes=num_classes) # Hyperparameters self.save_hyperparameters() @@ -79,15 +276,27 @@ def forward(self, x): def training_step(self, batch, batch_idx): loss, scores, y = self._common_step(batch) accuracy = self.accuracy(scores, y) - self.log_dict({'loss/train': loss, 'accuracy/train': accuracy}, - on_step=False, on_epoch=True, prog_bar=True, logger=True) + f1 = self.f1_score(scores, y) + + self.log_dict({ + 'loss/train': loss, + 'accuracy/train': accuracy, + 'f1_score/train': f1 + }, on_step=False, on_epoch=True, prog_bar=True, logger=True) + return loss def validation_step(self, batch, batch_idx): loss, scores, y = self._common_step(batch) accuracy = self.accuracy(scores, y) - self.log_dict({'loss/val': loss, 'accuracy/val': accuracy}, - on_step=False, on_epoch=True, prog_bar=True, logger=True) + f1 = self.f1_score(scores, y) + + self.log_dict({ + 'loss/val': loss, + 'accuracy/val': accuracy, + 'f1_score/val': f1 + }, on_step=False, on_epoch=True, prog_bar=True, logger=True) + self._wandb_log_image(batch, batch_idx, scores, frequency = cfg.WANDB_IMG_LOG_FREQ) def _common_step(self, batch): @@ -109,3 +318,4 @@ def _wandb_log_image(self, batch, batch_idx, preds, frequency = 100): key=f'pred/val/batch{batch_idx:5d}_sample_0', images=[x[0].to('cpu')], caption=[f'GT: {y[0].item()}, Pred: {preds[0].item()}']) + From 542d43e5ede7c879635dd160d4080b92e63efbd7 Mon Sep 17 00:00:00 2001 From: HGKim-andb <60685870+HGKim-andb@users.noreply.github.com> Date: Fri, 2 May 2025 22:13:00 +0900 Subject: [PATCH 2/2] Update metric.py --- src/metric.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/metric.py b/src/metric.py index f4f629e..50b4680 100644 --- a/src/metric.py +++ b/src/metric.py @@ -7,42 +7,31 @@ def __init__(self, num_classes=200): super().__init__() self.num_classes = num_classes - # 클래스별 카운터 초기화 self.add_state("tp", default=torch.zeros(num_classes), dist_reduce_fx="sum") self.add_state("fp", default=torch.zeros(num_classes), dist_reduce_fx="sum") self.add_state("fn", default=torch.zeros(num_classes), dist_reduce_fx="sum") def update(self, preds, target): - # 예측값에서 최대 점수 클래스 선택 (벡터화된 연산) pred_classes = torch.argmax(preds, dim=1) - # 각 클래스별로 TP, FP, FN 계산 (벡터화) for c in range(self.num_classes): - # 마스크 생성 target_mask = (target == c) pred_mask = (pred_classes == c) - # True Positives self.tp[c] += (target_mask & pred_mask).sum() - # False Positives self.fp[c] += (~target_mask & pred_mask).sum() - # False Negatives self.fn[c] += (target_mask & ~pred_mask).sum() def compute(self): - # 0으로 나누기 방지를 위한 작은 값 eps = 1e-10 - # 클래스별 정밀도, 재현율 계산 precision = self.tp / (self.tp + self.fp + eps) recall = self.tp / (self.tp + self.fn + eps) - # F1 점수 계산 f1 = 2 * (precision * recall) / (precision + recall + eps) - # 클래스별 점수 평균 return torch.mean(f1) class MyAccuracy(Metric): @@ -56,7 +45,7 @@ def update(self, preds, target): predicted_classes = torch.argmax(preds, dim=1) # [TODO] check if preds and target have equal shape - assert predicted_classes.shape == target.shape, "Predictions and targets must have the same shape" + assert predicted_classes.shape == target.shape # [TODO] Cound the number of correct prediction correct = (predicted_classes == target).sum()